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 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.

/*!
 * (c) 2010-2011 Rotorz Limited. All rights reserved.
 * License: BSD
 * 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();