Browse Source

Move ovveriding collection variables to component watcher

pull/6359/head
mohamedsalem401 1 year ago
parent
commit
369caed2f3
  1. 95
      packages/core/src/data_sources/model/collection_component/CollectionComponent.ts
  2. 10
      packages/core/src/dom_components/model/Component.ts
  3. 31
      packages/core/src/dom_components/model/ComponentDynamicValueWatcher.ts
  4. 41
      packages/core/src/dom_components/model/DynamicValueWatcher.ts

95
packages/core/src/data_sources/model/collection_component/CollectionComponent.ts

@ -8,12 +8,7 @@ import { ObjectAny } from '../../../common';
import EditorModel from '../../../editor/model/Editor';
import { keyCollectionsStateMap } from '../../../dom_components/model/Component';
import { CollectionDefinition, CollectionState, CollectionsStateMap } from './types';
import {
keyCollectionDefinition,
keyInnerCollectionState,
CollectionComponentType,
CollectionVariableType,
} from './constants';
import { keyCollectionDefinition, keyInnerCollectionState, CollectionComponentType } from './constants';
export default class CollectionComponent extends Component {
constructor(props: CollectionDefinition & ComponentProperties, opt: ComponentOptions) {
@ -53,12 +48,11 @@ export default class CollectionComponent extends Component {
};
if (index === start_index) {
const { clonedBlock } = resolveBlockValues(collectionsStateMap, block);
const type = em.Components.getType(clonedBlock?.type || 'default');
const type = em.Components.getType(block?.type || 'default');
const model = type.model;
blockComponent = new model(
{
...clonedBlock,
...block,
[keyCollectionsStateMap]: collectionsStateMap,
},
opt,
@ -126,9 +120,8 @@ function resolveComponent(
collectionsStateMap: CollectionsStateMap,
em: EditorModel,
) {
const { resolvedCollectionValues } = resolveBlockValues(collectionsStateMap, block);
Object.keys(resolvedCollectionValues).length && component!.setSymbolOverride(Object.keys(resolvedCollectionValues));
component!.set(resolvedCollectionValues);
// @ts-ignore
component!.set(block);
const children: ComponentDefinition[] = [];
for (let index = 0; index < component!.components().length; index++) {
@ -147,81 +140,3 @@ function resolveComponent(
return componentDefinition;
}
// TODO: remove this function
function resolveBlockValues(collectionsStateMap: CollectionsStateMap, block: ObjectAny) {
const clonedBlock = deepCloneObject(block);
const resolvedCollectionValues: ObjectAny = {};
if (typeof clonedBlock === 'object') {
const blockKeys = Object.keys(clonedBlock);
for (const key of blockKeys) {
let blockValue = clonedBlock[key];
if (key === keyCollectionDefinition) continue;
let hasCollectionVariable = false;
if (typeof blockValue === 'object') {
const isCollectionVariable = blockValue.type === 'parent-collection-variable';
if (isCollectionVariable) {
hasCollectionVariable = true;
} else if (Array.isArray(blockValue)) {
clonedBlock[key] = blockValue.map((arrayItem: any) => {
const { clonedBlock, resolvedCollectionValues: itemOverrideKeys } = resolveBlockValues(
collectionsStateMap,
arrayItem,
);
if (!isEmptyObject(itemOverrideKeys)) {
hasCollectionVariable = true;
}
return typeof arrayItem === 'object' ? clonedBlock : arrayItem;
});
} else {
const { clonedBlock, resolvedCollectionValues: itemOverrideKeys } = resolveBlockValues(
collectionsStateMap,
blockValue,
);
clonedBlock[key] = clonedBlock;
if (!isEmptyObject(itemOverrideKeys)) {
hasCollectionVariable = true;
}
}
if (hasCollectionVariable && key !== 'components') {
resolvedCollectionValues[key] = clonedBlock[key];
}
}
}
}
return { clonedBlock, resolvedCollectionValues };
}
function isEmptyObject(itemOverrideKeys: ObjectAny) {
return Object.keys(itemOverrideKeys).length === 0;
}
/**
* Deeply clones an object.
* @template T The type of the object to clone.
* @param {T} obj The object to clone.
* @returns {T} A deep clone of the object, or the original object if it's not an object or is null. Returns undefined if input is undefined.
*/
function deepCloneObject<T extends Record<string, any> | null | undefined>(obj: T): T {
if (obj === null) return null as T;
if (obj === undefined) return undefined as T;
if (typeof obj !== 'object' || Array.isArray(obj)) {
return obj; // Return primitives directly
}
const clonedObj: Record<string, any> = {};
for (const key in obj) {
if (Object.prototype.hasOwnProperty.call(obj, key)) {
clonedObj[key] = deepCloneObject(obj[key]);
}
}
return clonedObj as T;
}

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

@ -368,10 +368,10 @@ export default class Component extends StyleableModel<ComponentProperties> {
}
// @ts-ignore
const componentDVListener = this.componentDVListener || options.componentDVListener;
const evaluatedAttributes = componentDVListener.addProps(attributes, options);
this.componentDVListener = this.componentDVListener || options.componentDVListener;
const evaluatedProps = this.componentDVListener.addProps(attributes, options);
return super.set(evaluatedAttributes, options);
return super.set(evaluatedProps, options);
}
__postAdd(opts: { recursive?: boolean } = {}) {
@ -692,9 +692,7 @@ export default class Component extends StyleableModel<ComponentProperties> {
* component.setAttributes({ id: 'test', 'data-key': 'value' });
*/
setAttributes(attrs: ObjectAny, opts: SetAttrOptions = { skipWatcherUpdates: false, fromDataSource: false }) {
// @ts-ignore
const componentDVListener = this.componentDVListener || opts.componentDVListener;
const evaluatedAttributes = componentDVListener.setAttributes(attrs, opts);
const evaluatedAttributes = this.componentDVListener.setAttributes(attrs, opts);
this.set('attributes', { ...evaluatedAttributes }, opts);
return this;

31
packages/core/src/dom_components/model/ComponentDynamicValueWatcher.ts

@ -1,4 +1,5 @@
import { ObjectAny } from '../../common';
import { CollectionVariableType } from '../../data_sources/model/collection_component/constants';
import { CollectionsStateMap } from '../../data_sources/model/collection_component/types';
import EditorModel from '../../editor/model/Editor';
import Component from './Component';
@ -10,7 +11,7 @@ export class ComponentDynamicValueWatcher {
private attributeWatcher: DynamicValueWatcher;
constructor(
component: Component | undefined,
private component: Component | undefined,
options: {
em: EditorModel;
collectionsStateMap: CollectionsStateMap;
@ -19,6 +20,7 @@ export class ComponentDynamicValueWatcher {
this.propertyWatcher = new DynamicValueWatcher(component, this.createPropertyUpdater(), options);
this.attributeWatcher = new DynamicValueWatcher(component, this.createAttributeUpdater(), options);
}
private createPropertyUpdater() {
return (component: Component | undefined, key: string, value: any) => {
if (!component) return;
@ -34,24 +36,45 @@ export class ComponentDynamicValueWatcher {
}
bindComponent(component: Component) {
this.component = component;
this.propertyWatcher.bindComponent(component);
this.attributeWatcher.bindComponent(component);
this.updateSymbolOverride();
}
addProps(props: ObjectAny, options?: DynamicWatchersOptions) {
return this.propertyWatcher.addDynamicValues(props, options);
const evaluatedProps = this.propertyWatcher.addDynamicValues(props, options);
return evaluatedProps;
}
addAttributes(attributes: ObjectAny, options?: DynamicWatchersOptions) {
return this.attributeWatcher.addDynamicValues(attributes, options);
const evaluatedAttributes = this.attributeWatcher.addDynamicValues(attributes, options);
this.updateSymbolOverride();
return evaluatedAttributes;
}
setAttributes(attributes: ObjectAny, options?: DynamicWatchersOptions) {
return this.attributeWatcher.setDynamicValues(attributes, options);
const evaluatedAttributes = this.attributeWatcher.setDynamicValues(attributes, options);
this.updateSymbolOverride();
return evaluatedAttributes;
}
removeAttributes(attributes: string[]) {
this.attributeWatcher.removeListeners(attributes);
this.updateSymbolOverride();
}
updateSymbolOverride() {
if (!this.component) return;
const keys = this.propertyWatcher.getDynamicValuesOfType(CollectionVariableType);
const attributesKeys = this.attributeWatcher.getDynamicValuesOfType(CollectionVariableType);
const combinedKeys = [...keys];
const haveOverridenAttributes = Object.keys(attributesKeys).length;
if (haveOverridenAttributes) combinedKeys.push('attributes');
this.component.setSymbolOverride(combinedKeys);
}
getDynamicPropsDefs() {

41
packages/core/src/dom_components/model/DynamicValueWatcher.ts

@ -1,3 +1,4 @@
import { DynamicValueDefinition } from './../../data_sources/types';
import { CollectionsStateMap } from '../../data_sources/model/collection_component/types';
import { ObjectAny } from '../../common';
import DynamicVariableListenerManager from '../../data_sources/model/DataVariableListenerManager';
@ -5,6 +6,7 @@ import { evaluateDynamicValueDefinition, isDynamicValueDefinition } from '../../
import { DynamicValue } from '../../data_sources/types';
import EditorModel from '../../editor/model/Editor';
import Component from './Component';
import CollectionVariable from '../../data_sources/model/collection_component/CollectionVariable';
export interface DynamicWatchersOptions {
skipWatcherUpdates?: boolean;
@ -22,22 +24,6 @@ export class DynamicValueWatcher {
},
) {}
getStaticValues(values: ObjectAny | undefined): ObjectAny {
if (!values) return {};
const evaluatedValues: ObjectAny = { ...values };
const propsKeys = Object.keys(values);
for (const key of propsKeys) {
const valueDefinition = values[key];
if (!isDynamicValueDefinition(valueDefinition)) continue;
const { value } = evaluateDynamicValueDefinition(valueDefinition, this.options);
evaluatedValues[key] = value;
}
return evaluatedValues;
}
bindComponent(component: Component) {
this.component = component;
}
@ -53,7 +39,7 @@ export class DynamicValueWatcher {
addDynamicValues(values: ObjectAny | undefined, options: DynamicWatchersOptions = {}) {
if (!values) return {};
const { evaluatedValues, dynamicValues } = this.getDynamicValues(values);
const { evaluatedValues, dynamicValues } = this.evaluateValues(values);
const shouldSkipWatcherUpdates = options.skipWatcherUpdates || options.fromDataSource;
if (!shouldSkipWatcherUpdates) {
@ -79,13 +65,14 @@ export class DynamicValueWatcher {
}
}
private getDynamicValues(values: ObjectAny) {
private evaluateValues(values: ObjectAny) {
const dynamicValues: {
[key: string]: DynamicValue;
} = {};
const evaluatedValues: {
[key: string]: DynamicValue;
[key: string]: any;
} = { ...values };
const valuesToBeOverriden: string[] = [];
const propsKeys = Object.keys(values);
for (let index = 0; index < propsKeys.length; index++) {
const key = propsKeys[index];
@ -95,9 +82,12 @@ export class DynamicValueWatcher {
const { value, variable } = evaluateDynamicValueDefinition(values[key], this.options);
evaluatedValues[key] = value;
dynamicValues[key] = variable;
if (variable instanceof CollectionVariable) {
valuesToBeOverriden.push(key);
}
}
return { evaluatedValues, dynamicValues };
return { evaluatedValues, dynamicValues, valuesToBeOverriden };
}
/**
@ -113,6 +103,8 @@ export class DynamicValueWatcher {
delete this.dynamicVariableListeners[key];
}
});
return propsKeys;
}
getSerializableValues(values: ObjectAny | undefined) {
@ -139,4 +131,13 @@ export class DynamicValueWatcher {
return serializableValues;
}
getDynamicValuesOfType(type: DynamicValueDefinition['type']) {
const keys = Object.keys(this.dynamicVariableListeners).filter((key: string) => {
// @ts-ignore
return this.dynamicVariableListeners[key].dynamicVariable.get('type') === type;
});
return keys;
}
}

Loading…
Cancel
Save