mirror of https://github.com/artf/grapesjs.git
Browse Source
* Add tests for component wrapper * Refactor component data collection * Add data resolver to wrapper component * Fix types * Add collection data source to page * refactor get and set DataResolver to componentWrapper * Rename key to __rootData * add resolverCurrentItem * Make _resolverCurrentItem private * update ComponentWrapper tests * Fix componentWithCollectionsState * remove collectionsStateMap from Page * update component wrapper tests * fix component wrapper tests * return a copy of records for DataSource.getPath * Move all collection listeners to component with collection state * fix style sync in collection items * fix loop issue * update data collection tests * cleanup * update collection statemap on wrapper change * Add object test data for wrapper data resolver * cleanup * up unit test * remove duplicated code * cleanup event path * update test data to better names * improve component data collection performance * cleanup tests and types * fix performance issue for the new wrapper datasource * Undo updating component with datacolection tests * apply comments * Skip same path update --------- Co-authored-by: Artur Arseniev <artur.catch@hotmail.it>pull/6627/head
committed by
GitHub
12 changed files with 458 additions and 189 deletions
@ -0,0 +1,120 @@ |
|||||
|
import { DataCollectionStateMap } from '../../data_sources/model/data_collection/types'; |
||||
|
import DataResolverListener from '../../data_sources/model/DataResolverListener'; |
||||
|
import DataVariable, { DataVariableProps, DataVariableType } from '../../data_sources/model/DataVariable'; |
||||
|
import Components from '../../dom_components/model/Components'; |
||||
|
import Component from '../../dom_components/model/Component'; |
||||
|
import { ObjectAny } from '../../common'; |
||||
|
import DataSource from './DataSource'; |
||||
|
import { isArray } from 'underscore'; |
||||
|
|
||||
|
export type DataVariableMap = Record<string, DataVariableProps>; |
||||
|
|
||||
|
export type DataSourceRecords = DataVariableProps[] | DataVariableMap; |
||||
|
|
||||
|
export default class ComponentWithCollectionsState<DataResolverType> extends Component { |
||||
|
collectionsStateMap: DataCollectionStateMap = {}; |
||||
|
dataSourceWatcher?: DataResolverListener; |
||||
|
|
||||
|
constructor(props: any, opt: any) { |
||||
|
super(props, opt); |
||||
|
this.listenToPropsChange(); |
||||
|
} |
||||
|
|
||||
|
onCollectionsStateMapUpdate(collectionsStateMap: DataCollectionStateMap) { |
||||
|
this.collectionsStateMap = collectionsStateMap; |
||||
|
this.dataResolverWatchers?.onCollectionsStateMapUpdate?.(); |
||||
|
|
||||
|
this.components().forEach((cmp) => { |
||||
|
cmp.onCollectionsStateMapUpdate?.(collectionsStateMap); |
||||
|
}); |
||||
|
} |
||||
|
|
||||
|
syncOnComponentChange(model: Component, collection: Components, opts: any) { |
||||
|
const prev = this.collectionsStateMap; |
||||
|
this.collectionsStateMap = {}; |
||||
|
super.syncOnComponentChange(model, collection, opts); |
||||
|
this.collectionsStateMap = prev; |
||||
|
this.onCollectionsStateMapUpdate(prev); |
||||
|
} |
||||
|
|
||||
|
setDataResolver(dataResolver: DataResolverType | undefined) { |
||||
|
return this.set('dataResolver', dataResolver); |
||||
|
} |
||||
|
|
||||
|
get dataResolverProps(): DataResolverType | undefined { |
||||
|
return this.get('dataResolver'); |
||||
|
} |
||||
|
|
||||
|
protected listenToDataSource() { |
||||
|
const path = this.dataResolverPath; |
||||
|
if (!path) return; |
||||
|
|
||||
|
const { em, collectionsStateMap } = this; |
||||
|
this.dataSourceWatcher?.destroy(); |
||||
|
this.dataSourceWatcher = new DataResolverListener({ |
||||
|
em, |
||||
|
resolver: new DataVariable({ type: DataVariableType, path }, { em, collectionsStateMap }), |
||||
|
onUpdate: () => this.onDataSourceChange(), |
||||
|
}); |
||||
|
} |
||||
|
|
||||
|
protected listenToPropsChange() { |
||||
|
this.on(`change:dataResolver`, () => { |
||||
|
this.listenToDataSource(); |
||||
|
}); |
||||
|
|
||||
|
this.listenToDataSource(); |
||||
|
} |
||||
|
|
||||
|
protected get dataSourceProps(): DataVariableProps | undefined { |
||||
|
return this.get('dataResolver'); |
||||
|
} |
||||
|
|
||||
|
protected get dataResolverPath(): string | undefined { |
||||
|
return this.dataSourceProps?.path; |
||||
|
} |
||||
|
|
||||
|
protected onDataSourceChange() { |
||||
|
this.onCollectionsStateMapUpdate(this.collectionsStateMap); |
||||
|
} |
||||
|
|
||||
|
protected getDataSourceItems(): DataSourceRecords { |
||||
|
const dataSourceProps = this.dataSourceProps; |
||||
|
if (!dataSourceProps) return []; |
||||
|
const items = this.listDataSourceItems(dataSourceProps); |
||||
|
if (items && isArray(items)) { |
||||
|
return items; |
||||
|
} |
||||
|
|
||||
|
const clone = { ...items }; |
||||
|
return clone; |
||||
|
} |
||||
|
|
||||
|
protected listDataSourceItems(dataSource: DataSource | DataVariableProps): DataSourceRecords { |
||||
|
const path = dataSource instanceof DataSource ? dataSource.get('id')! : dataSource.path; |
||||
|
if (!path) return []; |
||||
|
let value = this.em.DataSources.getValue(path, []); |
||||
|
|
||||
|
const isDatasourceId = path.split('.').length === 1; |
||||
|
if (isDatasourceId) { |
||||
|
value = Object.entries(value).map(([_, value]) => value); |
||||
|
} |
||||
|
|
||||
|
return value; |
||||
|
} |
||||
|
|
||||
|
protected getItemKey(items: DataVariableProps[] | { [x: string]: DataVariableProps }, index: number) { |
||||
|
return isArray(items) ? index : Object.keys(items)[index]; |
||||
|
} |
||||
|
|
||||
|
private removePropsListeners() { |
||||
|
this.off(`change:dataResolver`); |
||||
|
this.dataSourceWatcher?.destroy(); |
||||
|
this.dataSourceWatcher = undefined; |
||||
|
} |
||||
|
|
||||
|
destroy(options?: ObjectAny): false | JQueryXHR { |
||||
|
this.removePropsListeners(); |
||||
|
return super.destroy(options); |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1 @@ |
|||||
|
export const keyRootData = '__rootData'; |
||||
Loading…
Reference in new issue