Browse Source

Allow traits to be dynamic ( again )

pull/6351/head
mohamedsalem401 2 years ago
parent
commit
9093df6c7b
  1. 28
      packages/core/src/dom_components/model/Component.ts
  2. 45
      packages/core/src/dom_components/model/ComponentDynamicValueListener.ts
  3. 35
      packages/core/src/trait_manager/model/Trait.ts
  4. 35
      packages/core/test/specs/data_sources/model/conditional_variables/ConditionalTraits.ts
  5. 31
      packages/core/test/specs/data_sources/model/conditional_variables/__snapshots__/ConditionalTraits.ts.snap

28
packages/core/src/dom_components/model/Component.ts

@ -54,9 +54,9 @@ import {
import { ComponentDynamicValueListener } from './ComponentDynamicValueListener'; import { ComponentDynamicValueListener } from './ComponentDynamicValueListener';
import { DynamicValueWatcher } from './DynamicValueWatcher'; import { DynamicValueWatcher } from './DynamicValueWatcher';
export interface IComponent extends ExtractMethods<Component> {} export interface IComponent extends ExtractMethods<Component> { }
export interface SetAttrOptions extends SetOptions, UpdateStyleOptions {} export interface SetAttrOptions extends SetOptions, UpdateStyleOptions { }
const escapeRegExp = (str: string) => { const escapeRegExp = (str: string) => {
return str.replace(/[|\\{}()[\]^$+*?.]/g, '\\$&'); return str.replace(/[|\\{}()[\]^$+*?.]/g, '\\$&');
@ -70,6 +70,7 @@ export const keySymbol = '__symbol';
export const keySymbolOvrd = '__symbol_ovrd'; export const keySymbolOvrd = '__symbol_ovrd';
export const keyUpdate = ComponentsEvents.update; export const keyUpdate = ComponentsEvents.update;
export const keyUpdateInside = ComponentsEvents.updateInside; export const keyUpdateInside = ComponentsEvents.updateInside;
export const dynamicAttrKey = 'attributes-dynamic-value';
/** /**
* The Component object represents a single node of our template structure, so when you update its properties the changes are * The Component object represents a single node of our template structure, so when you update its properties the changes are
@ -222,12 +223,12 @@ export default class Component extends StyleableModel<ComponentProperties> {
return this.frame?.getPage(); return this.frame?.getPage();
} }
preInit() {} preInit() { }
/** /**
* Hook method, called once the model is created * Hook method, called once the model is created
*/ */
init() {} init() { }
/** /**
* Hook method, called when the model has been updated (eg. updated some model's property) * Hook method, called when the model has been updated (eg. updated some model's property)
@ -235,12 +236,12 @@ export default class Component extends StyleableModel<ComponentProperties> {
* @param {*} value Property value, if triggered after some property update * @param {*} value Property value, if triggered after some property update
* @param {*} previous Property previous value, if triggered after some property update * @param {*} previous Property previous value, if triggered after some property update
*/ */
updated(property: string, value: any, previous: any) {} updated(property: string, value: any, previous: any) { }
/** /**
* Hook method, called once the model has been removed * Hook method, called once the model has been removed
*/ */
removed() {} removed() { }
em!: EditorModel; em!: EditorModel;
opt!: ComponentOptions; opt!: ComponentOptions;
@ -1570,6 +1571,21 @@ export default class Component extends StyleableModel<ComponentProperties> {
let obj = Model.prototype.toJSON.call(this, opts); let obj = Model.prototype.toJSON.call(this, opts);
obj = { ...obj, ...this.componentDVListener.getDynamicPropsDefs() }; obj = { ...obj, ...this.componentDVListener.getDynamicPropsDefs() };
obj.attributes = this.componentDVListener.getAttributesDefsOrValues(this.getAttributes({ noClass: true })); obj.attributes = this.componentDVListener.getAttributesDefsOrValues(this.getAttributes({ noClass: true }));
const dynamicTraitsObj = this.componentDVListener.getTraitsDefs();
const keys = Object.keys(dynamicTraitsObj);
const serializedTraits: ObjectAny[] = [];
keys.forEach(key => {
const traitJSON = this.getTrait(key).toJSON();
const traitValue = dynamicTraitsObj[key];
serializedTraits.push({
...traitJSON,
name: key,
value: traitValue
})
});
if (serializedTraits.length > 0) {
obj[dynamicAttrKey] = serializedTraits;
}
delete obj.componentDVListener; delete obj.componentDVListener;
delete obj.traits; delete obj.traits;
delete obj.attributes.class; delete obj.attributes.class;

45
packages/core/src/dom_components/model/ComponentDynamicValueListener.ts

@ -1,11 +1,12 @@
import { ObjectAny } from '../../common'; import { ObjectAny } from '../../common';
import EditorModel from '../../editor/model/Editor'; import EditorModel from '../../editor/model/Editor';
import Component from './Component'; import Component, { dynamicAttrKey } from './Component';
import { DynamicValueWatcher } from './DynamicValueWatcher'; import { DynamicValueWatcher } from './DynamicValueWatcher';
export class ComponentDynamicValueListener { export class ComponentDynamicValueListener {
propertyWatchClass: DynamicValueWatcher; propertyWatchClass: DynamicValueWatcher;
attributeWatchClass: DynamicValueWatcher; attributeWatchClass: DynamicValueWatcher;
traitsWatchClass: DynamicValueWatcher;
constructor( constructor(
private component: Component, private component: Component,
@ -18,20 +19,46 @@ export class ComponentDynamicValueListener {
this.attributeWatchClass = new DynamicValueWatcher((key: string, value: any) => { this.attributeWatchClass = new DynamicValueWatcher((key: string, value: any) => {
this.component.setAttributes({ [key]: value }); this.component.setAttributes({ [key]: value });
}, em); }, em);
this.traitsWatchClass = new DynamicValueWatcher((key: string, value: any) => {
this.component.updateTrait(key, { value });
const trait = this.component.getTrait(key);
trait.setTargetValue(value);
}, em);
} }
static evaluateComponentDef(values: ObjectAny, em: EditorModel) { static evaluateComponentDef(values: ObjectAny, em: EditorModel) {
const props = DynamicValueWatcher.getStaticValues(values, em); const props = DynamicValueWatcher.getStaticValues(values, em);
if (values.attributes) { if (values.attributes) {
props.attributes = DynamicValueWatcher.getStaticValues(values.attributes, em); props.attributes = DynamicValueWatcher.getStaticValues(values.attributes, em);
} }
if (Array.isArray(values[dynamicAttrKey]) && values[dynamicAttrKey].length > 0) {
values.traits = values.traits
? [...values[dynamicAttrKey], ...values.traits]
: values[dynamicAttrKey];
}
if (values.traits) {
const evaluatedTraitsValues = DynamicValueWatcher.getStaticValues(
values.traits.map((trait: any) => trait.value),
em
);
props.traits = values.traits.map((trait: any, index: number) => ({
...trait,
value: evaluatedTraitsValues[index]
}));
}
return props; return props;
} }
watchComponentDef(values: ObjectAny) { watchComponentDef(values: ObjectAny) {
this.watchProps(values); this.watchProps(values);
this.watchAttributes(values.attributes); this.watchAttributes(values.attributes);
this.watchTraits(values.traits);
} }
watchProps(props: ObjectAny) { watchProps(props: ObjectAny) {
@ -52,6 +79,18 @@ export class ComponentDynamicValueListener {
this.attributeWatchClass.watchDynamicValue(attributes); this.attributeWatchClass.watchDynamicValue(attributes);
} }
watchTraits(traits: (string | ObjectAny)[]) {
const evaluatedTraits: { [key: string]: ObjectAny } = {}
traits?.forEach((trait: any) => {
if (typeof trait === 'string' || !trait.name) {
return;
} else if (typeof trait === 'object') {
evaluatedTraits[trait.name] = trait.value;
}
});
this.traitsWatchClass.watchDynamicValue(evaluatedTraits);
}
removeAttributes(attributes: string[]) { removeAttributes(attributes: string[]) {
this.attributeWatchClass.removeListeners(attributes); this.attributeWatchClass.removeListeners(attributes);
} }
@ -60,6 +99,10 @@ export class ComponentDynamicValueListener {
return this.attributeWatchClass.getSerializableValues(attributes); return this.attributeWatchClass.getSerializableValues(attributes);
} }
getTraitsDefs() {
return this.traitsWatchClass.getAllSerializableValues();
}
getPropsDefsOrValues(props: ObjectAny) { getPropsDefsOrValues(props: ObjectAny) {
return this.propertyWatchClass.getSerializableValues(props); return this.propertyWatchClass.getSerializableValues(props);
} }

35
packages/core/src/trait_manager/model/Trait.ts

@ -58,30 +58,6 @@ export default class Trait extends Model<TraitProperties> {
this.setTarget(target); this.setTarget(target);
} }
this.em = em; this.em = em;
if (isDynamicValueDefinition(this.attributes.value)) {
const dataType = this.attributes.value.type;
switch (dataType) {
case DataVariableType:
this.dynamicVariable = new TraitDataVariable(this.attributes.value, { em: this.em, trait: this });
break;
case ConditionalVariableType: {
const { condition, ifTrue, ifFalse } = this.attributes.value;
this.dynamicVariable = new DataCondition(condition, ifTrue, ifFalse, { em: this.em });
break;
}
default:
return;
}
const dv = this.dynamicVariable.getDataValue();
this.set({ value: dv });
this.dynamicVariableListener = new DynamicVariableListenerManager({
em: this.em,
dataVariable: this.dynamicVariable,
updateValueFromDataVariable: this.updateValueFromDataVariable.bind(this),
});
}
} }
get parent() { get parent() {
@ -116,11 +92,6 @@ export default class Trait extends Model<TraitProperties> {
} }
} }
updateValueFromDataVariable(value: string) {
this.setValue(value);
this.trigger('change:value');
}
/** /**
* Get the trait id. * Get the trait id.
* @returns {String} * @returns {String}
@ -166,12 +137,6 @@ export default class Trait extends Model<TraitProperties> {
* @returns {any} * @returns {any}
*/ */
getValue(opts?: TraitGetValueOptions) { getValue(opts?: TraitGetValueOptions) {
if (this.dynamicVariable) {
const dValue = this.dynamicVariable.getDataValue();
return dValue;
}
return this.getTargetValue(opts); return this.getTargetValue(opts);
} }

35
packages/core/test/specs/data_sources/model/conditional_variables/ConditionalTraits.ts

@ -4,7 +4,7 @@ import { MissingConditionError } from '../../../../../src/data_sources/model/con
import { ConditionalVariableType } from '../../../../../src/data_sources/model/conditional_variables/DataCondition'; import { ConditionalVariableType } from '../../../../../src/data_sources/model/conditional_variables/DataCondition';
import { GenericOperation } from '../../../../../src/data_sources/model/conditional_variables/operators/GenericOperator'; import { GenericOperation } from '../../../../../src/data_sources/model/conditional_variables/operators/GenericOperator';
import { NumberOperation } from '../../../../../src/data_sources/model/conditional_variables/operators/NumberOperator'; import { NumberOperation } from '../../../../../src/data_sources/model/conditional_variables/operators/NumberOperator';
import Component from '../../../../../src/dom_components/model/Component'; import Component, { dynamicAttrKey } from '../../../../../src/dom_components/model/Component';
import ComponentWrapper from '../../../../../src/dom_components/model/ComponentWrapper'; import ComponentWrapper from '../../../../../src/dom_components/model/ComponentWrapper';
import EditorModel from '../../../../../src/editor/model/Editor'; import EditorModel from '../../../../../src/editor/model/Editor';
import { filterObjectForSnapshot, setupTestEditor } from '../../../../common'; import { filterObjectForSnapshot, setupTestEditor } from '../../../../common';
@ -135,8 +135,7 @@ describe('TraitConditionalVariable', () => {
}).toThrow(MissingConditionError); }).toThrow(MissingConditionError);
}); });
// TODO: Should we keep or delete saving triats with dynamic values? it('should store traits with conditional values correctly', () => {
it.skip('should store traits with conditional values correctly', () => {
const conditionalTrait = { const conditionalTrait = {
type: ConditionalVariableType, type: ConditionalVariableType,
condition: { condition: {
@ -165,13 +164,10 @@ describe('TraitConditionalVariable', () => {
const frame = page.frames[0]; const frame = page.frames[0];
const storedComponent = frame.component.components[0]; const storedComponent = frame.component.components[0];
// expect(storedComponent[dynamicAttrKey]).toEqual({ expect(storedComponent[dynamicAttrKey][0].value).toEqual(conditionalTrait);
// dynamicTrait: conditionalTrait,
// });
}); });
// TODO: Should we keep or delete saving triats with dynamic values? it('should load traits with conditional values correctly', () => {
it.skip('should load traits with conditional values correctly', () => {
const projectData = { const projectData = {
pages: [ pages: [
{ {
@ -183,17 +179,18 @@ describe('TraitConditionalVariable', () => {
attributes: { attributes: {
dynamicTrait: 'Default', dynamicTrait: 'Default',
}, },
// [dynamicAttrKey]: { [dynamicAttrKey]: [{
// dynamicTrait: { name: 'dynamicTrait',
// condition: { value: {
// left: 0, condition: {
// operator: '>', left: 0,
// right: -1, operator: '>',
// }, right: -1,
// ifTrue: 'Positive', },
// type: 'conditional-variable', ifTrue: 'Positive',
// }, type: 'conditional-variable',
// }, },
}],
type: 'text', type: 'text',
}, },
], ],

31
packages/core/test/specs/data_sources/model/conditional_variables/__snapshots__/ConditionalTraits.ts.snap

@ -14,17 +14,30 @@ exports[`TraitConditionalVariable should store traits with conditional values co
"attributes": { "attributes": {
"dynamicTrait": "Positive", "dynamicTrait": "Positive",
}, },
"attributes-dynamic-value": { "attributes-dynamic-value": [
"dynamicTrait": { {
"condition": { "category": "",
"left": 0, "changeProp": false,
"operator": ">", "default": "",
"right": -1, "id": "data-variable-id",
"label": "",
"name": "dynamicTrait",
"options": [],
"placeholder": "",
"step": 1,
"type": "text",
"unit": "",
"value": {
"condition": {
"left": 0,
"operator": ">",
"right": -1,
},
"ifTrue": "Positive",
"type": "conditional-variable",
}, },
"ifTrue": "Positive",
"type": "conditional-variable",
}, },
}, ],
"tagName": "h1", "tagName": "h1",
"type": "text", "type": "text",
}, },

Loading…
Cancel
Save