├── README.md ├── jquery-plugin-boilerplate-with-comments.js └── jquery-plugin-boilerplate.js /README.md: -------------------------------------------------------------------------------- 1 | #A jQuery plugin boilerplate 2 | 3 | I created this boilerplate for a jQuery plugin I was working on, and you can use it to kick start your own jQuery plugin development. The features of my boilerplate are: 4 | 5 | - Plugin can be customised using options 6 | - Setters/Getters for options 7 | - Private and public methods 8 | - Callback hooks 9 | - Plugin instances can be destroyed 10 | 11 | ## Usage 12 | 13 | The first thing you’ll need to do is change the name of the plugin, which is hardcoded as ‘demoplugin’, to something a little more descriptive. After that you should be able to follow the comments in the source code to customise the plugin. 14 | 15 | Here are examples of how an end-user would interact with the plugin: 16 | 17 | // Initialize plugin with default options. 18 | $('#element').demoplugin(); 19 | 20 | // Initialize plugin with user defined options. 21 | $('#element').demoplugin({ 22 | option1: 2000, 23 | option2: 'value', 24 | callback1: function () { ... } 25 | }); 26 | 27 | // Call a public method, no arguments. 28 | $('#element').demoplugin('publicFunctionName'); 29 | 30 | // Call a public method with arguments. 31 | $('#element').demoplugin('publicFunctionName', 'arg1', 'arg2'); 32 | 33 | // Get a plugin option. 34 | $('#element').demoplugin('option', 'key'); 35 | 36 | // Set a plugin option after plugin initialization. 37 | $('#element').demoplugin('option', 'key', value); 38 | 39 | // Destroy plugin. 40 | $('#element').demoplugin('destroy'); 41 | 42 | ## Setup options 43 | 44 | It is very useful to be able to customise jQuery plugins on a per instance basis. The boilerplate implements default settings which can be overwritten when the plugin is initialized: 45 | 46 | // Default plugin options. 47 | $.fn[pluginName].defaults = { 48 | color: '#ff0000', 49 | height: 200 50 | }; 51 | 52 | $('#element').demoplugin({ 53 | color: '#0000ff', 54 | height: 400 55 | }); 56 | 57 | Options can also be overwritten after the plugin is initialized, using the `option` method: 58 | 59 | $('#element').demoplugin('option', 'color', '#00ff00'); 60 | 61 | An option value can be fetched using the same method by simply omitting the third parameter: 62 | 63 | var color = $('#element').demoplugin('option', 'color'); 64 | 65 | ## Public and private methods 66 | 67 | Private functions reduce the chance of your users inadvertently calling the plugin’s utility methods. I’m a fan of the [Revealing Module pattern](http://addyosmani.com/resources/essentialjsdesignpatterns/book/#revealingmodulepatternjavascript), so that’s how I chose to implement private/public functionality in my boilerplate. 68 | 69 | function Plugin(element, options) { 70 | // This method is public. 71 | function fooPublic(param1, param2) { 72 | // ... 73 | } 74 | 75 | // This method is private. 76 | function fooPrivate() { 77 | // ... 78 | } 79 | 80 | // Expose methods of Plugin we wish to be public. 81 | return { 82 | fooPublic: fooPublic 83 | }; 84 | } 85 | 86 | Public functions can be called by your users like so: 87 | 88 | $('#element').demoplugin('fooPublic', 'val1', 'val2'); 89 | 90 | ##Callback hooks 91 | 92 | Callback hooks are incredibly powerful. They allow your users to listen for events in your plugin’s behaviour and respond accordingly. Hooks are implemented as functions in the default options object: 93 | 94 | $.fn[pluginName].defaults = { 95 | onSlideshowFinished: function() {} 96 | }; 97 | 98 | Each function is empty to begin with, since the callback’s behaviour will be defined by the user. This is done by overwriting the callback function when setting the plugin’s options. The scope of the callback is the DOM element the plugin is attached to, so in the following example the DOM element would be hidden. 99 | 100 | $('#element').demoplugin({ 101 | onSlideshowFinished: function() { 102 | $(this).hide(); 103 | } 104 | }); 105 | 106 | To trigger a hook, call the plugin’s `hook` method: 107 | 108 | hook('onSlideshowFinished'); 109 | 110 | There are two callbacks implemented by default in the boilerplate: `onInit` and `onDestroy`. 111 | 112 | ##Destroying a plugin instance 113 | 114 | Your users can remove an instance of the plugin by calling its `destroy` method: 115 | 116 | $('#element').demoplugin('destroy'); 117 | 118 | The plugin stores all its functionality in its DOM element’s `data` object. By default the `destroy` method simply removes the stored data values. You will probably need to customise destroy to restore the DOM element to its original state and remove any event handlers your plugin has created. 119 | 120 | ##Credit 121 | 122 | My boilerplate takes inspiration from a number of sources, most notably the [jQuery plugin authoring guidelines](http://docs.jquery.com/Plugins/Authoring), [Stefan Gabos’ boilerplate](http://stefangabos.ro/jquery/jquery-plugin-boilerplate-oop/), and Zeno Rocha and Addy Osmani’s [jQuery Boilerplate](http://jqueryboilerplate.com/). 123 | -------------------------------------------------------------------------------- /jquery-plugin-boilerplate-with-comments.js: -------------------------------------------------------------------------------- 1 | /** 2 | * A jQuery plugin boilerplate. 3 | * Author: Jonathan Nicol @f6design 4 | */ 5 | ;(function($) { 6 | // Change this to your plugin name. 7 | var pluginName = 'demoplugin'; 8 | 9 | /** 10 | * Plugin object constructor. 11 | * Implements the Revealing Module Pattern. 12 | */ 13 | function Plugin(element, options) { 14 | // References to DOM and jQuery versions of element. 15 | var el = element; 16 | var $el = $(element); 17 | 18 | // Extend default options with those supplied by user. 19 | options = $.extend({}, $.fn[pluginName].defaults, options); 20 | 21 | /** 22 | * Initialize plugin. 23 | */ 24 | function init() { 25 | // Add any initialization logic here... 26 | 27 | hook('onInit'); 28 | } 29 | 30 | /** 31 | * Example Public Method 32 | */ 33 | function fooPublic() { 34 | // Code goes here... 35 | } 36 | 37 | /** 38 | * Get/set a plugin option. 39 | * Get usage: $('#el').demoplugin('option', 'key'); 40 | * Set usage: $('#el').demoplugin('option', 'key', value); 41 | */ 42 | function option (key, val) { 43 | if (val) { 44 | options[key] = val; 45 | } else { 46 | return options[key]; 47 | } 48 | } 49 | 50 | /** 51 | * Destroy plugin. 52 | * Usage: $('#el').demoplugin('destroy'); 53 | */ 54 | function destroy() { 55 | // Iterate over each matching element. 56 | $el.each(function() { 57 | var el = this; 58 | var $el = $(this); 59 | 60 | // Add code to restore the element to its original state... 61 | 62 | hook('onDestroy'); 63 | // Remove Plugin instance from the element. 64 | $el.removeData('plugin_' + pluginName); 65 | }); 66 | } 67 | 68 | /** 69 | * Callback hooks. 70 | * Usage: In the defaults object specify a callback function: 71 | * hookName: function() {} 72 | * Then somewhere in the plugin trigger the callback: 73 | * hook('hookName'); 74 | */ 75 | function hook(hookName) { 76 | if (options[hookName] !== undefined) { 77 | // Call the user defined function. 78 | // Scope is set to the jQuery element we are operating on. 79 | options[hookName].call(el); 80 | } 81 | } 82 | 83 | // Initialize the plugin instance. 84 | init(); 85 | 86 | // Expose methods of Plugin we wish to be public. 87 | return { 88 | option: option, 89 | destroy: destroy, 90 | fooPublic: fooPublic 91 | }; 92 | } 93 | 94 | /** 95 | * Plugin definition. 96 | */ 97 | $.fn[pluginName] = function(options) { 98 | // If the first parameter is a string, treat this as a call to 99 | // a public method. 100 | if (typeof arguments[0] === 'string') { 101 | var methodName = arguments[0]; 102 | var args = Array.prototype.slice.call(arguments, 1); 103 | var returnVal; 104 | this.each(function() { 105 | // Check that the element has a plugin instance, and that 106 | // the requested public method exists. 107 | if ($.data(this, 'plugin_' + pluginName) && typeof $.data(this, 'plugin_' + pluginName)[methodName] === 'function') { 108 | // Call the method of the Plugin instance, and Pass it 109 | // the supplied arguments. 110 | returnVal = $.data(this, 'plugin_' + pluginName)[methodName].apply(this, args); 111 | } else { 112 | throw new Error('Method ' + methodName + ' does not exist on jQuery.' + pluginName); 113 | } 114 | }); 115 | if (returnVal !== undefined){ 116 | // If the method returned a value, return the value. 117 | return returnVal; 118 | } else { 119 | // Otherwise, returning 'this' preserves chainability. 120 | return this; 121 | } 122 | // If the first parameter is an object (options), or was omitted, 123 | // instantiate a new instance of the plugin. 124 | } else if (typeof options === "object" || !options) { 125 | return this.each(function() { 126 | // Only allow the plugin to be instantiated once. 127 | if (!$.data(this, 'plugin_' + pluginName)) { 128 | // Pass options to Plugin constructor, and store Plugin 129 | // instance in the elements jQuery data object. 130 | $.data(this, 'plugin_' + pluginName, new Plugin(this, options)); 131 | } 132 | }); 133 | } 134 | }; 135 | 136 | // Default plugin options. 137 | // Options can be overwritten when initializing plugin, by 138 | // passing an object literal, or after initialization: 139 | // $('#el').demoplugin('option', 'key', value); 140 | $.fn[pluginName].defaults = { 141 | onInit: function() {}, 142 | onDestroy: function() {} 143 | }; 144 | 145 | })(jQuery); -------------------------------------------------------------------------------- /jquery-plugin-boilerplate.js: -------------------------------------------------------------------------------- 1 | /** 2 | * A jQuery plugin boilerplate. 3 | * Author: Jonathan Nicol @f6design 4 | */ 5 | ;(function($) { 6 | var pluginName = 'demoplugin'; 7 | 8 | function Plugin(element, options) { 9 | var el = element; 10 | var $el = $(element); 11 | 12 | options = $.extend({}, $.fn[pluginName].defaults, options); 13 | 14 | function init() { 15 | // Add any initialization logic here... 16 | 17 | hook('onInit'); 18 | } 19 | 20 | function fooPublic() { 21 | // Code goes here... 22 | } 23 | 24 | function option (key, val) { 25 | if (val) { 26 | options[key] = val; 27 | } else { 28 | return options[key]; 29 | } 30 | } 31 | 32 | function destroy() { 33 | $el.each(function() { 34 | var el = this; 35 | var $el = $(this); 36 | 37 | // Add code to restore the element to its original state... 38 | 39 | hook('onDestroy'); 40 | $el.removeData('plugin_' + pluginName); 41 | }); 42 | } 43 | 44 | function hook(hookName) { 45 | if (options[hookName] !== undefined) { 46 | options[hookName].call(el); 47 | } 48 | } 49 | 50 | init(); 51 | 52 | return { 53 | option: option, 54 | destroy: destroy, 55 | fooPublic: fooPublic 56 | }; 57 | } 58 | 59 | $.fn[pluginName] = function(options) { 60 | if (typeof arguments[0] === 'string') { 61 | var methodName = arguments[0]; 62 | var args = Array.prototype.slice.call(arguments, 1); 63 | var returnVal; 64 | this.each(function() { 65 | if ($.data(this, 'plugin_' + pluginName) && typeof $.data(this, 'plugin_' + pluginName)[methodName] === 'function') { 66 | returnVal = $.data(this, 'plugin_' + pluginName)[methodName].apply(this, args); 67 | } else { 68 | throw new Error('Method ' + methodName + ' does not exist on jQuery.' + pluginName); 69 | } 70 | }); 71 | if (returnVal !== undefined){ 72 | return returnVal; 73 | } else { 74 | return this; 75 | } 76 | } else if (typeof options === "object" || !options) { 77 | return this.each(function() { 78 | if (!$.data(this, 'plugin_' + pluginName)) { 79 | $.data(this, 'plugin_' + pluginName, new Plugin(this, options)); 80 | } 81 | }); 82 | } 83 | }; 84 | 85 | $.fn[pluginName].defaults = { 86 | onInit: function() {}, 87 | onDestroy: function() {} 88 | }; 89 | 90 | })(jQuery); --------------------------------------------------------------------------------