Created
July 30, 2012 19:13
-
-
Save bripkens/3209266 to your computer and use it in GitHub Desktop.
Observable changes for class-level events
This file contains 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
(function(bui) { | |
var identifier = 'bui.Observable'; | |
/** | |
* @class | |
* By inheriting from this class you can allow observers. Please note | |
* that you have to add types using the {@link bui.Observable#addType} | |
* function before listener can be added. | |
* | |
* @extends bui.Object | |
*/ | |
bui.Observable = function() { | |
bui.Observable.superClazz.call(this); | |
this._getPrivateMembers(identifier).listener = {}; | |
}; | |
/* | |
* It is okay to bind listeners to one object as every listener type is | |
* identified by a distinct global id (see bui.Node.ListenerType et al.) | |
* | |
* The data structure is as follows: | |
* { <-- classLevelObserver | |
* type : { | |
* identification: callback | |
* } | |
* } | |
*/ | |
var classLevelObserver = {}; | |
var getClassLevelObserver = function(type) { | |
return classLevelObserver[type] = classLevelObserver[type] || {}; | |
}; | |
bui.Observable.bindClassLevel = function(type, callback, identification) { | |
var observer = getClassLevelObserver(type); | |
if (identification === undefined || identification === null) { | |
identification = callback; | |
} | |
observer[identification] = callback; | |
}; | |
bui.Observable.prototype = { | |
/** | |
* @description | |
* Add a listener type to this observable object. An added listener | |
* type allows to register listeners and fire events specific to | |
* this type. | |
* | |
* @param {String|Object} type The new type - a string which describes | |
* it or an object (map) for which all values | |
* (please note it's values - not keys) are used and added as types. | |
* @return {bui.Observable} Fluent interface | |
*/ | |
_addType : function(type) { | |
var listener = this._getPrivateMembers(identifier).listener; | |
if (typeof(type) === 'string') { | |
listener[type] = {}; | |
} else { | |
for (var i in type) { | |
if (type.hasOwnProperty(i)) { | |
listener[type[i]] = {}; | |
} | |
} | |
} | |
return this; | |
}, | |
/** | |
* @description | |
* Bind listener to a specific type | |
* | |
* @param {String} type The type of event that should be observed | |
* @param {Function} callback Method to be called | |
* @param {Object} [identification] An identifier used to identify the | |
* listener in the list of all over listeners. Should be unique for | |
* the listener type. When ommited the callback will be used for | |
* identification purposes. | |
* @return {bui.Observable} Fluent interface | |
*/ | |
bind : function(type, callback, identification) { | |
var listener = this._getPrivateMembers(identifier).listener[type]; | |
// type not registered, fail silently | |
if (listener === undefined) { | |
return this; | |
} | |
if (identification === undefined || identification === null) { | |
identification = callback; | |
} | |
listener[identification] = callback; | |
return this; | |
}, | |
/** | |
* @description | |
* Unbind a listener from a specific event. | |
* | |
* To unbind all listener, call this function without any parameter. | |
* To unbind all listener just for a specific type call this method | |
* with the type and omit the identification. | |
* | |
* @param {String} [type] listener type identification | |
* @param {String} [identification] identifies the listener which | |
* should be unbound | |
* @return {bui.Observable} Fluent interface | |
*/ | |
unbind : function(type, identification) { | |
var listener = this._getPrivateMembers(identifier).listener; | |
if (type === undefined) { | |
for(var registeredType in listener) { | |
if (listener.hasOwnProperty(registeredType)) { | |
listener[registeredType] = {}; | |
} | |
} | |
} else if (identification === undefined) { | |
listener[type] = {}; | |
} else { | |
delete listener[type][identification]; | |
} | |
return this; | |
}, | |
/** | |
* Unbind all listeners with the provided identification. | |
* | |
* @param {String} identification Listener identification | |
* @return {bui.Observable} Fluent interface | |
*/ | |
unbindAll : function(identification) { | |
var listener = this._getPrivateMembers(identifier).listener; | |
for(var type in listener) { | |
if (listener.hasOwnProperty(type)) { | |
delete listener[type][identification]; | |
} | |
} | |
return this; | |
}, | |
/** | |
* @description | |
* Fire an event | |
* | |
* @param {String} type listener type identification | |
* @param {Object[]} [params] Parameters to be passed to the listener | |
* @return {Boolean} True when every listener returned a value !== | |
* false, false otherwise. | |
*/ | |
fire : function(type, params) { | |
if (params === undefined) { | |
params = []; | |
} | |
var listener = this._getPrivateMembers(identifier).listener[type]; | |
// fail silently when the listener type is not registered | |
if (listener === undefined) { | |
return true; | |
} | |
for (var i in listener) { | |
if (listener.hasOwnProperty(i)) { | |
var status = listener[i].apply(this, params); | |
if (status === false) { | |
return false; | |
} | |
} | |
} | |
var classLevelObserver = getClassLevelObserver(type); | |
for (var i in classLevelObserver) { | |
if (classLevelObserver.hasOwnProperty(i)) { | |
// TODO join [this] and the params array, so that | |
// the first parameter is guaranteed to be the | |
// event source. | |
var status = classLevelObserver[i].apply(this, params); | |
if (status === false) { | |
return false; | |
} | |
} | |
} | |
return true; | |
} | |
}; | |
bui.util.setSuperClass(bui.Observable, bui.Object); | |
})(bui); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment