Detecting if a plugin has been applied - javascript

I have an app that loads conversations. Each time a conversation is loaded I need to destroy and re init the file uploader.
Per: https://github.com/blueimp/jQuery-File-Upload/wiki/API
I'm trying:
// First destroy existing instance
$('.upload').fileUpload('destroy');
// Init
$('.upload').fileUploadUI({
........
Problem is on first run I get an error: "Uncaught No FileUpload with namespace "file_upload" assigned to this element"
Any ideas on how I can somehow detect if the plugin has been applied and only then destroy? Thansk

You should be able to detect if the plugin has been applied to an element using the "namespace" (as the plugin refers to it), which is the .data() key the plugin uses.
With the current defaultNamespace being 'file_upload', try:
var upload = $('.upload');
if (upload.data('file_upload'))
upload.fileUpload('destroy');
Instead of just:
$('.upload').fileUpload('destroy');
This will mirror the plugin's own test, which you can see around line 920 of the current source.

Related

How to load new editorConfig for inline editor at run-time? [duplicate]

This question already has an answer here:
How to use CKEDITOR.replace after CKEDITOR.inline
(1 answer)
Closed 5 years ago.
I have run the Toolbar Configurator to remove some unwanted items from the toolbar. I can get the toolbar config, which consists of some javascript code which starts like this:
CKEDITOR.editorConfig = function( config ) {
config.toolbarGroups = [
However, it is unclear to me how to use this when instantiating a specific editor instead of using it globally. I have tried pasting this in my code before I instantiate the editor in question, but it shows the full toolbar with the unwanted items. I am also making some other CKEDITOR.config and CKEDITOR.on assignments at this time which do work.
I also tried modifying the configuration code within the function by changing the config to editor.config (where editor comes from the "editor" field of the event passed to the callback) and initializing it in the callback of CKEDITOR.on("instanceReady") but that also did not work.
Then I saw this question and tried using the replace function like so:
CKEDITOR.on("instanceReady", function(evt) {
...
CKEDITOR.replace(evt.editor.name, {
toolbarGroups: [
...
],
removeButtons: "..."
})
...
This also doesn't work!
Then I tried pasting the raw config from the configurator into a new file "config2.js" in my ckeditor directory on the server as this page suggests should work, and changing the replace call to:
CKEDITOR.replace(evt.editor.name, {
customConfig: "config2.js"
})
This doesn't work, even if I replace the string with "../ckeditor/config2.js". Looking at the network requests I see it doesn't even try requesting "config2.js" from anywhere.
If it makes any difference, I am starting the editor using CKEDITOR.inline(div) so as far as I know I have to perform the configuration in an event callback.
I also tried calling the replace function from the "instanceCreated" callback - this resulted in an infinite loop / max recursion exceeded error. I also tried it in the "instanceLoaded" event, also without effect.
Update:
I just noticed in the console that when it tries to call replace it throws this error:
Uncaught The editor instance "note1681" is already attached to the provided element.
So it seems I am doing something incorrectly with replace.
I believe it's impossible to hide buttons(change toolbar) after you initialized instance. However, you can recreate you ckeditor with new toolbar.
First, you need to destroy current instance, before creating new one.
CKEDITOR.instances.note1681.destroy();
CKEDITOR.replace('note1681');
For fast switching toolbar, i recommend use custom variable in configuration file.
Add in ckeditor/config.js your toolbar version
editor.my_toolbar = [['Sourcedialog','Cut','Copy']];
Init ckeditor with it
CKEDITOR.replace( 'note1681', { toolbar: my_toolbar })

Angular2 with Typescript, how to use Plupload CDN script file in lazy-loaded module?

I would like to use Plupload in an Angular2 component and access the Plupload JavaScript file from a CDN. I want it specific to a component so that it is not downloaded if it is not required - I want it to be in a lazy loaded module. How can I do this?
Now fully answered on this page!
The result of this quest, which included offering and awarding bounties to two people who worked hard with me on it, is as follows:
Example of using Plupload with Angular 2 and TypeScript
How to Lazy load a script from a CDN in Angular 2
Example of how to use Plupload in a lazy loaded module
How to use a lazy loaded script in Angular 2
(See edit history for the ugly details that used to make up this question.)
Here's the overview of what you need to do to create a lazy-loaded Plupload feature while loading Plupload from a CDN:
When the feature is needed (e.g. user clicks a button or visits a page), dynamically add a <script> tag to the page to load the Plupload library from a CDN.
Wait until the library is loaded to proceed (or you could get a "plupload is undefined" error).
Display the UI to interact with Plupload in one of your Angular templates. In its simplest form, this UI consists of two buttons: "Select files" and "Upload files".
Initialize Plupload and wire it up to the UI.
Complete, working code: https://plnkr.co/edit/4t39Rod4YNAOrHmZdxqc?p=preview
Please take note of the following points in my implementation:
Regarding #2. A better way to check whether Plupload has finished loading would be to poll the global namespace for the existence of the plupload variable. As long as window.plupload does not exist, it means the library hasn't been loaded yet and that we should NOT proceed. For simplicity my code just waits for one second and proceeds.
Number 4 can prove a bit tricky. Plupload makes a heavy use of direct DOM access to wire its API to the HTML (e.g. document.getElementById('filelist')). This is something Angular discourages and that you should try avoiding whenever possible. More specifically direct DOM access is used in the following places:
To tell Plupload which DOM element should trigger the "Select files" dialog (what they call the browse_button config option). For this I could not avoid the direct DOM reference and I used the #ViewChild decorator to get a hold of the "Select Files" button.
To display selected files in the template. For this I converted the Plupload syntax into the regular Angular syntax. I push selected files to a class property called fileList which I display in the template using a standard *ngFor.
The "Upload Files" button triggers some code that does the actual uploading and refreshes the UI to show upload progress. Once more, I converted this to regular Angular syntax using event binding and data binding.
Let me know if you have any questions.
In this approach no need for any extra loader modules.
See example (check console for Woohoo): http://plnkr.co/edit/gfUs4Uhe8kMGzPxwpBay?p=preview
updated plunker: https://plnkr.co/edit/leG062tg7uX8sLrA0i2i?p=preview
You can lazyload some js by adding the script url to you document:
Create a my-lazy-load.function.ts:
export function lazyload(url) {
// based on https://friendlybit.com/js/lazy-loading-asyncronous-javascript/
let scripts = document.getElementsByTagName('script');
for (let i = scripts.length; i--;) {
if (scripts[i].src.match(url)) return true;
}
let s = document.createElement('script');
s.type = 'text/javascript';
s.async = true;
s.src = url;
let x = document.getElementsByTagName('script')[0];
x.parentNode.insertBefore(s, x);
return true;
}
In your component that you want to add plupload:
import {lazyload} from "./my-lazy-load.function.ts";
export class MyComponent implements OnInit {
pluploadInterval:number = null;
hasPlupload: boolean = false;
ngOnInit() {
lazyload("https://cdnjs.cloudflare.com/ajax/libs/plupload/2.3.1/plupload.full.min.js");
this.pluploadInterval = window.setInterval(()=>{
if(window.plupload) { // you can check existence of plupload object any way you want
// Woohoo, I am ready to be used
this.hasPlupload = true; // everything is run outside ngZone, wrap it if angular2 is not reacting to changes, or change window.setInterval to setInterval
window.clearInterval(this.pluploadInterval); // don't forget to clean interval
}
}, 100); // timeinterval can vary
....
The browser will load this automatically.
Notice if(plupload) it assumes that there is global object plupload that the script adds (I do not know if it truely added, check your working example in pure javascript). As it is jquery extension you can check it's prototype like this: jQuery test for whether an object has a method?
OLD HISTORICAL:
#Reid here is plunker: https://plnkr.co/edit/zDWWQbTQUSHBqCsrUMUi?p=preview the plupload is actually loaded, but added to require with define("plupload", ['./moxie'], extract); I am not sure at the moment how to extract from there and which package require is belong to... the code for finding correct module loader belongs to plupload itself, here it is (from plupload.dev.js):
if (typeof define === "function" && define.amd) {
define("plupload", ['./moxie'], extract);
} else if (typeof module === "object" && module.exports) {
module.exports = extract(require('./moxie'));
} else {
global.plupload = extract(global.moxie);
}
I think that your best bet is to use the Require.js Library so that you can dynamically load your scripts from within your components.
The small trade off is that you will have to add this 18KB library to your index.html page (CDN), however this could save you huge amounts of loading if your 3rd party libraries are massive.
I have no experience with using plupload, so instead I put together the following plunkr which uses an external animation library, drawn from a CDN. The plunkr animates a number from 0 - 100.
https://plnkr.co/edit/fJCtezsERYHOYplLh7Jo?p=preview
index.html
<script src="https://cdnjs.cloudflare.com/ajax/libs/require.js/2.3.3/require.min.js"></script>
component.ts
ngOnInit(){
// Dynamically loads the framework from the CDN.
require(["https://cdnjs.cloudflare.com/ajax/libs/gsap/1.19.1/TweenLite.min.js"],
// This function is then called ONCE LOAD IS COMPLETE
function (common) {
// Do greensock things
var demo = {score:0},
scoreDisplay = document.getElementById("scoreDisplay");
//create a tween that changes the value of the score property of the demo object from 0 to 100 over the course of 20 seconds.
var tween = TweenLite.to(demo, 20, {score:100, onUpdate:showScore})
//each time the tween updates this function will be called.
function showScore() {
scoreDisplay.innerHTML = demo.score.toFixed(2);
}
});
}
What I like about this approach, is that in the onLoad callback from require, the syntax is unchanged from a normal implementation of the library, so you can just copy paste your currently working code into the callback.

how to obtain a reference to the lite plugin object for ckeditor

Beginning web developer here, bear with me, I realize this question is simplistic.
I am trying to use the LITE plugin for ckeditor. In the documentation (http://www.loopindex.com/lite/docs/) they say that in order to get a reference to the lite plugin object I need to
"To interact with the lite plugin, you need to obtain a reference to the actual plugin object which is unique for each instance of CKEditor. The safest way to do this is by listening to the event LITE.Events.INIT fired by the editor instance. The data member of the event will contain a property called lite which references the lite plugin instance, initialized and ready for action."
How do I do this?
Is it something like:
LITE.Events.INIT(data) {
//desired functionality here
}
or is it:
LITE.Events.INIT.addEventListener (function (data) {//desired functionality here})
Thanks in advance.
Hard to say without having access to the plugin, but according to the documentation this should work:
editor.on( LITE.Events.INIT, function( evt ) {
// The instance should be somewhere in:
evt.data;
} );
Note that LITE.Events.INIT is a constant which keeps the name of Lite's event name. It's not a name of the event.

Firebreath Object in AngularJS

I have tried to include a FireBreath plugin object in an AngularJS view, however when I try to render the view I get this error:
TypeError: Cannot read property 'nodeName' of undefined
I am able to successfully include the object in the view with $compile like this:
$("body").append($compile('<object id="plugin" type="application/x-firebreathplugin" width="0" height="0></object>')($scope));
However, after including the object like this I cannot get my plugin to fire an event in the JS.
Doing something like this:
plugin = document.getElementById('plugin');
console.log(plugin);
Returns
TypeError
In the Chrome console. But I can still do:
plugin.callFunction();
And have a FireBreath method execute. The issue is when I try to get an event to fire in the JS. No matter what I try, I cannot get the event to fire. So this code will never execute:
var addEvent = function(obj, name, func) {
obj.addEventListener(name, func, false);
}
addEvent(document.getElementById('plugin'), 'firebreathEvent', function(data) {
console.log('data ' + data);
});
var plugin = document.getElementById('plugin');
plugin.functionThatTriggersFireBreathEvent();
Does anybody know if it has something to do with accessing the object after calling $compile? I noticed that in regular HTML (before using AngularJS) logging the plugin in the console returns this :
<JSAPI-Auto Javascript Object>
So I am thinking that whatever I am getting with document.getElementById after using $compile is not the same.
What would be easier is is if I could just include the <object> tag in the view.html file and have it display in <body class='ng-view'> but I get the top TypeError, so if anyone has any ideas for that, that would be preferred.
Any help is appreciated. Thanks.
If anyone is interested, because I could not get the event to fire, I followed along to this link:
http://colonelpanic.net/2010/12/firebreath-tips-asynchronous-javascript-calls/
(which I think is your blog #taxilian) to get the data back to the JS.
Plugin Code: Great example in the link.
JS Code:
//attach FireBreath Object to AngularJS View
$("body").append($compile('<object id="plugin" type="application/x-firebreathplugin" width="1" height="1"><param name="onload" value="pluginLoaded"/></object>')($scope));
var callback = function(data) {
//data is an object
console.log(data.resultFromFireBreath);
}
plugin = document.getElementById("plugin");
plugin.getData(callback);
This will have to work for now until someone can figure out how to attach an event to the plugin object after $compile.
I ran into the same problem and was able to make the problem go away by creating a read-only nodeName property in my plugin object. I asked about this in a firebreath forum post and taxilian suggested adding this to JSAPIAuto.cpp, which also worked, so I submitted a pull request with the change.
I once spent about 6 hours trying to make FireBreath plugins work with jquery; it was really educational, but ultimately I determined that it wasn't worth the work.
Long story short is that it's not worth it; particularly since even if you could make it work, it would break on IE9 where FireBreath doesn't support addEventListener (IE never gives it the even info, so it's a little hard to support) and you would need to use attachEvent anyway.

How can I use jQuery 1.5.2+ on a Firefox addon?

At first I made a function that received a parameter and returned jQuery such as:
function getjQuery(window)
{
/*jquery code*/(window);
return window.jQuery;
}
But then I got an email form the review and they told me I have to use jQuery file with the original file name and completely unmodified.
I started to search for an alternative and found this solution, but there is no way it work.
jQuery object is created, but I can't find any elements. $("#id").length is always 0. With the previous method it was always found.
My current code (which doesn't work)
AddonNameSpace.jQueryAux = jQuery;
AddonNameSpace.$ = function(selector,context) {
return // correct window
new AddonNameSpace.jQueryAux.fn.init(selector,context||contentWindow);
};
AddonNameSpace.$.fn =
AddonNameSpace.$.prototype = AddonNameSpace.jQueryAux.fn;
AddonNameSpace.jQuery = AddonNameSpace.$;
The jQuery file is loading on my browser.xul overlay:
<script type="text/javascript" src="chrome://addon/content/bin/jquery-1.5.2.min.js" />
Am I loading in the right place?
How can I use jQuery to modify the content on a page (HTML) with the original jQuery file, is it even possible?
You need pass the e.originalTarget.defaultView on the second parameter on jquery..
If you don't jquery will use window.document, which is the window.document from the xul.
Use
gBrowser.addEventListener("DOMContentLoaded", function (e) {
$("#id", e.originalTarget.defaultView).length
}, true);
instead of
$("#id").length;
And, for avoid conflicts with other extensions don't use script in the xul page, use MozIJSSubScriptLoader.
Components.classes["#mozilla.org/moz/jssubscript-loader;1"]
.getService(Components.interfaces.mozIJSSubScriptLoader)
.loadSubScript("chrome://youraddon/content/jquery-1.5.2.min.js");
If you use this method, you load jquery only when you need, avoiding memory leak.
The preferred way to load it is with mozIJSSubScriptLoader so you don't collide with other's extensions. I'm not sure why you're having problems, I can use jQuery in my addon like $("#id").hide() with no additional code (although from the sidebar, now browser.xul).
Either way, this blog post provides a pretty good guide and even has an example xpi to download.

Categories