mframejs
Version:
simple framework
199 lines (161 loc) • 5.5 kB
text/typescript
import { ArrayObserverHandler } from './arrayObserverHandler';
// use prototype
// by doing this instead of object define I only do it once for all arrays
const events = ['pop', 'push', 'reverse', 'shift', 'sort', 'splice', 'unshift', 'sort'];
events.forEach((eventX) => {
const eventType = Array.prototype[eventX];
Array.prototype[eventX] = function () {
const result = eventType.apply(this, arguments);
if (this.__array_observer__class) {
this.__array_observer__class.check(arguments, eventX);
}
return result;
};
});
/**
* this is used to set observer on a array on a class/object
*
*/
export class ClassArrayObserver {
private callers: ArrayObserverHandler[];
private c1: ArrayObserverHandler;
private c2: ArrayObserverHandler;
private c3: ArrayObserverHandler;
private c4: ArrayObserverHandler;
private c5: ArrayObserverHandler;
private internalEvents: any[] = [];
private timer: any = null;
constructor(
private _class: Object,
private key: string
) {
if (typeof this._class === 'object') {
this.observe();
}
}
/**
* subscribe
*
*/
public subscribe(caller: ArrayObserverHandler) {
if (this.c1 !== caller && this.c2 !== caller && this.c3 !== caller && this.c4 !== caller && this.c5 !== caller) {
if (!this.c1) {
this.c1 = caller;
} else {
if (!this.c2) {
this.c2 = caller;
} else {
if (!this.c3) {
this.c3 = caller;
} else {
if (!this.c4) {
this.c4 = caller;
} else {
if (!this.c5) {
this.c5 = caller;
} else {
if (!this.callers) {
this.callers = [];
}
if (this.callers.indexOf(caller) === -1) {
this.callers.push(caller);
}
}
}
}
}
}
}
}
/**
* unsubscribe
*
*/
public unsubscribe(caller: ArrayObserverHandler) {
if (this.c1 === caller) {
this.c1 = null;
}
if (this.c2 === caller) {
this.c2 = null;
}
if (this.c3 === caller) {
this.c3 = null;
}
if (this.c4 === caller) {
this.c4 = null;
}
if (this.c5 === caller) {
this.c5 = null;
}
if (this.callers && this.callers.indexOf(caller) !== -1) {
this.callers.splice(this.callers.indexOf(caller), 1);
}
}
public check(args: any, event: any) {
clearTimeout(this.timer);
this.timer = 0;
// push event
this.internalEvents.push({
event: event,
args: args
});
this.timer = setTimeout(() => {
if (this.c1) {
const cc1 = this.c1;
this.c1 = undefined;
cc1.update(this.internalEvents);
}
if (this.c2) {
const cc2 = this.c2;
this.c2 = undefined;
cc2.update(this.internalEvents);
}
if (this.c3) {
const cc3 = this.c3;
this.c3 = undefined;
cc3.update(this.internalEvents);
}
if (this.c4) {
const cc4 = this.c4;
this.c4 = undefined;
cc4.update(this.internalEvents);
}
if (this.c5) {
const cc5 = this.c5;
this.c5 = undefined;
cc5.update(this.internalEvents);
}
if (this.callers && this.callers.length > 0) {
const calls = this.callers.slice();
this.callers = [];
calls.forEach((call: any) => {
call.update(this.internalEvents);
});
}
this.internalEvents = null;
this.internalEvents = [];
// check for length prop #13
// needs to be tested I dont break something else...
if (this._class[this.key] && this._class[this.key].__observer) {
for (const k in this._class[this.key].__observer) {
if (this._class[this.key].__observer[k] && this._class[this.key].__observer[k].forceUpdate) {
this._class[this.key].__observer[k].forceUpdate();
}
}
}
}, 0);
}
/**
* observe
*
*/
private observe() {
if (this._class[this.key] && Array.isArray(this._class[this.key])) {
Object.defineProperty(this._class[this.key], '__array_observer__class', {
writable: true,
configurable: true,
value: this
});
}
}
}