UNPKG

@pilotlab/lux-attributes

Version:

A luxurious user experience framework, developed by your friends at Pilot.

150 lines (112 loc) 5.9 kB
import is from '@pilotlab/lux-is'; import { IPromise, Result } from '@pilotlab/lux-result'; import { ProgressTracker, ProgressCommand, ProgressRunArgs } from '@pilotlab/lux-progress'; import { DataType } from './attributeEnums'; import IAttributeSetReturn from './interfaces/iAttributeSetReturn'; import IAttribute from './interfaces/iAttribute'; import IAttributes from './interfaces/iAttributes'; import IAttributeChangeOptions from './interfaces/iAttributeChangeOptions'; import AttributeChangeOptions from './attributeChangeOptions'; import { Animation, IAnimationBatch, AnimationBatch } from '@pilotlab/lux-animation'; import IAttributeUpdateTracker from './interfaces/iAttributeUpdateTracker'; export class AttributeUpdateTracker implements IAttributeUpdateTracker { constructor( attributesNew:IAttributes, changeOptions:IAttributeChangeOptions = AttributeChangeOptions.default, progressTracker?:ProgressTracker, attributesChanged?:IAttributes ) { this.attributesNew = attributesNew; this.changeOptions = changeOptions; this.p_result = new Result<IAttributeUpdateTracker>(); if (is.notEmpty(progressTracker)) this.progressTracker = progressTracker; /// IMPORTANT: /// Be sure to use a factory to create an empty collection here, /// or this code will break tests with UnhandledPromiseRejectionWarning. this.p_attributesChanged = is.notEmpty(attributesChanged) ? attributesChanged : attributesNew.create.collection.instance(); this.animation = new AnimationBatch(Animation.animate, [], false); } get progressTracker():ProgressTracker { if (is.empty(this.p_progressTracker)) { this.progressTracker = new ProgressTracker(); } return this.p_progressTracker; } set progressTracker(value:ProgressTracker) { if (is.empty(value)) return; this.p_progressTracker = value; this.p_progressTracker.completed.listenOnce(() => { this.animation.initialize(); this.p_result.resolve(this); }); } protected p_progressTracker:ProgressTracker; attributesNew:IAttributes; changeOptions:IAttributeChangeOptions; animation:IAnimationBatch; get result():IPromise<IAttributeUpdateTracker> { return this.p_result; } protected p_result:IPromise<any>; get isChanged():boolean { return this.p_isChanged; } protected p_isChanged:boolean = false; get attributesChanged():IAttributes { return this.p_attributesChanged; } protected p_attributesChanged:IAttributes; /** * This is resolved once the tracker has finished updating all attributes, * but before animations are initialized after the update cycle. */ then(onDone:(value:IAttributeUpdateTracker) => any, onError?:(error:Error) => void):IPromise<any> { return this.p_result.then(onDone, onError); } update(attributesToUpdate:IAttributes):void { this.attributesNew.forEach((attributeNew:IAttribute) => { let attributeToUpdate:IAttribute = is.notEmpty(attributesToUpdate) ? attributesToUpdate.get(attributeNew.key) : null; if (is.empty(attributeToUpdate)) return true; if (attributeToUpdate.dataType === DataType.COLLECTION) this.p_queueAttributesUpdate(attributeToUpdate.value, attributeNew); this.p_queueAttributeUpdate(attributeToUpdate, attributeNew); return true; }); } protected p_queueCommand(command:ProgressCommand, key?:string):void { if (is.empty(command)) return; if (is.empty(key)) this.progressTracker.queueCommand(command, [this.attributesNew, this.changeOptions]); else { let dataAttribute:IAttribute = this.attributesNew.get(key); if (is.empty(dataAttribute) || dataAttribute.isEmpty) return; this.progressTracker.queueCommand(command, [dataAttribute.value, this]); } } protected p_queueAttributeUpdate(attributeToUpdate:IAttribute, attributeNew:IAttribute):void { if (is.empty(attributeNew)) attributeNew = this.attributesNew.get(attributeToUpdate.key); if (attributeNew.isEmpty) return; this.progressTracker.queue((args:ProgressRunArgs) => { attributeToUpdate.set( attributeNew.value, this.changeOptions ).then((attributeSetReturn:IAttributeSetReturn) => { if (is.notEmpty(attributeSetReturn.animation) && attributeSetReturn.animation.animations.size > 0) { this.animation.animations.append(attributeSetReturn.animation.animations); } if (attributeSetReturn.isChanged) { this.p_isChanged = true; this.p_attributesChanged.addByPath(attributeToUpdate, attributeToUpdate.path); } args.result.resolve(); }); }, this, 'updating ' + attributeToUpdate.key + ' attribute'); } protected p_queueAttributesUpdate(attributesToUpdate:IAttributes, attributeNew:IAttribute):void { if (is.empty(attributesToUpdate) || is.empty(attributeNew)) return; if ( attributeNew.isEmpty || attributeNew.dataType !== DataType.COLLECTION || is.empty(attributeNew.value) || attributeNew.value.size === 0 ) return; this.progressTracker.queue((args:ProgressRunArgs) => { let updateTracker:AttributeUpdateTracker = new AttributeUpdateTracker(attributeNew.value, this.changeOptions, args.subTracker, this.p_attributesChanged); attributesToUpdate.updateTracked(updateTracker); return updateTracker.result; }, this, 'updating ' + attributeNew.key + ' data'); } } // End class export default AttributeUpdateTracker;