import { TypeVoidFunction } from '../types/voidFunction';
import { noop } from '../functions';
import { IEvent } from './types';
/**
* EventEmitter 의 기능과 동일한 맥락으로, 간단히 구성
<iframe
src="https://codesandbox.io/embed/nonollcode-snippet-9gko8?autoresize=1&expanddevtools=1&fontsize=14&hidenavigation=1&initialpath=%2Fevent-EventEmitter.html&module=%2Fevent-EventEmitter.html&theme=dark"
style="width:100%; height:500px; border:1px solid black; border-radius: 4px; overflow:hidden;"
title="@nonoll/code-snippet"
allow="geolocation; microphone; camera; midi; vr; accelerometer; gyroscope; payment; ambient-light-sensor; encrypted-media; usb"
sandbox="allow-modals allow-forms allow-popups allow-scripts allow-same-origin"
></iframe>
* @export
* @class EventEmitter
* @alias event/EventEmitter
* @memberof event
* @see https://www.npmjs.com/package/events
* @example
import { EventEmitter } from '@nonoll/code-snippet/event';
const createElement = ({ tag = 'div', id = '', style = '', value = '', text = '' }) => {
const doc = window.document;
const target = doc.createElement(tag);
target.setAttribute('id', id);
target.setAttribute('style', style);
target.setAttribute('value', value);
if (text) {
target.textContent = text;
}
return target;
}
let ee;
const forExample = () => {
const doc = window.document;
const onButton = createElement({ tag: 'button', text: 'on button' });
const offButton = createElement({ tag: 'button', text: 'off button' });
const emitButton = createElement({ tag: 'button', text: 'emit button' });
const EVENT_NAME = 'EVENT_EXAMPLE';
doc.body.appendChild(onButton);
doc.body.appendChild(offButton);
doc.body.appendChild(emitButton);
ee = new EventEmitter();
ee.on(EVENT_NAME, res => console.log(res));
onButton.addEventListener('click', e => {
e.preventDefault();
console.log('onButton clicked');
if (!ee) {
return;
}
ee.off(EVENT_NAME);
ee.on(EVENT_NAME, res => console.log(res));
});
offButton.addEventListener('click', e => {
e.preventDefault();
console.log('offButton clicked');
if (!ee) {
return;
}
ee.off(EVENT_NAME);
});
emitButton.addEventListener('click', e => {
e.preventDefault();
console.log('emitButton clicked');
if (!ee) {
return;
}
ee.emit(EVENT_NAME, new Date());
});
}
forExample();
*/
export class EventEmitter {
private events: Array<IEvent> = [];
constructor() {}
/**
* 이벤트 감지 등록
* @param {string} eventName
* @param {TypeVoidFunction} [listener={@link noop}]
* @param {*} [context]
* @returns {EventEmitter}
* @memberof EventEmitter
*/
on(eventName: string, /* istanbul ignore next: for noop */ listener: TypeVoidFunction = noop, context?: any): EventEmitter {
this.events.push({ eventName, listener, context });
return this;
}
/**
* 이벤트 감지 해제
* @param {string} eventName
* @param {TypeVoidFunction} [listener]
* @returns {EventEmitter}
* @memberof EventEmitter
*/
off(eventName: string, listener?: TypeVoidFunction): EventEmitter | false {
// tslint:disable-next-line: max-line-length
const matched = this.events.findIndex(regEvent => regEvent.eventName === eventName && (listener ? regEvent.listener === listener : true));
// tslint:disable-next-line: no-bitwise
if (!~matched) {
return false;
}
this.events.splice(matched, 1);
return this;
}
/**
* 이벤트 1회 감지 등록
* @param {string} eventName
* @param {TypeVoidFunction} [listener={@link noop}]
* @param {*} [context]
* @returns {EventEmitter}
* @memberof EventEmitter
*/
once(eventName: string, /* istanbul ignore next: for noop */ listener: TypeVoidFunction = noop, context?: any): EventEmitter {
const onceWrapper = (...values: any) => {
this.off(eventName, onceWrapper);
listener.apply(context || listener, values);
};
this.on(eventName, onceWrapper, context);
return this;
}
/**
* 이벤트 전파
* @param {string} eventName
* @param {...any[]} values
* @returns {EventEmitter}
* @memberof EventEmitter
*/
emit(eventName: string, ...values: any[]): EventEmitter {
this.events.forEach(regEvent => {
if (regEvent.eventName === eventName) {
regEvent.listener.apply(regEvent.context || regEvent.listener, values);
}
});
return this;
}
/**
* 이벤트 전파
* @param {string} eventName
* @param {any} values
* @returns {EventEmitter}
* @memberof EventEmitter
*/
fire(eventName: string, values: any): EventEmitter {
this.emit(eventName, values);
return this;
}
}