Skip to content

Instantly share code, notes, and snippets.

@orioltf
Created December 5, 2012 16:11
Show Gist options
  • Save orioltf/4216997 to your computer and use it in GitHub Desktop.
Save orioltf/4216997 to your computer and use it in GitHub Desktop.
#JQUERY: My jQuery plugin boilerplate
/*
* Project :
* Description :
* Author :
* License :
*/
// the semi-colon before function invocation is a safety net against concatenated
// scripts and/or other plugins which may not be closed properly.
;(function($, window, document, undefined) {
"use strict";
// undefined is used here as the undefined global variable in ECMAScript 3 is
// mutable (ie. it can be changed by someone else). undefined isn't really being
// passed in so we can ensure the value of it is truly undefined. In ES5, undefined
// can no longer be modified.
// window and document are passed through as local variable rather than global
// as this (slightly) quickens the resolution process and can be more efficiently
// minified (especially when both are regularly referenced in your plugin).
// Create the defaults once
var pluginName = "defaultPluginName",
defaults = {
propertyName: "value"
};
// The actual plugin constructor
function Plugin(element, options) {
var meta;
this.$element = $(element);
// Grab plugin options provided via data properties in the html element. Ex:
// <div class="calendar js-calendar" data-widget-plugin-opts="{'optionA':'someCoolOptionString'}">
meta = this.$element.data(pluginName+'-opts');
// jQuery has an extend method which merges the contents of two or
// more objects, storing the result in the first object. The first object
// is generally empty as we don't want to alter the default options for
// future instances of the plugin
this.options = $.extend({}, defaults, options, meta);
// Grab here common structural elements if needed
this.$header = this.$element.find('.js-header');
this.$body = this.$element.find('.js-body');
this._defaults = defaults;
this._name = pluginName;
this.init();
}
Plugin.prototype = {
init: function() {
// Place initialization logic here
// There's access to
// - the DOM element: this.$element
// - the options this.options
// add more functions like the one below and
// call them like so: this.yourOtherFunction(this.$element, this.options).
var self = this;
this.$header.on('click.' + pluginName, '.js-header-subele', function(e) {
e.preventDefault();
self.editSubElement();
});
this.$header.on('change.' + pluginName, '.js-header-subel-select', function(e) {
e.preventDefault();
self.saveSubElement();
});
},
editSubElement: function() {
this.$header.addClass('editing');
},
saveSubElement: function() {
var val = this.$header.find('.title').val();
// save val to database
this.$header.removeClass('editing');
},
yourOtherFunction: function(el, options) {
// some logic
},
// Remove the plugin without removing the DOM element
// If pluginName = js-calendar then
// remove the plugin like: $('.js-calendar').data('js-calendar').destroy();
destroy: function() {
this.$element.off('.' + pluginName);
this.$element.find('*').off('.' + pluginName);
this.$element.removeData(pluginName);
this.$element = null;
}
};
// A really lightweight plugin wrapper around the constructor,
// preventing against multiple instantiations and allowing any
// public function (ie. a function whose name doesn't start
// with an underscore) to be called via the jQuery plugin,
// e.g. $(element).defaultPluginName('functionName', arg1, arg2)
$.fn[pluginName] = function(options) {
var args = arguments;
if (options === undefined || typeof options === 'object') {
return this.each(function() {
if (!$.data(this, 'plugin_' + pluginName)) {
$.data(this, 'plugin_' + pluginName, new Plugin(this, options));
}
});
} else if (typeof options === 'string' && options[0] !== '_' && options !== 'init') {
return this.each(function() {
var instance = $.data(this, 'plugin_' + pluginName);
if (instance instanceof Plugin && typeof instance[options] === 'function') {
instance[options].apply(instance, Array.prototype.slice.call(args, 1));
}
});
}
};
// PubSub (publish/subscribe) to automatically invoke the plugin if the plugin needs to be
// initialized after its DOM elements have been loaded via AJAX
$(document).on('dom_loaded ajax_loaded', function(e, nodes) {
var $nodes = $(nodes);
var $elements = $nodes.find('.' + pluginName);
$elements = $elements.add($nodes.filter('.' + pluginName));
$elements.plugin();
});
})(jQuery, window, document);
// Plugin usage
$(function() {
// PubSub (publish/subscribe) to automatically invoke the plugin if the plugin needs to be
// initialized after its DOM elements have been loaded via AJAX
var $document = $(document);
$document.trigger('domloaded', $document);
$('.someselector').load('/my/url', function(nodes) {
$document.trigger('ajax_loaded', nodes);
});
// Instantiate the plugin on the given DOM elements
$('#elem, .js-elems').defaultPluginName(/*{optionA: 'a', optionB: 'b'}*/);
});
/*
* Project :
* Description :
* Author :
* License :
*/
;(function($, window, document, undefined) {
"use strict";
var pluginName = "defaultPluginName",
defaults = {
propertyName: "value"
};
function Plugin(element, options) {
var meta;
this.$element = $(element);
meta = this.$element.data(pluginName+'-opts');
this.options = $.extend({}, defaults, options, meta);
this.$header = this.$element.find('.js-header');
this.$body = this.$element.find('.js-body');
this._defaults = defaults;
this._name = pluginName;
this.init();
}
Plugin.prototype = {
init: function() {
var self = this;
this.$header.on('click.' + pluginName, '.js-header-subele', function(e) {
e.preventDefault();
self.editSubElement();
});
this.$header.on('change.' + pluginName, '.js-header-subele-select', function(e) {
e.preventDefault();
self.saveSubElement();
});
},
editSubElement: function() {
this.$header.addClass('editing');
},
saveSubElement: function() {
var val = this.$header.find('.title').val();
this.$header.removeClass('editing');
},
yourOtherFunction: function(el, options) {
},
destroy: function() {
this.$element.off('.' + pluginName);
this.$element.find('*').off('.' + pluginName);
this.$element.removeData(pluginName);
this.$element = null;
}
};
$.fn[pluginName] = function(options) {
var args = arguments;
if (options === undefined || typeof options === 'object') {
return this.each(function() {
if (!$.data(this, 'plugin_' + pluginName)) {
$.data(this, 'plugin_' + pluginName, new Plugin(this, options));
}
});
} else if (typeof options === 'string' && options[0] !== '_' && options !== 'init') {
return this.each(function() {
var instance = $.data(this, 'plugin_' + pluginName);
if (instance instanceof Plugin && typeof instance[options] === 'function') {
instance[options].apply(instance, Array.prototype.slice.call(args, 1));
}
});
}
};
$(document).on('dom_loaded ajax_loaded', function(e, nodes) {
var $nodes = $(nodes);
var $elements = $nodes.find('.' + pluginName);
$elements = $elements.add($nodes.filter('.' + pluginName));
$elements.plugin();
});
})(jQuery, window, document);
// Plugin usage
$(function() {
var $document = $(document);
$document.trigger('domloaded', $document);
$('.someselector').load('/my/url', function(nodes) {
$document.trigger('ajax_loaded', nodes);
});
$('#elem, .js-elems').defaultPluginName(/*{optionA: 'a', optionB: 'b'}*/);
});
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment