Skip to content

Commit

Permalink
Mediator pattern in JavaScript
Browse files Browse the repository at this point in the history
  • Loading branch information
Nicholas committed Apr 22, 2011
1 parent 09b9721 commit e9503f5
Show file tree
Hide file tree
Showing 7 changed files with 529 additions and 0 deletions.
132 changes: 132 additions & 0 deletions build/gallery-mediator/gallery-mediator-debug.js
@@ -0,0 +1,132 @@
YUI.add('gallery-mediator', function(Y) {

/*global YUI*/
/*
* Copyright (c) 2011 Yahoo! Inc. All rights reserved.
* Author: Nicholas C. Zakas, nczonline.net
*/

/**
* Mediator pattern in JavaScript. For more info on Mediator pattern:
* http://en.wikipedia.org/wiki/Mediator_pattern
* @module gallery-mediator
*/

/**
* Implementation of the mediator pattern. Purposely does not
* require Y.Event.Target to avoid confusion with regular
* event target pattern and also to keep the code as light
* and simple as possible.
* @class Mediator
* @static
*/
Y.Mediator = function(){
/**
* Array of listeners.
* @type Array
* @property _listeners
* @private
*/
this._listeners = {};
};

Y.Mediator.prototype = {

//restore constructor
constructor: Y.Mediator,

/**
* Broadcasts a message throughout the system, calling any
* registered callbacks.
* @param {String} name The name of the message to fire.
* @param {variant} data (Optional) Any additional data.
* @return {void}
* @method broadcast
*/
broadcast: function(name, data){
var i, len,
nameListeners = this._listeners[name];

if (nameListeners){
/*
* Create a clone of the array list. This handles the case where
* a callback calls listen() or unlisten() and thus alters the number of
* listeners. Using the clone ensures that the original listeners all
* get called.
*/
nameListeners = nameListeners.concat();
for (i=0, len=nameListeners.length; i < len; i++){
nameListeners[i].callback.call(nameListeners[i].scope, {
type: name,
data: data
});
}
}
},

/**
* Registers a listener for a particular message.
* @param {String} name The name of the message to listen for.
* @param {Function} callback The function to call when the message occurs.
* @param {Object} scope The value for "this" inside of the callback.
* @return {void}
* @method listen
*/
listen: function(name, callback, scope){
var listeners = this._listeners;

if (!listeners[name]){
listeners[name] = [];
}

/*
* In my experience, the #1 cause of issues with callback functions
* is that someone passes in a value that they think contains a
* function but actually doesn't. Then when something tries to call
* that function, there's an error that's hard to track down. Throwing
* an error here allows you to trap the issue at the listen() method,
* which is where the wrong value is being passed in. This improves
* debugging such issues dramatically.
*/
if (typeof callback == "function"){
listeners[name].push({
callback: callback,
scope:scope
});
} else {
throw new Error("Callback must be a function.");
}
},

/**
* Unregisters a listener for a particular message. The callback function
* and the scope must match the ones passed into listen() to be removed.
* @param {String} name The name of the message the listener was registered for.
* @param {Function} callback The function to remove.
* @param {Object} scope The value for "this" inside of the callback.
* @return {Boolean} True if the callback was removed, false if not.
* @method listen
*/
unlisten: function(name, callback, scope){
var i, len,
nameListeners = this._listeners[name],
removed = false;

if (nameListeners){
for (i=0, len=nameListeners.length; i < len; i++){
if (nameListeners[i].callback === callback && nameListeners[i].scope === scope){
nameListeners[i].splice(i, 1);
removed = true;
break;
}
}
}

return removed;
}

};



}, '@VERSION@' );
1 change: 1 addition & 0 deletions build/gallery-mediator/gallery-mediator-min.js

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

132 changes: 132 additions & 0 deletions build/gallery-mediator/gallery-mediator.js
@@ -0,0 +1,132 @@
YUI.add('gallery-mediator', function(Y) {

/*global YUI*/
/*
* Copyright (c) 2011 Yahoo! Inc. All rights reserved.
* Author: Nicholas C. Zakas, nczonline.net
*/

/**
* Mediator pattern in JavaScript. For more info on Mediator pattern:
* http://en.wikipedia.org/wiki/Mediator_pattern
* @module gallery-mediator
*/

/**
* Implementation of the mediator pattern. Purposely does not
* require Y.Event.Target to avoid confusion with regular
* event target pattern and also to keep the code as light
* and simple as possible.
* @class Mediator
* @static
*/
Y.Mediator = function(){
/**
* Array of listeners.
* @type Array
* @property _listeners
* @private
*/
this._listeners = {};
};

Y.Mediator.prototype = {

//restore constructor
constructor: Y.Mediator,

/**
* Broadcasts a message throughout the system, calling any
* registered callbacks.
* @param {String} name The name of the message to fire.
* @param {variant} data (Optional) Any additional data.
* @return {void}
* @method broadcast
*/
broadcast: function(name, data){
var i, len,
nameListeners = this._listeners[name];

if (nameListeners){
/*
* Create a clone of the array list. This handles the case where
* a callback calls listen() or unlisten() and thus alters the number of
* listeners. Using the clone ensures that the original listeners all
* get called.
*/
nameListeners = nameListeners.concat();
for (i=0, len=nameListeners.length; i < len; i++){
nameListeners[i].callback.call(nameListeners[i].scope, {
type: name,
data: data
});
}
}
},

/**
* Registers a listener for a particular message.
* @param {String} name The name of the message to listen for.
* @param {Function} callback The function to call when the message occurs.
* @param {Object} scope The value for "this" inside of the callback.
* @return {void}
* @method listen
*/
listen: function(name, callback, scope){
var listeners = this._listeners;

if (!listeners[name]){
listeners[name] = [];
}

/*
* In my experience, the #1 cause of issues with callback functions
* is that someone passes in a value that they think contains a
* function but actually doesn't. Then when something tries to call
* that function, there's an error that's hard to track down. Throwing
* an error here allows you to trap the issue at the listen() method,
* which is where the wrong value is being passed in. This improves
* debugging such issues dramatically.
*/
if (typeof callback == "function"){
listeners[name].push({
callback: callback,
scope:scope
});
} else {
throw new Error("Callback must be a function.");
}
},

/**
* Unregisters a listener for a particular message. The callback function
* and the scope must match the ones passed into listen() to be removed.
* @param {String} name The name of the message the listener was registered for.
* @param {Function} callback The function to remove.
* @param {Object} scope The value for "this" inside of the callback.
* @return {Boolean} True if the callback was removed, false if not.
* @method listen
*/
unlisten: function(name, callback, scope){
var i, len,
nameListeners = this._listeners[name],
removed = false;

if (nameListeners){
for (i=0, len=nameListeners.length; i < len; i++){
if (nameListeners[i].callback === callback && nameListeners[i].scope === scope){
nameListeners[i].splice(i, 1);
removed = true;
break;
}
}
}

return removed;
}

};



}, '@VERSION@' );
4 changes: 4 additions & 0 deletions src/gallery-mediator/build.properties
@@ -0,0 +1,4 @@
builddir=../../../builder/componentbuild
component=gallery-mediator
component.jsfiles=mediator.js

6 changes: 6 additions & 0 deletions src/gallery-mediator/build.xml
@@ -0,0 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<project name="YUI" default="local">
<property file="build.properties" />
<import file="${builddir}/3.x/bootstrap.xml"
description="Default Build Properties and Targets" />
</project>

0 comments on commit e9503f5

Please sign in to comment.