steal('jquery/class', 'jquery/lang/string', 'jquery/event/destroyed', function ($){ var bind = function (el, ev, callback){ var wrappedCallback, binder = el.bind && el.unbind? el: $(isFunction(el)? [el] : el); if (ev.indexOf(">") === 0) { ev = ev.substr(1); wrappedCallback = function (event){ if (_AN_Read_target("target", event) === el) { callback.apply(this, arguments); } } ; } binder.bind(ev, wrappedCallback || callback); return function (){ binder.unbind(ev, wrappedCallback || callback); el = ev = callback = wrappedCallback = null ; } ; } , makeArray = $.makeArray, isArray = $.isArray, isFunction = $.isFunction, extend = $.extend, Str = $.String, each = $.each, STR_PROTOTYPE = 'prototype', STR_CONSTRUCTOR = 'constructor', slice = Array[STR_PROTOTYPE].slice, delegate = function (el, selector, ev, callback){ var binder = el.delegate && el.undelegate? el: $(isFunction(el)? [el] : el); binder.delegate(selector, ev, callback); return function (){ binder.undelegate(selector, ev, callback); binder = el = ev = callback = selector = null ; } ; } , binder = function (el, ev, callback, selector){ return selector? delegate(el, selector, ev, callback): bind(el, ev, callback); } , shifter = function shifter(context, name){ var method = typeof name == "string"? context[name]: name; return function (){ context.called = name; return method.apply(context, [this.nodeName? $(this): this] .concat(slice.call(arguments, 0))); } ; } , dotsReg = /\./g, controllersReg = /_?controllers?/ig, underscoreAndRemoveController = function (className){ return Str.underscore(_AN_Call_replace("replace", _AN_Call_replace("replace", _AN_Call_replace("replace", className, "jQuery.", ""), dotsReg, '_'), controllersReg, "")); } , actionMatcher = /[^\w]/, parameterReplacer = /\{([^\}]+)\}/g, breaker = /^(?:(.*?)\s)?([\w\.\:>]+)$/, basicProcessor, data = function (el, data){ return $.data(el, "controllers", data); } ; $.Class("jQuery.Controller", { setup: function (){ this._super.apply(this, arguments); if (!this.shortName || this.fullName == "jQuery.Controller") { return ; } this._fullName = underscoreAndRemoveController(this.fullName); this._shortName = underscoreAndRemoveController(this.shortName); var controller = this, pluginname = this.pluginName || this._fullName, funcName, forLint; if (!$.fn[pluginname]) { $.fn[pluginname] = function (options){ var args = makeArray(arguments), isMethod = typeof options == "string" && isFunction(controller[STR_PROTOTYPE][options]), meth = args[0]; return this.each(function (){ var controllers = data(this), plugin = controllers && controllers[pluginname]; if (plugin) { if (isMethod) { plugin[meth].apply(plugin, args.slice(1)); } else { plugin.update.apply(plugin, args); } } else { controller.newInstance.apply(controller, [this] .concat(args)); } } ); } ; } if (!isArray(this.listensTo)) { throw "listensTo is not an array in " + this.fullName } this.actions = { } ; for (funcName in this[STR_PROTOTYPE]){ if (funcName == 'constructor' || !isFunction(this[STR_PROTOTYPE][funcName])) { continue ; } if (this._isAction(funcName)) { this.actions[funcName] = this._action(funcName); } } } , hookup: function (el){ return new this(el); } , _isAction: function (methodName){ if (actionMatcher.test(methodName)) { return true ; } else { return $.inArray(methodName, this.listensTo) > -1 || $.event.special[methodName] || processors[methodName]; } } , _action: function (methodName, options){ parameterReplacer.lastIndex = 0; if (!options && parameterReplacer.test(methodName)) { return null ; } var convertedName = options? Str.sub(methodName, [options, window] ): methodName, arr = isArray(convertedName), parts = (arr? convertedName[1]: convertedName).match(breaker), event = parts[2], processor = processors[event] || basicProcessor; return { processor: processor, parts: parts, delegate: arr? convertedName[0]: undefined} ; } , processors: { } , listensTo: [] , defaults: { } } , { setup: function (element, options){ var funcName, ready, cls = this[STR_CONSTRUCTOR]; element = (typeof element == 'string'? $(element): (element.jquery? element: [element] ))[0]; var pluginname = cls.pluginName || cls._fullName; this.element = $(element).addClass(pluginname); (data(element) || data(element, { } ))[pluginname] = this; this.options = extend(extend(true , { } , cls.defaults), options); this.called = "init"; this.bind(); return [this.element, this.options] .concat(makeArray(arguments).slice(2)); } , bind: function (el, eventName, func){ if (el === undefined) { this._bindings = [] ; var cls = this[STR_CONSTRUCTOR], bindings = this._bindings, actions = cls.actions, element = this.element; for (funcName in actions){ if (actions.hasOwnProperty(funcName)) { ready = actions[funcName] || cls._action(funcName, this.options); bindings.push(ready.processor(ready.delegate || element, ready.parts[2], ready.parts[1], funcName, this)); } } var destroyCB = shifter(this, "destroy"); element.bind("destroyed", destroyCB); bindings.push(function (el){ $(el).unbind("destroyed", destroyCB); } ); return _AN_Read_length("length", bindings); } if (typeof el == 'string') { func = eventName; eventName = el; el = this.element; } return this._binder(el, eventName, func); } , _binder: function (el, eventName, func, selector){ if (typeof func == 'string') { func = shifter(this, func); } this._bindings.push(binder(el, eventName, func, selector)); return _AN_Read_length('length', this._bindings); } , _unbind: function (){ var el = this.element[0]; each(this._bindings, function (key, value){ value(el); } ); this._bindings = [] ; } , delegate: function (element, selector, eventName, func){ if (typeof element == 'string') { func = eventName; eventName = selector; selector = element; element = this.element; } return this._binder(element, eventName, func, selector); } , update: function (options){ extend(this.options, options); this._unbind(); this.bind(); } , destroy: function (){ if (this._destroyed) { throw this[STR_CONSTRUCTOR].shortName + " controller already deleted" } var self = this, fname = this[STR_CONSTRUCTOR].pluginName || this[STR_CONSTRUCTOR]._fullName, controllers; this._destroyed = true ; this.element.removeClass(fname); this._unbind(); delete this._actions; delete this.element.data("controllers")[fname]; $(this).triggerHandler("destroyed"); this.element = null ; } , find: function (selector){ return this.element.find(selector); } , _set_called: true } ); var processors = $.Controller.processors, basicProcessor = function (el, event, selector, methodName, controller){ return binder(el, event, shifter(controller, methodName), selector); } ; each("change click contextmenu dblclick keydown keyup keypress mousedown mousemove mouseout mouseover mouseup reset resize scroll select submit focusin focusout mouseenter mouseleave".split(" "), function (i, v){ processors[v] = basicProcessor; } ); var i, isAControllerOf = function (instance, controllers){ for (i = 0; i < _AN_Read_length("length", controllers); i++ ){ if (typeof controllers[i] == 'string'? instance[STR_CONSTRUCTOR]._shortName == controllers[i]: instance instanceof controllers[i]) { return true ; } } return false ; } ; $.fn.extend({ controllers: function (){ var controllerNames = makeArray(arguments), instances = [] , controllers, c, cname; this.each(function (){ controllers = $.data(this, "controllers"); for (cname in controllers){ if (controllers.hasOwnProperty(cname)) { c = controllers[cname]; if (!_AN_Read_length("length", controllerNames) || isAControllerOf(c, controllerNames)) { instances.push(c); } } } } ); return instances; } , controller: function (controller){ return this.controllers.apply(this, arguments)[0]; } } ); } );