Skip to content

Instantly share code, notes, and snippets.

@kflorence
Created November 17, 2010 01:43
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save kflorence/702866 to your computer and use it in GitHub Desktop.
Save kflorence/702866 to your computer and use it in GitHub Desktop.
jQuery plugin pattern
(function($) {
// $.widget-lite
$.plugin = function(name, base, prototype) {
if (!prototype) {
prototype = base;
base = function(options, element) {
if (arguments.length) {
$.data(element, name, this);
this.element = $(element);
this._init(options);
}
};
base.prototype = {
_init: function() {}
};
}
$.extend(true, base.prototype, prototype);
$.fn[name] = function(options) {
var isMethodCall = (typeof options === "string"),
args = Array.prototype.slice.call(arguments, 1),
returnValue = this; // Chain by default
if (isMethodCall) {
if (options.charAt(0) === "_") { // Psuedo-private
return returnValue;
}
this.each(function() {
var instance = $.data(this, name) || new base({}, this);
if (instance && $.isFunction(instance[options])) {
var methodValue = instance[options].apply(instance, args);
if (methodValue !== undefined) {
returnValue = methodValue;
return false;
}
}
});
} else {
this.each(function() {
var instance = $.data(this, name);
if (instance) {
instance._init(options);
} else {
new base(options, this);
}
});
}
return returnValue;
};
};
})(jQuery);
// Set up like so:
jQuery(function($) {
$.plugin("pluginName", {
options: {
test: true
},
_init: function(options) {
$.extend(true, this.options, options || {});
},
somePublicFunc: function() {
console.log(this.options.test);
}
});
});
// Then use like so:
$("#element").pluginName({test: false}); // initialize first
$("#element").pluginName("somePublicFunc"); // => false
// Or use without initializing (danger!?)
$("#element").pluginName("somePublicFunc"); // => true
@kflorence
Copy link
Author

I wonder if there is anything inherently wrong with this...

@cowboy
Copy link

cowboy commented Nov 17, 2010

But then, every time you want to access that element's instance, you need to use $(elem).data("plugin"), which keeps you from being able to chain. A signature like $(elem).plugin() or $(elem).plugin( "submethod" ) (chainable) would probably feel more jQuery-like. This is the signature the jQuery UI Widget Factory provides (among other things).

@kflorence
Copy link
Author

Very true, apart from initialization chaining is impossible. I never really cared for the jQuery UI submethod style, but I suppose it's probably the best thing to use right now. Anyways, thanks for the insight, back to the drawing boards!

@kflorence
Copy link
Author

After reading up on $.widget a bit, it seems like that is basically what I want. I guess I was trying to avoid the overhead of having to incorporate jQuery.UI into my plugin, but there's no use in re-inventing the wheel.

@kflorence
Copy link
Author

I think my "$.widget-lite" should work for most of the things I want to use it for.

@cowboy
Copy link

cowboy commented Nov 17, 2010

I had been hacking around with a "lite" widget factory as well, but haven't gone too far with it yet.

@kflorence
Copy link
Author

Hah! And here I was thinking I was being original ;) I think yours is a bit more straightforward, I wonder which is faster.

@kflorence
Copy link
Author

http://jsfiddle.net/kflorence/bc8Kx/ -- Not sure how accurate that benchmark is, but it seems that prototypical inheritance is definitely the way to go. There are definitely other differences in the two plugins, but that one probably has the most bearing on speed ("new" vs. $.extend({}, {...}) is my guess).

@kflorence
Copy link
Author

Stuck what I've got now in a Repo: https://github.com/kflorence/jquery-plugin
Feel free to tweak

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment