squee
Version:
Super quick event emitter!
175 lines • 6.81 kB
JavaScript
define("index", ["require", "exports"], function (require, exports) {
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
/**
* Removes any instances of an item from an array.
*
* @template TItem Types of items in the array.
* @param array Array of items.
* @param item Item to remove.
* @returns Whether any number of that item was removed.
*/
const removeFromArray = (array, item) => {
let removed = false;
for (let i = 0; i < array.length; i += 1) {
if (array[i] === item) {
removed = true;
array.splice(i, 1);
i -= 1;
}
}
return removed;
};
/**
* Creates a new, blank registration.
*
* @returns A new, blank registration.
*/
const createNewRegistration = () => ({
firstOnlyListeners: [],
listeners: [],
});
/**
* Hub for triggerable application events.
*
* @template TTypes Event names linked to their arg types.
*/
class EventEmitter {
constructor() {
/**
* Listeners to fire on all events.
*/
this.anyRegistrations = [];
/**
* Listeners and first args registered to events.
*/
this.registrations = {};
}
/**
* Binds an event listener to an event name.
*
* @param eventName Name of an event.
* @param listener Listener for the event.
*/
on(eventName, listener) {
this.safelyGetRegistration(eventName)
.listeners.push(listener);
}
/**
* Binds an event listener to the first time an event name.
*
* @param eventName Name of an event.
* @param listener Listener for the event.
* @remarks If the event name was already fired, it's immediately called with the args from the first event.
*/
onFirst(eventName, listener) {
const registration = this.safelyGetRegistration(eventName);
if (registration.firstArgs !== undefined) {
listener(...registration.firstArgs);
}
registration.firstOnlyListeners.push(listener);
}
/**
* Binds an event listener to all events.
*
* @param listener Called on any event with the event name and args.
*/
onAny(listener) {
this.anyRegistrations.push(listener);
}
/**
* Removes an event listener from an event name.
* If no listener is provided, it removes all listeners for that event name.
* If no event name is provided, it removes all listeners for all event names.
*
* @param eventName Name of an event, if not all events.
* @param listener Listener for the event, if not all listeners for the event(s).
* @remarks Throws an error if the listener wasn't added for that event name.
*/
off(eventName, listener) {
if (eventName === undefined) {
this.registrations = {};
return;
}
if (listener === undefined) {
this.registrations[eventName] = createNewRegistration();
return;
}
const registration = this.safelyGetRegistration(eventName);
const wasInListeners = removeFromArray(registration.listeners, listener);
const wasInFirstOnlyListeners = removeFromArray(registration.firstOnlyListeners, listener);
if (!wasInListeners && !wasInFirstOnlyListeners) {
throw new Error(`Tried to remove a non-existent listener for event name '${eventName}'.`);
}
}
/**
* Emits an event, along with any amount of additional information.
*
* @param eventName Name of an event.
* @param args Any additional information for the event.
*/
emit(eventName, ...args) {
const registration = this.safelyGetRegistration(eventName);
if (registration.firstArgs === undefined) {
for (const firstOnlyListener of registration.firstOnlyListeners) {
firstOnlyListener(...args);
}
registration.firstArgs = args;
registration.firstOnlyListeners = [];
}
for (const listener of registration.listeners) {
listener(...args);
}
for (const listener of this.anyRegistrations) {
listener(eventName, ...args);
}
}
/**
* Creates a Promise to be resolved the next time an event is fired.
*
* @param eventName Name of an event.
* @returns A Promise to be resolved with the first object passed with the event.
*/
waitFor(eventName) {
return new Promise((resolve) => {
const listener = (arg) => {
resolve(arg);
this.off(eventName, listener);
};
this.on(eventName, listener);
});
}
/**
* Creates a Promise to be resolved the first time an event is fired.
*
* @param eventName Name of an event.
* @returns A Promise to be resolve with the first object passed with the first event.
* @remarks If the event name was already fired, it's immediately resolved with the args from the first event.
*/
waitForFirst(eventName) {
return new Promise((resolve) => {
const listener = (arg) => {
resolve(arg);
this.off(eventName, listener);
};
this.onFirst(eventName, listener);
});
}
/**
* Ensures the registrations object for an event exists.
*
* @param eventName Name of an event.
* @returns Registrations for the event.
*/
safelyGetRegistration(eventName) {
if (this.registrations[eventName] === undefined) {
this.registrations[eventName] = createNewRegistration();
}
// See https://github.com/Microsoft/TypeScript/issues/10530
return this.registrations[eventName];
}
}
exports.EventEmitter = EventEmitter;
exports.Squee = EventEmitter;
});
//# sourceMappingURL=squee-amd-es2015.js.map