Using namespaces with jQuery Widgets


Creating plugins for jQuery is a relatively straightforward task, however poorly named plugins can conflict with one another (or even with core jQuery functionality). I have seen numerous attempts at solving this problem which each have their advantages and disadvantages.

My take on this problem is to define widgets in a completely separate namespace and then refer to them using a single jQuery plugin `widget`. This plugin depends upon the following jQuery variant of my `$namespace` function from here.

The source in this post is available under multiple licenses: BSD, GNU/GPLv2, GNU/GPLv3.

/*!
 * (c) 2010-2011 Rotorz Limited. All rights reserved.
 * License:	BSD, GNU/GPLv2, GNU/GPLv3
 * Author:	Lea Hayes
 * Website:	http://leahayes.co.uk
*/
$global = window;
$namespace = function(ns, extension) {
    if (ns == '')
        return $global;

    if (typeof ns === 'string') {
        var fragments = ns.split('.');
        var node = $global;
        for (var i = 0; i < fragments.length; ++i) {
            var f = fragments[i];
            node = !node[f] ? (node[f] = {}) : node[f];
        }
    }
    else
        node = ns;

    if (extension)
        $.extend(node, extension);

    return node;
};

Each widget can be defined as a class within a vendor specific namespace (like `my` for example) using something like the following:

$namespace('my').SpecialWidget = function(options) {
    this.color = options.color;
};

// Invoked automatically when element is attached to object.
my.SpecialWidget.prototype.attach = function(element) {
    this.element = element;
    element.css('color', this.color);
};

my.SpecialWidget.prototype.enable = function() {
    this.element.css('opacity', 1.0);
};
my.SpecialWidget.prototype.disable = function() {
    this.element.css('opacity', 0.5);
};

The following jQuery `widget` plugin will then make the above work in a fairly standard jQuery fashion:

(function($) {

$.fn.widget = function(name, a, b) {
    if (!name) return this.data('widget');
    this.each(function() {
        var widget;
        if (message === 'init') {
            a = $namespace(a);
            widget = new a(b || {});
            widget.attach(this);
            this.data('widget', widget);
        }
        else {
            widget = this.data('widget');
            widget[message].apply(widget, Array.prototype.slice.call(arguments, 1));
        }
    });
    return this;
};

})(jQuery);

The special widget can then be used as follows:

// Attach widget to element.
$('div.my-special-widget')
    .widget('init', my.SpecialWidget, { color: 'red' });

// Disable widget.
$('div.my-special-widget')
    .widget('disable');

// Interact with widget object directly.
var widget = $('div.my-special-widget').widget();
widget.enable();
Advertisements

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s