125 lines
3.1 KiB
JavaScript
125 lines
3.1 KiB
JavaScript
function createListener(fn, that, type, once) {
|
|
return {
|
|
fn, that, type, once,
|
|
bound: that ? fn.bind(that) : fn,
|
|
}
|
|
}
|
|
|
|
export function EventEmitterMixin(Superclass) {
|
|
|
|
return class EventEmitter extends Superclass {
|
|
|
|
constructor(...args) {
|
|
super(...args);
|
|
this.$$events = Object.create(null);
|
|
}
|
|
|
|
addListener(typesOrType, fn, that) {
|
|
return this.on(typesOrType, fn, that);
|
|
}
|
|
|
|
// Notify ALL the listeners!
|
|
emit(type, ...args) {
|
|
const typeListeners = this.$$events[type];
|
|
if (typeListeners && typeListeners.length > 0) {
|
|
this.emitToListeners(typeListeners, args);
|
|
}
|
|
}
|
|
|
|
emitToListeners(listeners, args) {
|
|
for (let i = 0; i < listeners.length; ++i) {
|
|
const {once, type, fn, bound, that} = listeners[i];
|
|
// Remove if only once.
|
|
if (once) {
|
|
this.offSingleEvent(type, fn);
|
|
}
|
|
// Fast path...
|
|
if (0 === args.length) {
|
|
bound()
|
|
}
|
|
else if (1 === args.length) {
|
|
bound(args[0]);
|
|
}
|
|
else if (2 === args.length) {
|
|
bound(args[0], args[1]);
|
|
}
|
|
else if (3 === args.length) {
|
|
bound(args[0], args[1], args[2]);
|
|
}
|
|
else if (4 === args.length) {
|
|
bound(args[0], args[1], args[2], args[3]);
|
|
}
|
|
else if (5 === args.length) {
|
|
bound(args[0], args[1], args[2], args[3], args[4]);
|
|
}
|
|
// Slow path...
|
|
else {
|
|
fn.apply(that, args);
|
|
}
|
|
}
|
|
}
|
|
|
|
off(typesOrType, fn) {
|
|
typesOrType = Array.isArray(typesOrType) ? typesOrType : [typesOrType];
|
|
for (let i = 0; i < typesOrType.length; i++) {
|
|
const type = typesOrType[i];
|
|
this.offSingleEvent(type, fn);
|
|
}
|
|
return this;
|
|
}
|
|
|
|
offSingleEvent(type, fn) {
|
|
if ('function' !== typeof fn) {
|
|
// Only type.
|
|
if (type in this.$$events) {
|
|
delete this.$$events[type];
|
|
}
|
|
return;
|
|
}
|
|
// Function.
|
|
const lists = [];
|
|
if ((type in this.$$events)) {
|
|
lists.push(this.$$events);
|
|
}
|
|
const listeners = this.$$events;
|
|
listeners[type] = listeners[type].filter((listener) => {
|
|
return listener.fn !== fn;
|
|
});
|
|
if (0 === listeners[type].length) {
|
|
delete listeners[type];
|
|
}
|
|
}
|
|
|
|
on(typesOrType, fn, that = undefined) {
|
|
this._on(typesOrType, fn, that, false);
|
|
return this;
|
|
}
|
|
|
|
_on(typesOrType, fn, that, once) {
|
|
typesOrType = Array.isArray(typesOrType) ? typesOrType : [typesOrType];
|
|
for (let i = 0; i < typesOrType.length; i++) {
|
|
const type = typesOrType[i];
|
|
this.onSingleEvent(type, fn, that, once);
|
|
}
|
|
}
|
|
|
|
once(types, fn, that = undefined) {
|
|
this._on(types, fn, that, true);
|
|
return this;
|
|
}
|
|
|
|
onSingleEvent(type, fn, that, once) {
|
|
const listener = createListener(fn, that, type, once);
|
|
if (!(type in this.$$events)) {
|
|
this.$$events[type] = [];
|
|
}
|
|
this.$$events[type].push(listener);
|
|
}
|
|
|
|
removeListener(...args) {
|
|
return this.off(...args);
|
|
}
|
|
|
|
}
|
|
}
|