With `arguments.callee deprecated I would like to find al alternative approach to extend a jQuery plugin I created to execute one of its built in methods from the outside.
My sample jQuery plugin:
(function($) {
$.myPlugin = function(options) {
// normal var and methods
// this is to execute a method from outside
arguments.callee.close = function() {
// to do when this is called
}
}
}(jQuery))
The plugin would be used for it’s normal use with this
$(selector).myPlugin();
And this is to trigger the “close” method inside the plugin
$(selector).myPlugin.close()
I found an answer to this and have this to share:
(function($) {
function myPlugin(options) {
// normal var and methods: do whatever I want...
myPlugin.close = myPlugin.close.bind(this);
}
myPlugin.close = function() {
// do this thing
}
$.fn.myPlugin = myPlugin;
}(jQuery));
This allows me to call the close method with this:
$(selector).myPlugin.close();
Related
Here is a fictional version of my jQuery plugin, but the structure is exactly the same:
(function ($)
{
var initialized = false;
var element;
var counter = 0;
$.fn.myPlugin= function(action)
{
if (action === "increase")
{
increase(arguments[1]);
}
else if (!initialized)
{
settings = $.extend({
...
}, action);
initialized = true;
element = $(this);
return this;
}
else
{
console.error("Unknown function call.");
return;
}
};
var increase = function(amount)
{
counter += amount;
element.text(counter);
};
}(jQuery));
With this code I am able to initialize my plugin like this:
$("#element").myPlugin(options);
And I can call the method increase like this:
$("#element").myPlugin("increase", 5);
However, I am not able to initialize my plugin on multiple elements on one page, because of the variables initilized, element and counter.
How do I modify this code in such a way that I can use it multiple times on one page without changing the way you can initialize and call methods?
I do this exact same thing myself, and it's very simple once you know how.
Take this example of a simple plugin...
$.fn.myPlugin = function() {
// plugin global vars go here
// do plugin stuff here
}
To modify it to work on multiple instances, you just have to parse this when you call it...
$.fn.myPlugin = function() {
$(this).each(function() {
// plugin global vars go here
// do plugin stuff here
});
}
That way it will work when you assign the plugin to either a single instance, or a collection of elements.
Then, to call methods on individual elements, you just need to specify the correct one...
$("#element1").doMethod(1, 2, 3);
$("#element2").doMethod(4, 5, 6);
how can I call a tinymce plugin function?
tinymce.activeEditor.plugins.customplugin.customfunction(customvar);
not working!
tinymce.activeEditor.plugins.customplugin.customfunction(customvar);
is the correct way to call such a function.
Be aware that tinymce.activeEditor needs to be set already in order to use it.
tinymce.activeEditor gets set when the user clicks into the editor for example.
Otherwise use
tinymce.get('your_editor_id_here').plugins.customplugin.customfunction(customvar);
There might be another reason for your function call not to work:
The function you want to call needs to be defined like the functions getInfo, _save and _nodeChange in the save plugin (see the developer build of tinymce to inspect this plugin in the plugins directory).
The save plugin shortened here:
(function() {
tinymce.create('tinymce.plugins.Save', {
init : function(ed, url) {
...
},
getInfo : function() {
...
},
// Private methods
_nodeChange : function(ed, cm, n) {
...
},
// Private methods
...
_save : function() {
}
});
// Register plugin
tinymce.PluginManager.add('save', tinymce.plugins.Save);
})();
You may call the getInfo function of this plugin using the following javascript call:
tinymce.get('your_editor_id_here').plugins.save.getInfo();
Put the function you want to expose to the outside world in self.
tinymce.PluginManager.add('myplugin', function(editor) {
var self = this;
var self.myFunction = myFunction(); // Put function into self!
function myFunction() {
console.log('Hello world!');
}
}
Then:
tinymce.get('your_editor_id_here').plugins.myplugin.myFunction();
It has been suggested to me the following structure is preferred/standard to expose public properties from a jQuery plugin.
(function($) {
$.myPlugin = {
data: {}
};
$.fn.myPlugin = function() {
return this;
};
})(jQuery);
The above example exposes 'data' through the syntax $.myPlugin.data.
If the plugin is attached to multiple HTML elements on a page, then I think $.myPlugin.data becomes invalid as it is the equivalent of a static variable.
What is another way to write the plugin so .data is related to the instance of a particular plugin?
How would one reference this property through code external to the plugin? ie. how do you read the property?
This would attach the data to each element the plugin operates on.
(function($) {
$.fn.extend({
myPlugin: function (options) {
var defaultConfig = {data: {}};
return this.each(function () {
$(this).data(
"myPlugin", $.extend(defaultConfig, options)
);
});
}
});
})(jQuery);
For example when called like this:
$("div.foo").myPlugin({option: "value"});
Each <div class="foo"> would have its own copy of
{
data: {},
option: "value"
}
available at $(this).data("myPlugin").
What about using callback functions?
// external code
$('.something').myPlugin({
onLoad : function(object, data) {
// use data here
}
});
I need to redefine the jQuery val() function, but I don't want to mess with the source code. Is it possible to modify it on just one element?
Specifically, I need to do something like this:$("div.smth").val = function() {return this.innerText;};. However, the val function is not modified by this code. What am I doing wrong?
You should instead modify the function of the prototype (jQuery calls this fn). This is where all functions like $(...).something inherit from.
$.fn.val = function() { ... };
If you want to save the original function:
var old = $.fn.val; // `old` won't be overwritten
$.fn.val = function() { ... };
This will do what you want, you need to attach your new val method to jQuery's plugin stack:
$.fn.val = function(value) {
return this[0].innerText;
}
The other answers indicate how to replace the .val() method, but if you know you only need this for one specific element can't you just do this:
$("div.smth")[0].innerText
But in any case isn't that pretty much what the existing jQuery .text() method does?
jsval: function(fn) {
var that = this;
var newfn = function(event) { fn.apply(that, arguments); };
this.click(newfn);
return newfn;
}
Instead now you can call your normal val and on that specific div, call jsval
Below is my my plugin:
(function($) {
$.fn.myPlugin = function(options) {
var opt = $.extend({}, $.fn.myPlugin.defaults, options);
this.foo()
{
alert('test');
}
}
$.fn.myPlugin.defaults = {
};
});
Now I want to extend it without touching the original plugin i.e I want the full feature of existing plugin + the new features which I want. Below are the new things I need:
First:
Name of the new plugin "myPlugin2"
Second:
The "foo" function of the existing plugin should be overridden in the new plugin with this:
function foo() {
alert('test2');
}
Third:
I need to add one more method to my new plugin say function foo2(){} .
Can you help me in achieving this?
You need to define your default name and foo events in your defaults declaration:
$.fn.myPlugin.defaults = {
name: 'test',
onFoo: function() {
alert(this.name);
},
onFoo2: function() {
// your default behaviour for foo2
}
};
Then, when someone calls your plugin, they can override the defaults, in this case name:
$("#myControl").myPlugin({
name: 'test2'
});
Note that they don't need to override onFoo, because it will display an alert with test2. Anyway, if they need to override it to do something different, then they should:
$("#myControl").myPlugin({
name: 'test2',
onFoo: function() {
alert('onFoo overrired');
},
onFoo2: function() {
alert('onFoo2 overrired');
}
});
In your plugin, you invoke the foo methods as
(function($) {
$.fn.myPlugin = function(options) {
var opt = $.extend({}, $.fn.myPlugin.defaults, options);
// if onFoo is defined then call it
if (opt.onFoo) {
opt.onFoo();
}
// if onFoo2 is defined then call it
if (opt.onFoo2) {
opt.onFoo2();
}
}
$.fn.myPlugin.defaults = {
name: 'test',
onFoo: function() {
alert(this.name);
},
onFoo2: function() {
// your default behaviour for foo2
}
};
});
You should use this technique for public methods/properties that you want to expose to the users of your plugin.
I didn't tested but should work
Edit
You need to check if the event is set before calling it:
// if onFoo is defined (not null) then call it
if (opt.onFoo) {
opt.onFoo();
}
You are setting already an event for onFoo and onFoo2, but the user of your plugin might choose to disable it:
$("#myControl").myPlugin({
onFoo: null
});
In this case, although you have defined an onFoo event, the user of your plugin decided to ignore it, by setting it to null. So, even though you have defined an event, you never know what others will do with it, therefore it's better to be on the safe side and check for nullity.
Once again, you need to be careful with what you expose to the end user, because setting/unsetting events should not break the basic functionality of your plugin
If this is any decently coded plugin, you shouldn't be able to alter it's methods. It should of made anything which isn't meant to be invoked an internal function i.e.:
$.fn.oldPlugin = function() {
var foo = function() {
alert('old code');
};
};
There is no way to invoke foo or overwrite it.
Should you not need to change any of the methods/functions then you can use $.extend($.fn.pluginName, {/*your methods/properties*/};
What it all really comes down to is:
How the plugin you want to extend is coded
If you want to overwrite or just extend on it's functionality