Skip to content

Instantly share code, notes, and snippets.

@davejohnson
Created July 14, 2010 17:59
Show Gist options
  • Save davejohnson/475767 to your computer and use it in GitHub Desktop.
Save davejohnson/475767 to your computer and use it in GitHub Desktop.
/**
* Creates an event object.
* @class ChannelChannel class is used for attaching
* event handlers to JavaScript objects.
* <pre class="code">
* &#102;unction handleEvent(eventArgs) {
* // Do something with the event arguments...
* }
*
* var onItemSelected = new Channel();
* onItemSelected.subscribe(handleEvent);
*
* // When the item is selected, fire the event.
* onItemSelected.notify(eventArgs = {arg1: 'val1', arg2: 'val2'});
* </pre>
* @constructor
* @param {String} [type] The type of event, e.g., "click", "mouseover" etc. Does not affect the behaviour of the
* event object.
*/
var Channel = function(type)
{
this.type = type;
this.handlers = {};
this.guid = 0;
this.fired = false;
this.enabled = true;
}
/**
* Subscribes a method with a given context to the event.
* @example
* var onClick = new Channel();
* onClick.subscribe(myClickHandlerFunction);
* @param {Function} method The event handler to be executed when the event is fired.
* @param {Object} [context] The JavaScript object in the context of which the event handler is to be executed.
* @param {String} [guid] A custom GUID. Must be unique.
* @return The unique ID of the subscription - it can be used for unsubscription.
* @type Number
*/
Channel.prototype.subscribe = function(method, context, guid)
{
if (method == null)
return;
var func = method;
if (typeof context == "object" && method instanceof Function)
func = Channel.close(context, method);
guid = guid || func.observer_guid || method.observer_guid || this.guid++;
func.observer_guid = method.observer_guid = guid;
this.handlers[guid] = func;
return guid;
}
/**
* Subscribes a method to the event so that it will fire only once. When method
* is executed (on an event notification) it is immediately unsubscribed.
* @param {Function} method The event handler to be executed when the event is fired.
* @param {Object} context The JavaScript object in the context of which the event handler is to be executed. Optional.
* @return The unique ID of the subscription - it can be used for unsubscription.
* @type Number
*/
Channel.prototype.subscribeOnce = function(method, context)
{
var guid = null;
var _this = this;
var func1 = function() {
method.apply(context || null, arguments);
_this.unSubscribe(guid);
}
guid = this.subscribe(func1);
return guid;
}
/**
* Unsubscribes a method from an event.
* @param {Number|Function} guid The ID of the subscription to remove or the function to unsubscribe.
*/
Channel.prototype.unSubscribe = function(guid) {
if (guid instanceof Function)
guid = guid.observer_guid;
this.handlers[guid] = null;
delete this.handlers[guid];
}
/**
* Executes all the event handlers that have been subscribed to this event.
* Event handlers should return boolean values.
* @param {Object} evtArgs Arbitrary event arguments that are passed to the event handler functions.
* @type Boolean
*/
Channel.prototype.notify = function(evtArgs) {
if (this.enabled) {
if (arguments.length == 0) {
arguments = new Array();
arguments[0] = {};
arguments[0].event = this;
arguments[0].source = null;
} else if (typeof(arguments[0].event) != "undefined" && arguments[0].event == null) {
arguments[0].event = this;
}
var fail = false;
for (var item in this.handlers) {
var handler = this.handlers[item];
if (handler instanceof Function) {
var rv = (handler.apply(this, arguments)==false);
fail = fail || rv;
}
}
this.fired = true;
return !fail;
}
return true;
}
Channel.merge = function(handler, events) {
var i = events.length;
var f = function() {
if (!(--i)) handler();
}
for (var j=0; j<i; j++) {
var e = events[j];
(!e.fired?e.subscribeOnce(f):i--);
}
if (!i) handler();
}
Channel.close = function(context, func, params) {
if (null == params)
return function() {
return func.apply(context, arguments);
}
else
return function() {
return func.apply(context, params);
}
}
//====================
// Example usage...
var foo = new Channel();
var bar = new Channel();
Channel.merge(function() {alert('foobar!');}, [foo, bar]);
foo.notify(); // noting happens
bar.notify(); // alert('foobar!');
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment