151 lines
5.4 KiB
JavaScript
151 lines
5.4 KiB
JavaScript
mimicry.module([
|
|
"./base"
|
|
], function emitterModule(global, [Base]) {
|
|
class Emitter extends Base {
|
|
constructor () {
|
|
super();
|
|
|
|
this._events = Object.create(null);
|
|
this._accumulatedEvents = Object.create(null);
|
|
}
|
|
destructor () {
|
|
this.off();
|
|
|
|
super.destructor();
|
|
}
|
|
/**
|
|
* Subscribes to event
|
|
*
|
|
* @param {String} name - name of the event you want to subscribe
|
|
* @param {Function} handler - a handler you want to perform on the event
|
|
* @param {Object} [context] - a context you want to perform your handler with
|
|
* */
|
|
on (name, handler, context) {
|
|
let handlers = this._events[name];
|
|
|
|
if (typeof name !== "string")
|
|
throw new Error("Name of event is mandatory");
|
|
|
|
if (!(handler instanceof Function))
|
|
throw new Error("Handler of event is mandatory");
|
|
|
|
if (!handlers) {
|
|
handlers = [];
|
|
this._events[name] = handlers;
|
|
}
|
|
|
|
handlers.push({
|
|
handler: handler,
|
|
context: context || this,
|
|
once: false
|
|
});
|
|
}
|
|
/**
|
|
* Subscribes to event, but the handler is called only once
|
|
*
|
|
* @param {String} name - name of the event you want to subscribe
|
|
* @param {Function} handler - a handler you want to perform on the event
|
|
* @param {Object} [context] - a context you want to perform your handler with
|
|
* */
|
|
one (name, handler, context) {
|
|
this.on(name, handler, context);
|
|
this._events[name][this._events[name].length - 1].once = true;
|
|
}
|
|
/**
|
|
* Unsubscribes from event
|
|
*
|
|
* @param {String} [name] - name of the event you want to unsubscribe from.
|
|
* If not passed unsubscribes every subscribed handler from all events
|
|
* @param {Function} [handler] - a handler you want to unsubscribe.
|
|
* If not passed unsubscribes all handlers from event defined by "name" parameter
|
|
* @param {Object} [context] - a context you want to unsubscribe.
|
|
* If not passed unsubscribes all matching handlers from
|
|
* event defined by "name" parameter.
|
|
* */
|
|
off (name, handler, context) {
|
|
if (typeof name !== "string") {
|
|
this._events = {};
|
|
return;
|
|
}
|
|
|
|
if (!this._events[name])
|
|
return;
|
|
|
|
if (!(handler instanceof Function)) {
|
|
delete this._events[name];
|
|
return;
|
|
}
|
|
|
|
const handlers = this._events[name];
|
|
for (let i = handlers.length - 1; i >= 0; --i) {
|
|
if (handlers[i].handler === handler) {
|
|
if (context || context === null) {
|
|
if (handlers[i].context === context)
|
|
handlers.splice(i, 1);
|
|
} else {
|
|
handlers.splice(i, 1);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
/**
|
|
* Emits event name with given parameters
|
|
*
|
|
* @param {String} name - name of the emitting event
|
|
* @param {...Array} [params] - list of parameters separated by comma
|
|
* */
|
|
emit (...[name, ...params]) {
|
|
if (this._accumulatedEvents[name]) {
|
|
this._accumulatedEvents[name] = params;
|
|
return;
|
|
}
|
|
const handlers = this._events[name];
|
|
if (!handlers)
|
|
return;
|
|
|
|
for (let i = 0; i < handlers.length; ++i) {
|
|
const handle = handlers[i];
|
|
handle.handler.apply(handle.context, params);
|
|
if (handle.once)
|
|
handlers.splice(i--, 1);
|
|
}
|
|
}
|
|
/**
|
|
* Counts how many handlers are subscribed to given event name
|
|
*
|
|
* @param {String} name - name of the event
|
|
*
|
|
* @returns {Number} - how many handlers are subscribed to given event
|
|
* */
|
|
countHandlers (name) {
|
|
return this._events[name] && this._events[name].length || 0;
|
|
}
|
|
/**
|
|
* You can call this method and emit(name) will stop notifying subscribers
|
|
* It will keep the last event parameters event was called with instead
|
|
* This way you can avoid multiple notifications of the same event
|
|
*
|
|
* @param {String} name - event name
|
|
* */
|
|
accumulateEvent (name) {
|
|
this._accumulatedEvents[name] = true;
|
|
}
|
|
/**
|
|
* This method stops accumulation of the event and emits it
|
|
* if there were emissions during accumulation period
|
|
* If there were several emissions - event is emitted with the last set of parameters
|
|
*
|
|
* @param {String} name - event name
|
|
* */
|
|
releaseEvent (name) {
|
|
const params = this._accumulatedEvents[name];
|
|
delete this._accumulatedEvents[name];
|
|
if (params instanceof Array) {
|
|
params.unshift(name);
|
|
this.emit.apply(this, params);
|
|
}
|
|
}
|
|
}
|
|
|
|
return Emitter;
|
|
}); |