File: lib/events.js
/*
* niViz -- snow profiles visualization
* Copyright (C) 2015 WSL/SLF - Fluelastrasse 11 - 7260 Davos Dorf - Switzerland.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
(function (niviz) {
'use strict';
var util = niviz.util;
var assert = util.assert;
/** @module niviz */
/**
* Any object can mix-in or inherit from the
* EventEmitter prototype.
*
* @example
* var inherits = niviz.util.inherits;
* var EventEmitter = niviz.EventEmitter;
*
* function MyEventEmitter() {
* EventEmitter.call(this);
* }
*
* inherits(MyEventEmitter, EventEmitter);
*
* @class EventEmitter
* @constructor
*/
function EventEmitter() {
/**
* @property events
* @type Object
* @private
*/
this.events = {};
}
/**
* Registers a new handler for an event.
*
* @method on
* @chainable
*
* @param {String} type The event type.
* @param {Function} listener The listener.
*/
EventEmitter.prototype.on = function (type, listener) {
assert(typeof type === 'string');
assert(typeof listener === 'function');
(this.events[type] = this.events[type] || []).push(listener);
return this;
};
/**
* Registers a new handler for an event
* that will be executed at most once.
*
* @method once
* @chainable
*
* @param {String} type The event type.
* @param {Function} listener The listener.
*/
EventEmitter.prototype.once = function (type, listener) {
assert(typeof type === 'string');
assert(typeof listener === 'function');
var self = this;
function proxy() {
self.off(type, proxy);
return listener.apply(this, arguments);
}
proxy.listener = listener;
return this.on(type, proxy);
};
/**
* Removes a given event listener. If no listener
* is given, removes all listeners for the given
* type; if no type is given, removes all listeners.
*
* @method off
* @chainable
*
* @param {String} [type] The event type.
* @param {Function} [listener] The listener.
*/
EventEmitter.prototype.off = function (type, listener) {
switch (arguments.length) {
case 0:
this.events = {};
break;
case 1:
assert(typeof type === 'string');
delete this.events[type];
break;
default:
assert(typeof type === 'string');
assert(typeof listener === 'function');
var i, ii, cb;
if ((cb = this.events[type])) {
for (i = 0, ii = cb.length; i < ii; ++i) {
if (cb[i] === listener || cb[i].listener === listener) {
cb.splice(i, 1);
}
}
}
}
return this;
};
/**
* Fires event type, executing all registered
* handlers synchronously.
*
* @method emit
* @returns {Boolean} True if there were listeners;
* false otherwise;
*/
EventEmitter.prototype.emit = function (type) {
assert(typeof type === 'string');
var listeners = this.listeners(type);
if (type === 'error' && !listeners.length) {
var error = arguments[1];
if (error instanceof Error) throw error;
throw new Error('uncaught "error" event');
}
if (!listeners.length) return false;
var args = Array.prototype.slice.call(arguments, 1);
var i, ii;
// Make a defensive copy in case events
// register other events!
listeners = listeners.slice();
for (i = 0, ii = listeners.length; i < ii; ++i)
listeners[i].apply(this, args);
return true;
};
/**
* Returns all listeners for the given event type.
*
* @method listeners
* @returns {Array<Function>} All listeners for type.
*/
EventEmitter.prototype.listeners = function (type) {
return this.events[type] || [];
};
/**
* Registers a callback function to be called
* by the `end` or `error` events, like a Node
* callback would be called.
*
* @method nodeback
* @chainable
* @private
*
* @param {Function} callback The callback to register.
*/
EventEmitter.prototype.nodeback = function (callback) {
return this
.once('end', function (result) {
callback.apply(this, [null, result]);
})
.once('error', function (error) {
callback.apply(this, [error]);
});
};
// --- Module Exports ---
niviz.EventEmitter = EventEmitter;
}(niviz));