mframejs
Version:
simple framework
138 lines (107 loc) • 3.33 kB
text/typescript
import { traverseAST, getBehavior } from '../ast/traverseAst';
import { createBindingExpression, removeBindingExpression } from '../createBindingExpression';
import { IListener, IBindingContext } from '../../interface/exported';
import { ContainerBehavior } from '../../container/exported';
/**
* Register/creates a property observer with expression
* It be called on changes to value of expression
*
*/
export class PropertyObserverHandler {
private expression: string;
private ast: any;
private context: IBindingContext;
private observing: boolean;
private listener: IListener;
private value: any = undefined;
private isNew = true;
public curBehavior: any;
public attributesValues: string[];
constructor(expression: string, listener: IListener) {
this.expression = expression;
this.listener = listener;
}
/**
* binds observer handler to passed in context
*
*/
public bind(context: IBindingContext) {
this.observing = true;
this.context = context;
createBindingExpression(this.expression, this.context, this);
}
/**
* gets new AST "createNewBindingExpression"
*
*/
public setAst(ast: Object) {
this.ast = ast;
if (!this.curBehavior) {
this.connectBehavior();
}
}
/**
* Sets init value
*
*/
public init() {
if (this.isNew) {
this.isNew = false;
const oldValue = this.value;
const newValue = traverseAST(this.ast, this.context);
this.value = newValue;
this.listenerCall(newValue, oldValue);
this.isNew = false;
}
}
/**
* connectBehavior
* only used for signal
*
*/
public connectBehavior() {
const behaviors = getBehavior(this.ast);
if (behaviors) {
behaviors.forEach((behavior: { name: string, args: any[] }) => {
if (behavior.name === 'signal') {
const x = ContainerBehavior.findBehavior(behavior.name);
if (x) {
this.curBehavior = new x(this, behavior.args);
}
}
});
}
}
/**
* Gets called by observer, it then calls the listener
*
*/
public update() {
const newValue = traverseAST(this.ast, this.context);
const oldValue = this.value;
this.value = newValue;
this.listenerCall(newValue, oldValue);
this.bind(this.context);
}
public listenerCall(newValue: any, oldValue: any) {
if (this.listener) {
this.listener.call(newValue, oldValue);
}
}
/**
* Unbinds and clears all internals
*
*/
public unbind() {
if (this.observing) {
removeBindingExpression(this.expression, this.context, this);
}
// remove this from caller
this.listener.caller = null;
// remove rest of internals
this.observing = false;
this.context = null;
this.listener = null;
this.value = null;
}
}