Browse Source

Refactor component data collection

pages-datasources
mohamedsalem401 1 year ago
parent
commit
e7aede4312
  1. 173
      packages/core/src/data_sources/model/data_collection/ComponentDataCollection.ts

173
packages/core/src/data_sources/model/data_collection/ComponentDataCollection.ts

@ -3,11 +3,9 @@ import { ObjectAny } from '../../../common';
import Component, { keySymbol } from '../../../dom_components/model/Component';
import { ComponentAddType, ComponentDefinitionDefined, ComponentOptions } from '../../../dom_components/model/types';
import EditorModel from '../../../editor/model/Editor';
import { isObject, toLowerCase } from '../../../utils/mixins';
import { toLowerCase } from '../../../utils/mixins';
import DataResolverListener from '../DataResolverListener';
import DataSource from '../DataSource';
import DataVariable, { DataVariableProps, DataVariableType } from '../DataVariable';
import { isDataVariable } from '../../utils';
import { DataVariableProps } from '../DataVariable';
import { DataCollectionItemType, DataCollectionType, keyCollectionDefinition } from './constants';
import {
ComponentDataCollectionProps,
@ -17,13 +15,11 @@ import {
} from './types';
import { detachSymbolInstance, getSymbolInstances } from '../../../dom_components/model/SymbolUtils';
import { keyDataValues, updateFromWatcher } from '../../../dom_components/model/ModelDataResolverWatchers';
import { ModelDestroyOptions } from 'backbone';
import Components from '../../../dom_components/model/Components';
import ComponentWithCollectionsState, { DataVariableMap } from '../ComponentWithCollectionsState';
const AvoidStoreOptions = { avoidStore: true, partial: true };
type DataVariableMap = Record<string, DataVariableProps>;
export default class ComponentDataCollection extends Component {
export default class ComponentDataCollection extends ComponentWithCollectionsState {
dataSourceWatcher?: DataResolverListener;
get defaults(): ComponentDefinitionDefined {
@ -123,47 +119,59 @@ export default class ComponentDataCollection extends Component {
this.firstChild.components(content);
}
private get firstChild() {
return this.components().at(0);
}
onCollectionsStateMapUpdate(collectionsStateMap: DataCollectionStateMap) {
super.onCollectionsStateMapUpdate(collectionsStateMap);
private updateCollectionConfig(updates: Partial<DataCollectionProps>): void {
this.set(keyCollectionDefinition, {
...this.dataResolver,
...updates,
const items = this.getDataSourceItems();
const { startIndex } = this.resolveCollectionConfig(items);
const cmps = this.components();
cmps.forEach((cmp, index) => {
const key = this.getItemKey(items, startIndex + index);
const collectionsStateMap = this.getCollectionsStateMapForItem(items, key);
cmp.onCollectionsStateMapUpdate(collectionsStateMap);
});
}
private getDataSourceItems() {
const items = getDataSourceItems(this.dataResolver.dataSource, this.em);
if (isArray(items)) {
return items;
}
protected stopSyncComponentCollectionState() {
this.stopListening(this.components(), 'add remove reset', this.syncOnComponentChange);
this.onCollectionsStateMapUpdate({});
}
protected setCollectionStateMapAndPropagate(cmp: Component, collectionsStateMap: DataCollectionStateMap) {
cmp.setSymbolOverride(['locked', 'layerable', keyDataValues]);
cmp.syncComponentsCollectionState();
cmp.onCollectionsStateMapUpdate(collectionsStateMap);
}
const clone = { ...items };
delete clone['__p'];
return clone;
protected onDataSourceChange() {
this.rebuildChildrenFromCollection();
}
private get dataResolver() {
return (this.get(keyCollectionDefinition) || {}) as DataCollectionProps;
protected listenToPropsChange() {
this.on(`change:${keyCollectionDefinition}`, () => {
this.rebuildChildrenFromCollection();
this.listenToDataSource();
});
this.listenToDataSource();
}
private get collectionDataSource() {
protected get dataSourceProps(): DataVariableProps | undefined {
return this.dataResolver.dataSource;
}
private listenToDataSource() {
const { em } = this;
const path = this.collectionDataSource?.path;
if (!path) return;
this.dataSourceWatcher = new DataResolverListener({
em,
resolver: new DataVariable(
{ type: DataVariableType, path },
{ em, collectionsStateMap: this.collectionsStateMap },
),
onUpdate: this.rebuildChildrenFromCollection,
protected get dataResolver(): DataCollectionProps {
return this.get(keyCollectionDefinition) || {};
}
private get firstChild() {
return this.components().at(0);
}
private updateCollectionConfig(updates: Partial<DataCollectionProps>): void {
this.set(keyCollectionDefinition, {
...this.dataResolver,
...updates,
});
}
@ -200,13 +208,13 @@ export default class ComponentDataCollection extends Component {
for (let index = startIndex; index <= endIndex; index++) {
const isFirstItem = index === startIndex;
const key = isArray(items) ? index : Object.keys(items)[index];
const key = this.getItemKey(items, index);
const collectionsStateMap = this.getCollectionsStateMapForItem(items, key);
if (isFirstItem) {
getSymbolInstances(firstChild)?.forEach((cmp) => detachSymbolInstance(cmp));
setCollectionStateMapAndPropagate(firstChild, collectionsStateMap);
this.setCollectionStateMapAndPropagate(firstChild, collectionsStateMap);
// TODO: Move to component view
firstChild.addStyle({ display: resolvedDisplay }, AvoidStoreOptions);
@ -215,7 +223,7 @@ export default class ComponentDataCollection extends Component {
const instance = firstChild!.clone({ symbol: true, symbolInv: true });
instance.set({ locked: true, layerable: false }, AvoidStoreOptions);
setCollectionStateMapAndPropagate(instance, collectionsStateMap);
this.setCollectionStateMapAndPropagate(instance, collectionsStateMap);
components.push(instance);
}
@ -287,46 +295,6 @@ export default class ComponentDataCollection extends Component {
);
}
private listenToPropsChange() {
this.on(`change:${keyCollectionDefinition}`, () => {
this.rebuildChildrenFromCollection();
this.listenToDataSource();
});
this.listenToDataSource();
}
private removePropsListeners() {
this.off(`change:${keyCollectionDefinition}`);
this.dataSourceWatcher?.destroy();
}
onCollectionsStateMapUpdate(collectionsStateMap: DataCollectionStateMap) {
super.onCollectionsStateMapUpdate(collectionsStateMap);
const items = this.getDataSourceItems();
const { startIndex } = this.resolveCollectionConfig(items);
const cmps = this.components();
cmps.forEach((cmp, index) => {
const collectionsStateMap = this.getCollectionsStateMapForItem(items, startIndex + index);
cmp.onCollectionsStateMapUpdate(collectionsStateMap);
});
}
stopSyncComponentCollectionState() {
this.stopListening(this.components(), 'add remove reset', this.syncOnComponentChange);
this.onCollectionsStateMapUpdate({});
}
syncOnComponentChange(model: Component, collection: Components, opts: any) {
const collectionsStateMap = this.collectionsStateMap;
// Avoid assigning wrong collectionsStateMap value to children components
this.collectionsStateMap = {};
super.syncOnComponentChange(model, collection, opts);
this.collectionsStateMap = collectionsStateMap;
this.onCollectionsStateMapUpdate(collectionsStateMap);
}
private get collectionId() {
return this.getDataResolver().collectionId as string;
}
@ -344,23 +312,12 @@ export default class ComponentDataCollection extends Component {
const firstChild = this.firstChild as any;
return { ...json, components: [firstChild] };
}
destroy(options?: ModelDestroyOptions | undefined): false | JQueryXHR {
this.removePropsListeners();
return super.destroy(options);
}
}
function getLength(items: DataVariableProps[] | object) {
return isArray(items) ? items.length : Object.keys(items).length;
}
function setCollectionStateMapAndPropagate(cmp: Component, collectionsStateMap: DataCollectionStateMap) {
cmp.setSymbolOverride(['locked', 'layerable', keyDataValues]);
cmp.syncComponentsCollectionState();
cmp.onCollectionsStateMapUpdate(collectionsStateMap);
}
function logErrorIfMissing(property: any, propertyPath: string, em: EditorModel) {
if (!property) {
em.logError(`The "${propertyPath}" property is required in the collection definition.`);
@ -389,37 +346,3 @@ function validateCollectionDef(dataResolver: DataCollectionProps, em: EditorMode
return true;
}
function getDataSourceItems(
dataSource: DataCollectionDataSource,
em: EditorModel,
): DataVariableProps[] | DataVariableMap {
switch (true) {
case isObject(dataSource) && dataSource instanceof DataSource: {
const id = dataSource.get('id')!;
return listDataSourceVariables(id, em);
}
case isDataVariable(dataSource): {
const path = dataSource.path;
if (!path) return [];
const isDataSourceId = path.split('.').length === 1;
if (isDataSourceId) {
return listDataSourceVariables(path, em);
} else {
return em.DataSources.getValue(path, []);
}
}
default:
return [];
}
}
function listDataSourceVariables(dataSource_id: string, em: EditorModel): DataVariableProps[] {
const records = em.DataSources.getValue(dataSource_id, []);
const keys = Object.keys(records);
return keys.map((key) => ({
type: DataVariableType,
path: dataSource_id + '.' + key,
}));
}

Loading…
Cancel
Save