My jQuery Plugin Design Pattern

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