mframejs
Version:
simple framework
255 lines (205 loc) • 6.54 kB
text/typescript
import { PropertyObserverHandler } from './propertyObserverHandler';
/**
* this handles changes on property by using defineProperty, other can then subscibe this to get calls when chnages occur
*
*/
export class ClassPropertyObserver {
private _class: Object | any;
private key: string;
private value: any;
private callers: PropertyObserverHandler[];
private c1: PropertyObserverHandler;
private c2: PropertyObserverHandler;
private c3: PropertyObserverHandler;
private c4: PropertyObserverHandler;
private c5: PropertyObserverHandler;
private setterBind: any;
private getterBind: any;
constructor(_class: Object, key: string) {
this._class = _class;
this.key = key;
this.setterBind = this.setter.bind(this);
this.getterBind = this.getter.bind(this);
if (typeof this._class === 'object') {
this.value = this._class[this.key];
this.observe();
}
}
/**
* unsubscribe
*
*/
public unsubscribe(caller: PropertyObserverHandler) {
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);
}
}
/**
* subscribe
*
*/
public subscribe(caller: PropertyObserverHandler) {
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);
}
}
}
}
}
}
}
}
/**
* helper for #13 to update something that can be observed like array length
*
*/
public forceUpdate() {
if (this.c1) {
const cc1 = this.c1;
this.c1 = undefined;
cc1.update();
}
if (this.c2) {
const cc2 = this.c2;
this.c2 = undefined;
cc2.update();
}
if (this.c3) {
const cc3 = this.c3;
this.c3 = undefined;
cc3.update();
}
if (this.c4) {
const cc4 = this.c4;
this.c4 = undefined;
cc4.update();
}
if (this.c5) {
const cc5 = this.c5;
this.c5 = undefined;
cc5.update();
}
if (this.callers && this.callers.length > 0) {
const calls = this.callers.slice();
this.callers = [];
for (let i = 0; i < calls.length; i++) {
calls[i].update();
}
}
}
/**
* observer
*
*/
private observe() {
// check if property is on prototype have getter/setter, if se we skip it.
const descriptor = Reflect.getOwnPropertyDescriptor(this._class.__proto__, this.key);
let oldDescriptor = null;
if (descriptor) {
oldDescriptor = descriptor.get || descriptor.set;
if (oldDescriptor) {
console.warn('skipping dirty observer - no-dirty //todo remove this message');
}
}
if (oldDescriptor === null) {
if (!Reflect.defineProperty(this._class, this.key, {
configurable: true,
enumerable: true,
set: this.setterBind,
get: this.getterBind
})) {
console.warn('This key could not be observed:' + this.key);
}
}
}
/**
* setter
*
*/
private setter(newValue: any) {
if (newValue !== this.value) {
if (typeof newValue === 'object') {
if (newValue && newValue.__observer) {
newValue.__observer = null;
}
if (newValue && newValue.__observerArray) {
newValue.__observerArray = null;
}
}
this.value = newValue;
if (this.c1) {
const cc1 = this.c1;
this.c1 = undefined;
cc1.update();
}
if (this.c2) {
const cc2 = this.c2;
this.c2 = undefined;
cc2.update();
}
if (this.c3) {
const cc3 = this.c3;
this.c3 = undefined;
cc3.update();
}
if (this.c4) {
const cc4 = this.c4;
this.c4 = undefined;
cc4.update();
}
if (this.c5) {
const cc5 = this.c5;
this.c5 = undefined;
cc5.update();
}
if (this.callers && this.callers.length > 0) {
const calls = this.callers.slice();
this.callers = [];
for (let i = 0; i < calls.length; i++) {
calls[i].update();
}
}
}
}
/**
* getter
*
*/
private getter() {
return this.value;
}
}