webdev && sysadmin quips, tips, articles + more

jQuery Pluginifier - Plugin Instantiator & Plugin Boilerplate

After coming across a recent blog post on jQuery Plugin Boilerplate code it reminded me a few months back when I was looking at the best method for authoring plugins for use at work. After much googling and trial and error I finally came to grips with something and below is the end result.

The code in the jQuery Plugin Boilerplate blog post is very similar to the plugin authoring page in the jQuery Documentation. While they are both good resources, I think they favor single plugins and may potentially lead developers down a path of duplicate code. Similar to jQuery UI’s $.widget what I want to push here is a snippet of code that can transform your code into a “jQuery Plugin” (is there a real definition of this somewhere?).

The Meat - Pluginifier (Instantiator)

The plugin instantiator function creates the prototype plugin function using jQuery.fn, inside that function the code will handle creating/storing/retrieving plugin instances and calling methods on plugins that are already created. This code is meant for reuse for n amount of plugins you create, there is no need to rewrite this block of code (or something similar) for each plugin you have.

//Wrap in a closure to secure $ for jQuery(function($){//name is the name of your plugin$.pluginifier=function(name){//Create the prototype function for the plugin$.fn[name]=function(options){//args isset to everything passed in after options itemvarargs=Array.prototype.slice.call(arguments,1);//Don't waste time if there are no matching elementsif(this.length){//Support chaining by returning thisreturnthis.each(function(){/* * Retrieve the instance from $.data() OR create the instance, _init() it, and store that instance in $.data() * Here your plugin is assumed to live in namespace.plugins.name * Look in the samples folder for a namespaced example */varinstance=$.data(this,name)||$.data(this,name,newnamespace.plugins[name](this,options)._init());//If the first arg is a string we assume you are calling a method inside the plugin instanceif(typeofoptions==="string"){//underscored methods are "private" (similar to jQuery UI's $.widget we allow this to make methods not availble via public api)options=options.replace(/^_/,"");//Check if underscore filtered method existsif(instance[options]){//Call method with argsinstance[options].apply(instance,args);}}});}};};})(jQuery);//After pluginifier and your plugin are in place you need to register your plugins//$.pluginifier( "myAwesomeSauce" );

The Cheese - Plugin Boilerplate

The idea of this plugin boilerplate is that you keep the code that does everything separate from the code that makes it accessible as a jQuery Plugin.

//This should be available somewhere, doesn't have to be here explicitlyvarnamespace={//This will hold all of the pluginsplugins:{}};//Wrap in a closure to secure $ for jQuery(function($){//Constructor - This is what is called when we create call new namspace.plugins.pluginNameHere( this , options );namespace.plugins.pluginNameHere=function(ele,options){this.$this=$(ele);this.options=$.extend({},this.defaults,options);};//These prototype items get assigned to every instance of namespace.plugins.pluginNameHerenamespace.plugins.pluginNameHere.prototype={//This is the default option all instances get, can be overridden by incoming options argumentdefaults:{opt:"tion"},//private init method - This is called immediately after the constructor_init:function(){//useful code here},//private method - We filter out method names that start with an underscore this won't work outside_aPrivateMethod:function(){//Something useful here that is not needed externally},//public method - This method is available via $("#element").pluginNameHere("aPublicMethod","aParameter");aPublicMethod:function(){//Something useful here that anyone can call anytime}};//Here we register the plugin - $("#ele").pluginNameHere(); now works as expected$.pluginifier("pluginNameHere");})(jQuery);

The pickles?

These two jsFiddles are examples of the same plugin written with and without the pluginifier and my boilerplate. You’ll see that the functionality stays the same and the concept to grasp here is on code reuse and management. - Also note there is overhead in filesize when you are dealing with a single plugin, however once you add another plugin that utilizes $.pluginifier you gain a few bytes.

I’m interested to see how people may use this code or what else they use instead. Questions and comments are always welcomed. Alex Sexton deserves most of the credit for this cod (see below).

Resources:

Using Inheritance Patterns to Organize Large jQuery Applications - If you want a greater understanding of this concept take a look at Alex Sexton’s post, you will see where I came up with most of this code (although there are some tweaks that I made for personal preference), read the comments too as there is some good discussion.