/** * Create an event emitter with namespaces * @name createNamespaceEmitter * @example * var emitter = require('./index')() * * emitter.on('*', function () { * console.log('all events emitted', this.event) * }) * * emitter.on('example', function () { * console.log('example event emitted') * }) */ module.exports = function createNamespaceEmitter () { var emitter = {} var _fns = emitter._fns = {} /** * Emit an event. Optionally namespace the event. Handlers are fired in the order in which they were added with exact matches taking precedence. Separate the namespace and event with a `:` * @name emit * @param {String} event – the name of the event, with optional namespace * @param {...*} data – up to 6 arguments that are passed to the event listener * @example * emitter.emit('example') * emitter.emit('demo:test') * emitter.emit('data', { example: true}, 'a string', 1) */ emitter.emit = function emit (event, arg1, arg2, arg3, arg4, arg5, arg6) { var toEmit = getListeners(event) if (toEmit.length) { emitAll(event, toEmit, [arg1, arg2, arg3, arg4, arg5, arg6]) } } /** * Create en event listener. * @name on * @param {String} event * @param {Function} fn * @example * emitter.on('example', function () {}) * emitter.on('demo', function () {}) */ emitter.on = function on (event, fn) { if (!_fns[event]) { _fns[event] = [] } _fns[event].push(fn) } /** * Create en event listener that fires once. * @name once * @param {String} event * @param {Function} fn * @example * emitter.once('example', function () {}) * emitter.once('demo', function () {}) */ emitter.once = function once (event, fn) { function one () { fn.apply(this, arguments) emitter.off(event, one) } this.on(event, one) } /** * Stop listening to an event. Stop all listeners on an event by only passing the event name. Stop a single listener by passing that event handler as a callback. * You must be explicit about what will be unsubscribed: `emitter.off('demo')` will unsubscribe an `emitter.on('demo')` listener, * `emitter.off('demo:example')` will unsubscribe an `emitter.on('demo:example')` listener * @name off * @param {String} event * @param {Function} [fn] – the specific handler * @example * emitter.off('example') * emitter.off('demo', function () {}) */ emitter.off = function off (event, fn) { var keep = [] if (event && fn) { var fns = this._fns[event] var i = 0 var l = fns ? fns.length : 0 for (i; i < l; i++) { if (fns[i] !== fn) { keep.push(fns[i]) } } } keep.length ? this._fns[event] = keep : delete this._fns[event] } function getListeners (e) { var out = _fns[e] ? _fns[e] : [] var idx = e.indexOf(':') var args = (idx === -1) ? [e] : [e.substring(0, idx), e.substring(idx + 1)] var keys = Object.keys(_fns) var i = 0 var l = keys.length for (i; i < l; i++) { var key = keys[i] if (key === '*') { out = out.concat(_fns[key]) } if (args.length === 2 && args[0] === key) { out = out.concat(_fns[key]) break } } return out } function emitAll (e, fns, args) { var i = 0 var l = fns.length for (i; i < l; i++) { if (!fns[i]) break fns[i].event = e fns[i].apply(fns[i], args) } } return emitter }