Browse Source

Add data resolver to wrapper component

pages-datasources
mohamedsalem401 1 year ago
parent
commit
d81686d476
  1. 139
      packages/core/src/data_sources/model/ComponentWithCollectionsState.ts
  2. 102
      packages/core/src/dom_components/model/ComponentWrapper.ts

139
packages/core/src/data_sources/model/ComponentWithCollectionsState.ts

@ -0,0 +1,139 @@
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 { isDataVariable } from '../utils';
import { isObject } from '../../utils/mixins';
import DataSource from './DataSource';
import { isArray } from 'underscore';
export type DataVariableMap = Record<string, DataVariableProps>;
export default class ComponentWithCollectionsState 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);
}
syncComponentsCollectionState() {
super.syncComponentsCollectionState();
this.components().forEach((cmp) => cmp.syncComponentsCollectionState?.());
}
protected listenToDataSource() {
const path = this.dataSourcePath;
if (!path) return;
const { em } = this;
this.dataSourceWatcher = new DataResolverListener({
em,
resolver: new DataVariable(
{ type: DataVariableType, path },
{ em, collectionsStateMap: this.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 dataSourcePath(): string | undefined {
return this.dataSourceProps?.path;
}
protected onDataSourceChange() {
this.onCollectionsStateMapUpdate(this.collectionsStateMap);
}
protected getDataSourceItems() {
const dataSourceProps = this.dataSourceProps;
if (!dataSourceProps) return [];
const items = this.listDataSourceItems(dataSourceProps);
if (items && isArray(items)) {
return items;
}
const clone = { ...items };
delete clone['__p'];
return clone;
}
protected listDataSourceItems(dataSource: DataSource | DataVariableProps): DataVariableProps[] | DataVariableMap {
const em = this.em;
switch (true) {
case isObject(dataSource) && dataSource instanceof DataSource: {
const id = dataSource.get('id')!;
return this.listDataSourceVariables(id);
}
case isDataVariable(dataSource): {
const path = dataSource.path;
if (!path) return [];
const isDataSourceId = path.split('.').length === 1;
if (isDataSourceId) {
return this.listDataSourceVariables(path);
} else {
return em.DataSources.getValue(path, []);
}
}
default:
return [];
}
}
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;
}
private listDataSourceVariables(path: string): DataVariableProps[] {
const records = this.em.DataSources.getValue(path, []);
const keys = Object.keys(records);
return keys.map((key) => ({
type: DataVariableType,
path: path + '.' + key,
}));
}
destroy(options?: ObjectAny): false | JQueryXHR {
this.removePropsListeners();
return super.destroy(options);
}
}

102
packages/core/src/dom_components/model/ComponentWrapper.ts

@ -1,10 +1,17 @@
import { isUndefined } from 'underscore'; import { isArray, isUndefined } from 'underscore';
import { attrToString } from '../../utils/dom'; import { attrToString } from '../../utils/dom';
import Component from './Component'; import Component from './Component';
import ComponentHead, { type as typeHead } from './ComponentHead'; import ComponentHead, { type as typeHead } from './ComponentHead';
import { ToHTMLOptions } from './types'; import { ToHTMLOptions } from './types';
import Components from './Components';
import DataResolverListener from '../../data_sources/model/DataResolverListener';
import { DataVariableProps } from '../../data_sources/model/DataVariable';
import { DataCollectionStateMap } from '../../data_sources/model/data_collection/types';
import ComponentWithCollectionsState, { DataVariableMap } from '../../data_sources/model/ComponentWithCollectionsState';
export default class ComponentWrapper extends ComponentWithCollectionsState {
dataSourceWatcher?: DataResolverListener;
export default class ComponentWrapper extends Component {
get defaults() { get defaults() {
return { return {
// @ts-ignore // @ts-ignore
@ -30,6 +37,21 @@ export default class ComponentWrapper extends Component {
}; };
} }
constructor(props: any, opt: any) {
super(props, opt);
const hasDataResolver = this.getDataResolver();
console.log('🚀 ~ ComponentWrapper ~ constructor ~ hasDataResolver:', hasDataResolver);
if (hasDataResolver) {
this.syncComponentsCollectionState();
console.log(
'🚀 ~ ComponentWrapper ~ constructor ~ this.getCollectionsStateMap():',
this.getCollectionsStateMap(),
);
this.onCollectionsStateMapUpdate(this.getCollectionsStateMap());
}
}
preInit() { preInit() {
const { opt, attributes: props } = this; const { opt, attributes: props } = this;
const cmp = this.em?.Components; const cmp = this.em?.Components;
@ -78,6 +100,82 @@ export default class ComponentWrapper extends Component {
return asDoc ? `${doctype}<html${docElAttrStr}>${headStr}${body}</html>` : body; return asDoc ? `${doctype}<html${docElAttrStr}>${headStr}${body}</html>` : body;
} }
setDataResolver(dataResolver: DataVariableProps) {
return this.set('dataResolver', dataResolver);
}
getDataResolver() {
return this.get('dataResolver');
}
onCollectionsStateMapUpdate(collectionsStateMap: DataCollectionStateMap) {
const { page, head } = this;
super.onCollectionsStateMapUpdate(collectionsStateMap);
head.onCollectionsStateMapUpdate(collectionsStateMap);
if (page) page.collectionsStateMap = collectionsStateMap;
}
syncComponentsCollectionState() {
super.syncComponentsCollectionState();
this.head.syncComponentsCollectionState();
}
syncOnComponentChange(model: Component, collection: Components, opts: any) {
const collectionsStateMap: any = this.getCollectionsStateMap();
this.collectionsStateMap = collectionsStateMap;
super.syncOnComponentChange(model, collection, opts);
this.onCollectionsStateMapUpdate(collectionsStateMap);
}
protected listenToPropsChange() {
this.on(`change:dataResolver`, () => {
this.onCollectionsStateMapUpdate(this.getCollectionsStateMap());
this.listenToDataSource();
});
this.listenToDataSource();
}
private getCollectionsStateMapForItem(items: DataVariableProps[] | DataVariableMap, key: number | string) {
const totalItems = Object.keys(items).length;
let item: DataVariableProps = (items as any)[key];
const numericKey = typeof key === 'string' ? Object.keys(items).indexOf(key) : key;
const offset = numericKey - 0;
const remainingItems = totalItems - (1 + offset);
const collectionState = {
collectionId: '__pages',
currentIndex: numericKey,
currentItem: item,
currentKey: key,
startIndex: 0,
endIndex: totalItems - 1,
totalItems: totalItems,
remainingItems,
};
return collectionState;
}
private getCollectionsStateMap(): DataCollectionStateMap {
const path = this.dataSourcePath;
if (!path) return this.collectionsStateMap;
const items = this.getDataSourceItems();
const pages = [];
const length = Object.keys(items).length;
for (let index = 0; index <= length; index++) {
const key = this.getItemKey(items, index);
const collectionsStateMap = this.getCollectionsStateMapForItem(items, key);
pages.push(collectionsStateMap);
}
const collectionsStateMap = {
__pages: { currentItem: pages },
};
return collectionsStateMap as any;
}
__postAdd() { __postAdd() {
const um = this.em?.UndoManager; const um = this.em?.UndoManager;
!this.__hasUm && um?.add(this); !this.__hasUm && um?.add(this);

Loading…
Cancel
Save