@pilotlab/lux-attributes
Version:
A luxurious user experience framework, developed by your friends at Pilot.
150 lines (112 loc) • 5.9 kB
text/typescript
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;