var Listener = (function () {
/*! (C) Andrea Giammarchi - Mit Style */
/**
* A basic module with all functionalities we need to create listeners.
* @author Andrea Giammarchi
* @license Mit Style
* @url http://webreflection.blogspot.com/2010/05/event-driven-application-and-most-basic.html
*/
// helpers
/**
* Return the named listener, if any, or create a new named stack.
* @param Object the generic instance that is implementing a Listener.
* @param String the listener name
* @returns Array the named listener
*/
function _get(self, name) {
return self[_hash][name] || _set(self[_hash], name);
}
/**
* Create an Array and associate it with a certain listener name.
* Ensure that indexOf method is attached (as privileged).
* @param Object the Listener object
* @param String the missing listener name
* @returns Array the new stack with a privileged indexOf method
*/
function _set(listener, name) {
(listener[name] = []).indexOf = indexOf;
return listener[name];
}
var
/**
* Native Array.prototype.indexOf or an optimized fallback.
* @type Function
* @name indexOf
* @private
*/
indexOf = Array.prototype.indexOf || function (callback) {
for (var i = this.length; i-- && this[i] !== callback;) {}
return i;
},
/**
* A unique hash to avoid name clashes when Listener is used as mixin.
* @type String
* @private
*/
_hash = "_" + (Math.random() + "_Listener").slice(2),
/**
* Used to cache last indexOf result in order to easily
* perform operations over the listener stack.
* @type Number
* @private
*/
_index,
/**
* Used to cache last used listener access to easily
* perform common stack operations.
* @type Array
* @private
*/
_listener
;
/**
* @name Listener
* @type Object
* @public
* @module
*/
return {
/**
* Create the listener object if it's not there
*/
initListener: function () {
this[_hash] || (this[_hash] = {});
},
/**
* Add a listener if not there already.
* @param String a generic listener name
* @param Function callback to add
*/
addListener: function (name, callback) {
if (!this.hasListener(name, callback)) {
_listener.push(callback);
}
},
/**
* Fire registered callbacks for a specific listener
* following the same DOM logic.
* The firing order is FIFO.
* If there is no callback, nothing will be fired.
* If a listener with the same name is added,
* this will be fire next time.
* If a listener with the same name is removed,
* this won't be fired.
* @param String a generic listener name
* @param Function callback to add
*/
fireListener: function (name, event) {
for (var
listener = _get(this, name).slice(),
i = 0, length = listener.length,
index, fire;
i < length; ++i
) {
index = _listener.indexOf(fire = listener[i]);
if (-1 < index && index <= i) {
fire.call(this, event);
}
}
},
/**
* Verify a listener for a specific name.
* @param String a generic listener name
* @param Function callback to verify
* @returns Boolean true if the listener has been added before.
*/
hasListener: function (name, callback) {
return -1 < (_index = (_listener = _get(this, name)).indexOf(callback));
},
/**
* Remove a listener if added before.
* @param String a generic listener name
* @param Function callback to remove
*/
removeListener: function (name, callback) {
if (this.hasListener(name, callback)) {
_listener.splice(_index, 1);
}
}
};
}());