-
-
Save kflorence/702866 to your computer and use it in GitHub Desktop.
(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 |
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).
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!
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.
I think my "$.widget-lite" should work for most of the things I want to use it for.
I had been hacking around with a "lite" widget factory as well, but haven't gone too far with it yet.
Hah! And here I was thinking I was being original ;) I think yours is a bit more straightforward, I wonder which is faster.
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).
Stuck what I've got now in a Repo: https://github.com/kflorence/jquery-plugin
Feel free to tweak
I wonder if there is anything inherently wrong with this...