Skip to content
This repository has been archived by the owner on Nov 3, 2021. It is now read-only.

Commit

Permalink
Merge pull request #21828 from azasypkin/bug-1039585-event-dispatcher
Browse files Browse the repository at this point in the history
Bug 1039585 - [Messages][Refactoring] Implement EventDispatcher object. r=julien
Conflicts:
	apps/sms/index.html
  • Loading branch information
azasypkin authored and rvandermeulen committed Jul 29, 2014
1 parent 5a3b33d commit 28a8c9a
Show file tree
Hide file tree
Showing 3 changed files with 556 additions and 0 deletions.
1 change: 1 addition & 0 deletions apps/sms/index.html
Expand Up @@ -45,6 +45,7 @@
<script defer src="shared/js/settings_listener.js"></script>
<script defer src="shared/js/sim_picker.js"></script>
<script defer src="shared/js/multi_sim_action_button.js"></script>
<script defer src="js/event_dispatcher.js"></script>
<script defer src="js/navigation.js"></script>
<script defer src="js/dialog.js"></script>
<script defer src="js/task_runner.js"></script>
Expand Down
151 changes: 151 additions & 0 deletions apps/sms/js/event_dispatcher.js
@@ -0,0 +1,151 @@
/*global Map, Set */

/* exported EventDispatcher */

(function(exports) {
'use strict';

function ensureValidEventName(eventName) {
if (!eventName || typeof eventName !== 'string') {
throw new Error('Event name should be a valid non-empty string!');
}
}

function ensureValidHandler(handler) {
if (typeof handler !== 'function') {
throw new Error('Handler should be a function!');
}
}

function ensureAllowedEventName(allowedEvents, eventName) {
if (allowedEvents && allowedEvents.indexOf(eventName) < 0) {
throw new Error('Event "' + eventName + '" is not allowed!');
}
}

// Implements publish/subscribe behaviour that can be applied to any object,
// so that object can be listened for custom events. "this" context is the
// object with Map "listeners" property used to store handlers.
var eventDispatcher = {
/**
* Registers listener function to be executed once event occurs.
* @param {string} eventName Name of the event to listen for.
* @param {function} handler Handler to be executed once event occurs.
*/
on: function(eventName, handler) {
ensureValidEventName(eventName);
ensureAllowedEventName(this.allowedEvents, eventName);
ensureValidHandler(handler);

var handlers = this.listeners.get(eventName);

if (!handlers) {
handlers = new Set();
this.listeners.set(eventName, handlers);
}

// Set.add ignores handler if it has been already registered
handlers.add(handler);
},

/**
* Removes registered listener for the specified event.
* @param {string} eventName Name of the event to remove listener for.
* @param {function} handler Handler to remove, so it won't be executed
* next time event occurs.
*/
off: function(eventName, handler) {
ensureValidEventName(eventName);
ensureAllowedEventName(this.allowedEvents, eventName);
ensureValidHandler(handler);

var handlers = this.listeners.get(eventName);

if (!handlers) {
return;
}

handlers.delete(handler);

if (!handlers.size) {
this.listeners.delete(eventName);
}
},

/**
* Removes all registered listeners for the specified event.
* @param {string} eventName Name of the event to remove all listeners for.
*/
offAll: function(eventName) {
ensureValidEventName(eventName);
ensureAllowedEventName(this.allowedEvents, eventName);

var handlers = this.listeners.get(eventName);

if (!handlers) {
return;
}

handlers.clear();

this.listeners.delete(eventName);
},

/**
* Emits specified event so that all registered handlers will be called
* with the specified parameters.
* @param {string} eventName Name of the event to call handlers for.
* @param {Object} parameters Optional parameters that will be passed to
* every registered handler.
*/
emit: function(eventName, parameters) {
ensureValidEventName(eventName);
ensureAllowedEventName(this.allowedEvents, eventName);

var handlers = this.listeners.get(eventName);

if (!handlers) {
return;
}

handlers.forEach(function(handler) {
try {
handler(parameters);
} catch (e) {
console.error(e);
}
});
}
};

exports.EventDispatcher = {
/**
* Mixes dispatcher methods into target object.
* @param {Object} target Object to mix dispatcher methods into.
* @param {Array.<string>} allowedEvents Optional list of the allowed event
* names that can be emitted and listened for.
* @returns {Object} Target object with added dispatcher methods.
*/
mixin: function(target, allowedEvents) {
if (!target || typeof target !== 'object') {
throw new Error('Object to mix into should be valid object!');
}

if (typeof allowedEvents !== 'undefined' &&
!Array.isArray(allowedEvents)) {
throw new Error('Allowed events should be a valid array of strings!');
}

Object.keys(eventDispatcher).forEach(function(method) {
if (typeof target[method] !== 'undefined') {
throw new Error(
'Object to mix into already has "' + method + '" property defined!'
);
}
target[method] = eventDispatcher[method].bind(this);
}, { listeners: new Map(), allowedEvents: allowedEvents });

return target;
}
};
})(window);

0 comments on commit 28a8c9a

Please sign in to comment.