UNPKG

mframejs

Version:
202 lines (159 loc) 7.2 kB
import { RepeatAttribute } from './repeatAttribute'; import { BindingEngine } from '../binding/exported'; import { IListener } from '../interface/exported'; import { ArrayObserverHandler } from '../binding/array/arrayObserverHandler'; import { PropertyObserverHandler } from '../binding/property/propertyObserverHandler'; /*************************************************************** * Helpers for repeat for attribute when array changes * ArrayMethodCallHandler & ArrayPropertyChange & PropertyChangeSimple ***************************************************************/ /** * Handles events/methods on array, like push/splice etc * */ export class ArrayMethodCallHandler implements IListener { public name: string; public caller: ArrayObserverHandler | PropertyObserverHandler; constructor( private repeat: RepeatAttribute ) { this.name = 'repeat' + this.repeat.value; } public call(events: any) { let sort = true; events.forEach((event: any) => { switch (event.event) { case 'push': let i = 0; while (i < event.args.length) { this.repeat.push(event.args[i]); i++; } this.repeat.updateInternals(); break; case 'reverse': case 'sort': if (sort) { sort = false; const array = this.repeat.$array; // BindingEngine.evaluateExpression(this.repeat.arrayExpression, this.repeat.$bindingContext); if (array) { array.forEach((ctx: any, i: number) => { this.repeat.templateArray[i].ctx.$context[this.repeat.rowInstanceName] = ctx; }); } } break; case 'shift': this.repeat.shift(); break; case 'pop': this.repeat.pop(); break; case 'splice': this.repeat.splice(event.args); break; default: } }); } } /** * Handles changes to array when its replaced * */ export class ArrayPropertyChange implements IListener { public name: string; public caller: ArrayObserverHandler | PropertyObserverHandler; constructor( private repeat: RepeatAttribute, public expression?: boolean ) { this.name = 'repeat' + this.repeat.value; } public call() { if (this.repeat.isAttached) { const array = BindingEngine.evaluateExpression(this.repeat.arrayExpression, this.repeat.$bindingContext); if (Array.isArray(array) && this.repeat.templateArray.length !== array.length) { this.repeat.$array = array; if (this.repeat.templateArray.length !== 0 && array.length !== 0) { if (this.repeat.templateArray.length > array.length) { this.repeat.loopBinded(true, this.repeat.templateArray.length - array.length, 0); } else { this.repeat.loopBinded(true, 0, array.length - this.repeat.templateArray.length); } BindingEngine.unSubscribeClassArray(this.repeat.$bindingContext, this.repeat.arrayMethodCallHandler); this.repeat.subscribeArray(); } else { this.repeat.clearTemplateArray(); let array = BindingEngine.evaluateExpression(this.repeat.arrayExpression, this.repeat.$bindingContext); if (Array.isArray(array)) { array.forEach((ctx: any) => { this.repeat.push(ctx); }); BindingEngine.unSubscribeClassArray(this.repeat.$bindingContext, this.repeat.arrayMethodCallHandler); this.repeat.subscribeArray(); array = null; } } } else { if (Array.isArray(array)) { // array is same size, we just need to replace data this.repeat.$array = array; this.repeat.loopBinded(); BindingEngine.unSubscribeClassArray(this.repeat.$bindingContext, this.repeat.arrayMethodCallHandler); if (array) { this.repeat.subscribeArray(); } } else { // array is null/undefined, we need to clear array this.repeat.$array = Array.isArray(array) ? array : []; this.repeat.clearTemplateArray(); BindingEngine.unSubscribeClassArray(this.repeat.$bindingContext, this.repeat.arrayMethodCallHandler); if (array) { this.repeat.subscribeArray(); } } } } } } /** * Handles changes to property(not array when this is used) when its replaced (simple array, not object) * */ export class PropertyChangeSimple implements IListener { public name: string; public caller: ArrayObserverHandler | PropertyObserverHandler; constructor(private repeat: RepeatAttribute) { this.name = 'repeat' + this.repeat.value; } public call(newValue: any) { if (this.repeat.isAttached) { if (this.repeat.arrayType === 'string') { // TODO: this is slow if sub router and many // I think this will ever be used..much // need to think about implementing this better like numbers const stringLength = typeof newValue === 'string' ? newValue.length : 0; if (this.repeat.templateArray.length !== stringLength) { this.repeat.clearTemplateArray(); for (let i = 0; i < stringLength; i++) { this.repeat.push(newValue[i]); } } } if (this.repeat.arrayType === 'number') { if (typeof newValue !== 'number') { console.warn('repeat not number:', newValue); newValue = 0; } if (this.repeat.templateArray.length !== newValue) { if (this.repeat.templateArray.length < newValue) { this.repeat.loopArrayNumber(true, 0, newValue - this.repeat.templateArray.length); } else { this.repeat.loopArrayNumber(true, this.repeat.templateArray.length - newValue, 0); } } } } } }