///
import utils = require('./Utils');
import log = require('./Log');
import context = require('./Context');
/**
* @see https://github.com/Microsoft/TypeScript/issues/275
*/
export class Observable> {
protected context:context.Context;
protected utils:utils.Utils;
protected log:log.Log;
private listeners:any;
private oneTimeEvents:any;
private oneTimeArguments:any;
constructor(context:context.Context) {
if (!(this instanceof Observable)) throw new Error('Observable(): New operator was omitted');
Object.defineProperty(this, 'listeners', {value: {}, enumerable: false, writable: true});
Object.defineProperty(this, 'oneTimeEvents', {value: {}, enumerable: false, writable: true});
Object.defineProperty(this, 'oneTimeArguments', {value: {}, enumerable: false, writable: true});
this.context = context;
this.utils = utils.$get(context);
this.log = log.$get(context);
}
hasListeners(event) {
return (event in this.listeners);
}
/**
* @deprecated
* @param {string} event
*/
registerOneTimeEvent(event:string) {
this.oneTimeEvents[event] = false;
this.oneTimeArguments[event] = [];
}
on(events:any, callback:(...args)=>any):T {
if (typeof events == 'string') events = [events];
if (!events) throw new Error('No events to subscribe to');
if (typeof callback !== 'function') throw new Error('Callback must be a function');
var self = this;
(events).forEach((event) => {
if (!self.hasListeners(event)) self.listeners[event] = [];
self.listeners[event].push(callback);
if (self.isOneTimeEventFired(event)) { // Fire listener immediately if is inited already
this.log.debug('Observable.on(%s): One-time event has been fired already, executing callback', event);
callback.apply(self, self.getOneTimeEventArgumens(event));
}
});
return this;
}
emit(event:string, ...args):any {
if (this.isOneTimeEventFired(event)) {
this.log.debug('Observable.emit(%s): One-time event has been fired already', event);
return null;
}
var result = null;
if (this.isOneTimeEvent(event)) {
this.setOneTimeEventFired(event);
this.setOneTimeEventArgumens(event, args);
}
if (!this.hasListeners(event)) return null;
this.listeners[event].some((callback:()=>any) => {
result = callback.apply(this, args);
return (result === false);
});
return result;
}
off(event?:string, callback?):T {
if (!event) {
this.listeners = {};
this.oneTimeEvents = {};
this.oneTimeArguments = {};
} else {
if (!callback) {
delete this.listeners[event];
} else {
if (!this.hasListeners(event)) return this;
this.listeners[event].forEach((cb, i) => {
if (cb === callback) delete this.listeners[event][i];
});
}
}
return this;
}
/**
* @deprecated
* @param event
* @returns {boolean}
*/
isOneTimeEvent(event:string) {
return (event in this.oneTimeEvents);
}
/**
* @deprecated
* @param {string} event
* @returns {boolean}
*/
isOneTimeEventFired(event:string):boolean {
if (!this.isOneTimeEvent(event)) return false;
return (this.oneTimeEvents[event]);
}
/**
* @deprecated
* @param event
*/
setOneTimeEventFired(event) {
this.oneTimeEvents[event] = true;
}
/**
* @deprecated
* @param {string} event
* @param args
*/
setOneTimeEventArgumens(event:string, args) {
this.oneTimeArguments[event] = args;
}
/**
* @deprecated
* @param {string} event
* @returns {any}
*/
getOneTimeEventArgumens(event:string) {
return this.oneTimeArguments[event];
}
/**
* @deprecated
* @returns {T}
*/
offAll():T {
return this.off();
}
destroy():T {
this.off();
this.log.debug('Observable.destroy(): Listeners were destroyed');
return this;
}
emitAndCallback(event, args?, callback?):T {
args = this.utils.argumentsToArray(args);
if (event) this.emit.apply(this, [event].concat(args));
if (callback) callback.apply(this, args);
return this;
}
}
export function $get(context:context.Context):Observable {
return new Observable(context);
}