Created
December 11, 2009 19:39
-
-
Save he9lin/254453 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// $.widget is a factory to create jQuery plugins | |
// taking some boilerplate code out of the plugin code | |
function getter(namespace, plugin, method, args) { | |
function getMethods(type) { | |
var methods = $[namespace][plugin][type] || []; | |
return (typeof methods == 'string' ? methods.split(/,?\s+/) : methods); | |
} | |
var methods = getMethods('getter'); //[ui][plugin_name][getter], all getter methods | |
if (args.length == 1 && typeof args[0] == 'string') { | |
methods = methods.concat(getMethods('getterSetter')); //[ui][plugin_name][getterSetter] | |
} | |
return ($.inArray(method, methods) != -1); //see if the method parameter is in methods | |
} | |
$.widget = function(name, prototype) { | |
var namespace = name.split(".")[0]; | |
name = name.split(".")[1]; | |
// create plugin method | |
$.fn[name] = function(options) { | |
var isMethodCall = (typeof options == 'string'), | |
args = Array.prototype.slice.call(arguments, 1); | |
// prevent calls to internal methods | |
if (isMethodCall && options.substring(0, 1) == '_') { | |
return this; | |
} | |
// handle getter methods: | |
// if it's a method call and a getter method provided by the | |
// plugin, then we go get the instance of the plugin by using | |
// $.data(element, plugin_name), and apply the method to the | |
// instance(why the instance, not the element?) | |
if (isMethodCall && getter(namespace, name, options, args)) { | |
var instance = $.data(this[0], name); | |
return (instance ? instance[options].apply(instance, args) | |
: undefined); | |
} | |
// handle initialization and non-getter methods | |
return this.each(function() { | |
var instance = $.data(this, name); | |
// constructor, here we actually set $.data(element, plugin_name) | |
// to be an instance of the plugin | |
(!instance && !isMethodCall && | |
$.data(this, name, new $[namespace][name](this, options))._init()); | |
// method call, call the method if instance is set and method is valid | |
(instance && isMethodCall && $.isFunction(instance[options]) && | |
instance[options].apply(instance, args)); | |
}); | |
}; | |
// create widget constructor | |
$[namespace] = $[namespace] || {}; | |
$[namespace][name] = function(element, options) { | |
var self = this; | |
this.namespace = namespace; | |
this.widgetName = name; | |
this.widgetEventPrefix = $[namespace][name].eventPrefix || name; | |
this.widgetBaseClass = namespace + '-' + name; | |
this.options = $.extend({}, | |
$.widget.defaults, | |
$[namespace][name].defaults, | |
$.metadata && $.metadata.get(element)[name], | |
options); | |
// setup a few useful methods, including destroy which removes | |
// the plugin instance from the element. this.element is assigned | |
// by jquery version of 'element' | |
this.element = $(element) | |
.bind('setData.' + name, function(event, key, value) { | |
if (event.target == element) { | |
return self._setData(key, value); | |
} | |
}) | |
.bind('getData.' + name, function(event, key) { | |
if (event.target == element) { | |
return self._getData(key); | |
} | |
}) | |
.bind('remove', function() { | |
return self.destroy(); | |
}); | |
}; | |
// add widget prototype | |
$[namespace][name].prototype = $.extend({}, $.widget.prototype, prototype); | |
// TODO: merge getter and getterSetter properties from widget prototype | |
// and plugin prototype | |
$[namespace][name].getterSetter = 'option'; | |
}; | |
$.widget.prototype = { | |
_init: function() {}, | |
destroy: function() { | |
this.element.removeData(this.widgetName) //removes previously set by $.data(element, plugin) | |
.removeClass(this.widgetBaseClass + '-disabled' + ' ' + this.namespace + '-state-disabled') | |
.removeAttr('aria-disabled'); | |
}, | |
option: function(key, value) { | |
var options = key, | |
self = this; | |
if (typeof key == "string") { | |
if (value === undefined) { | |
return this._getData(key); // getter | |
} | |
options = {}; // set options to a hash | |
options[key] = value; // setup key/value pair | |
} | |
// options is a hash, might contain more key/value pair | |
$.each(options, function(key, value) { | |
self._setData(key, value); | |
}); | |
}, | |
_getData: function(key) { | |
return this.options[key]; | |
}, | |
_setData: function(key, value) { | |
this.options[key] = value; | |
if (key == 'disabled') { | |
this.element | |
[value ? 'addClass' : 'removeClass']( | |
this.widgetBaseClass + '-disabled' + ' ' + | |
this.namespace + '-state-disabled') | |
.attr("aria-disabled", value); | |
} | |
}, | |
enable: function() { | |
this._setData('disabled', false); | |
}, | |
disable: function() { | |
this._setData('disabled', true); | |
}, | |
//type is the method name | |
_trigger: function(type, event, data) { | |
var callback = this.options[type], | |
eventName = (type == this.widgetEventPrefix | |
? type : this.widgetEventPrefix + type); | |
//get the event object from 'event' parameter | |
event = $.Event(event); | |
event.type = eventName; | |
// copy original event properties over to the new event | |
// this would happen if we could call $.event.fix instead of $.Event | |
// but we don't have a way to force an event to be fixed multiple times | |
if (event.originalEvent) { | |
for (var i = $.event.props.length, prop; i;) { | |
prop = $.event.props[--i]; | |
event[prop] = event.originalEvent[prop]; | |
} | |
} | |
this.element.trigger(event, data); | |
return !($.isFunction(callback) && callback.call(this.element[0], event, data) === false | |
|| event.isDefaultPrevented()); | |
} | |
}; | |
$.widget.defaults = { | |
disabled: false | |
}; |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment