Almost every Web2.0 widget that I create is crafted around the jQuery framework. As many other developers have posted their 'plugin design pattern', I figured I'd provide some insight into how I set mine up. Rather than try to explain in prose, I've put a generic code sample below, and have placed inline comments for clarification.
Note: This pattern has been modeled around the jQuery plugin authoring best practices.
/*
* enclose the plugin's JS in a closure so that
* we do not pollute the global namespace
* and avoid ns conflicts
*/
;(function($){ // $ represents the jQuery obj passed in
// local constants and labels
var PLUGIN_POSTFIX = ".pluginName", // have some unique identifier
OPTS = "opts"+PLUGIN_POSTFIX, // the attribute for the options data
const1 = "CONST1", // define constants that are required in this plugin
const2 = "CONST2";
// defaults, public scope for extensibility
// these are really the _core_ defaults for the plugin
// i.e. everything you need to init the plugin without user input
$.pluginName = {
defaults: {
option1: "option1",
option2: function(){}
}
};
// the jQuery chainable helper, to allow jQuery('#elem').pluginName(x)
$.fn.pluginName = function(incoming, additional){
var $this = $(this);
// determine the type of the incoming argument
var type = typeof (incoming);
// NOW DELEGATE ON CONDITIONALS -- done with if or switch
// if it isn't defined or its an object, initialize
if(type == "undefined" || type == "object")
return initialize($this, incoming);
// if its a string, then its a event delegation.
// additional is the param passed in with the call
// i.e. jQuery().pluginName('event', additional)
// and can be undefined
else if (type == "string")
return $this.trigger(incoming+PLUGIN_POSTFIX, additional);
// (optional): if its a number, make a selection
else if (type == "number")
return $this.trigger(/*some defined function*/+PLUGIN_POSTFIX, incoming);
};
// the method that does the initialization
function initialize($subject, options){
// merge the options that the user has defined with our core options
var opts = $.extend({}, $.pluginName.defaults, options);
// loop through all the elements desired to initialize on
return $subject.each(function(subj){
var $subj = $(this);
// store the options with the plugin node being init'd
$subj.data(OPTS, opts);
// loop through all the events in PluginEvents and
// bind them to the subject and pass the subject in
// to be later grabbed as event.data
for(pluginEvent in PluginEvents)
$subj.bind(pluginEvent+_POSTFIX, $subj, PluginEvents[pluginEvent]);
/** DO INITIALIZATION RELATED THINGS HERE **/
});
};
/*
* This pattern simplifies the event binding initialization
*
* each object is a event name / function pairs that are bound to
* the plugin note that the functions use a 'helper' method which grabs
* common elements that are used within each of the event methods
*
*/
var PluginEvents = {
// jQuery().pluginName('event1', additional)
event1: function(evt, additional){
var helper = pluginObjectHelper(evt);
// do stuff with 'helper.options' and/or 'helper.subject'
},
// jQuery().pluginName('event2') = getter,
// jQuery().pluginName('event2', value) = setter
event2: function(evt, additional){
var helper = pluginObjectHelper(evt);
if(additional) {
// treat as setter
} else {
// treat as getter
}
},
// jQuery().pluginName('destroy')
destroy: function(evt){
var helper = pluginObjectHelper(evt);
// unbind all the events subscribed via this plugin
helper.subject.unbind(PLUGIN_POSTFIX);
}
};
// private scope helper to retrieve the necessary
// plugin related elements from the event object
// initially bound
function pluginObjectHelper(evt){
var $mySubject = evt.data;
return {
// return the object that has been plugged in
subject: $mySubject,
// return the options of the plugin when init'd
options: $mySubject.data(OPTS)
}
}
})(jQuery); // pass jQuery object in to self enclosing fn
Nirvana Tikku, Tikku.com © 2010-2013