Browse Source

Allow traits to be dynamic ( again )

pull/6351/head
mohamedsalem401 1 year 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 { 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) => {
return str.replace(/[|\\{}()[\]^$+*?.]/g, '\\$&');
@ -70,6 +70,7 @@ export const keySymbol = '__symbol';
export const keySymbolOvrd = '__symbol_ovrd';
export const keyUpdate = ComponentsEvents.update;
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
@ -222,12 +223,12 @@ export default class Component extends StyleableModel<ComponentProperties> {
return this.frame?.getPage();
}
preInit() {}
preInit() { }
/**
* 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)
@ -235,12 +236,12 @@ export default class Component extends StyleableModel<ComponentProperties> {
* @param {*} value Property 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
*/
removed() {}
removed() { }
em!: EditorModel;
opt!: ComponentOptions;
@ -1570,6 +1571,21 @@ export default class Component extends StyleableModel<ComponentProperties> {
let obj = Model.prototype.toJSON.call(this, opts);
obj = { ...obj, ...this.componentDVListener.getDynamicPropsDefs() };
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.traits;
delete obj.attributes.class;

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

@ -1,11 +1,12 @@
import { ObjectAny } from '../../common';
import EditorModel from '../../editor/model/Editor';
import Component from './Component';
import Component, { dynamicAttrKey } from './Component';
import { DynamicValueWatcher } from './DynamicValueWatcher';
export class ComponentDynamicValueListener {
propertyWatchClass: DynamicValueWatcher;
attributeWatchClass: DynamicValueWatcher;
traitsWatchClass: DynamicValueWatcher;
constructor(
private component: Component,
@ -18,20 +19,46 @@ export class ComponentDynamicValueListener {
this.attributeWatchClass = new DynamicValueWatcher((key: string, value: any) => {
this.component.setAttributes({ [key]: value });
}, 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) {
const props = DynamicValueWatcher.getStaticValues(values, em);
if (values.attributes) {
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;
}
watchComponentDef(values: ObjectAny) {
this.watchProps(values);
this.watchAttributes(values.attributes);
this.watchTraits(values.traits);
}
watchProps(props: ObjectAny) {
@ -52,6 +79,18 @@ export class ComponentDynamicValueListener {
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[]) {
this.attributeWatchClass.removeListeners(attributes);
}
@ -60,6 +99,10 @@ export class ComponentDynamicValueListener {
return this.attributeWatchClass.getSerializableValues(attributes);
}
getTraitsDefs() {
return this.traitsWatchClass.getAllSerializableValues();
}
getPropsDefsOrValues(props: ObjectAny) {
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.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() {
@ -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.
* @returns {String}
@ -166,12 +137,6 @@ export default class Trait extends Model<TraitProperties> {
* @returns {any}
*/
getValue(opts?: TraitGetValueOptions) {
if (this.dynamicVariable) {
const dValue = this.dynamicVariable.getDataValue();
return dValue;
}
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 { GenericOperation } from '../../../../../src/data_sources/model/conditional_variables/operators/GenericOperator';
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 EditorModel from '../../../../../src/editor/model/Editor';
import { filterObjectForSnapshot, setupTestEditor } from '../../../../common';
@ -135,8 +135,7 @@ describe('TraitConditionalVariable', () => {
}).toThrow(MissingConditionError);
});
// TODO: Should we keep or delete saving triats with dynamic values?
it.skip('should store traits with conditional values correctly', () => {
it('should store traits with conditional values correctly', () => {
const conditionalTrait = {
type: ConditionalVariableType,
condition: {
@ -165,13 +164,10 @@ describe('TraitConditionalVariable', () => {
const frame = page.frames[0];
const storedComponent = frame.component.components[0];
// expect(storedComponent[dynamicAttrKey]).toEqual({
// dynamicTrait: conditionalTrait,
// });
expect(storedComponent[dynamicAttrKey][0].value).toEqual(conditionalTrait);
});
// TODO: Should we keep or delete saving triats with dynamic values?
it.skip('should load traits with conditional values correctly', () => {
it('should load traits with conditional values correctly', () => {
const projectData = {
pages: [
{
@ -183,17 +179,18 @@ describe('TraitConditionalVariable', () => {
attributes: {
dynamicTrait: 'Default',
},
// [dynamicAttrKey]: {
// dynamicTrait: {
// condition: {
// left: 0,
// operator: '>',
// right: -1,
// },
// ifTrue: 'Positive',
// type: 'conditional-variable',
// },
// },
[dynamicAttrKey]: [{
name: 'dynamicTrait',
value: {
condition: {
left: 0,
operator: '>',
right: -1,
},
ifTrue: 'Positive',
type: 'conditional-variable',
},
}],
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": {
"dynamicTrait": "Positive",
},
"attributes-dynamic-value": {
"dynamicTrait": {
"condition": {
"left": 0,
"operator": ">",
"right": -1,
"attributes-dynamic-value": [
{
"category": "",
"changeProp": false,
"default": "",
"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",
"type": "text",
},

Loading…
Cancel
Save