Skip to content

Commit d629989

Browse files
Add collection components (#6359)
1 parent f333ef4 commit d629989

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

48 files changed

+3780
-647
lines changed

README.md

+1-1
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
./packages/core/README.md
1+
./packages/core/README.md

packages/core/src/css_composer/model/CssRule.ts

-2
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,6 @@ import { isEmptyObj, hasWin } from '../../utils/mixins';
77
import Selector, { SelectorProps } from '../../selector_manager/model/Selector';
88
import EditorModel from '../../editor/model/Editor';
99
import CssRuleView from '../view/CssRuleView';
10-
import DynamicVariableListenerManager from '../../data_sources/model/DataVariableListenerManager';
1110

1211
/** @private */
1312
export interface CssRuleProperties {
@@ -95,7 +94,6 @@ export default class CssRule extends StyleableModel<CssRuleProperties> {
9594
em?: EditorModel;
9695
opt: any;
9796
views: CssRuleView[] = [];
98-
dynamicVariableListeners: Record<string, DynamicVariableListenerManager> = {};
9997

10098
defaults() {
10199
return {

packages/core/src/data_sources/model/ComponentDataVariable.ts

+11-3
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,11 @@
11
import Component from '../../dom_components/model/Component';
2+
import { ComponentOptions } from '../../dom_components/model/types';
23
import { toLowerCase } from '../../utils/mixins';
3-
import { DataVariableType } from './DataVariable';
4+
import DataVariable, { DataVariableProps, DataVariableType } from './DataVariable';
45

56
export default class ComponentDataVariable extends Component {
7+
dataResolver: DataVariable;
8+
69
get defaults() {
710
return {
811
// @ts-ignore
@@ -13,9 +16,14 @@ export default class ComponentDataVariable extends Component {
1316
};
1417
}
1518

19+
constructor(props: DataVariableProps, opt: ComponentOptions) {
20+
super(props, opt);
21+
const { type, path, defaultValue } = props;
22+
this.dataResolver = new DataVariable({ type, path, defaultValue }, opt);
23+
}
24+
1625
getDataValue() {
17-
const { path, defaultValue } = this.attributes;
18-
return this.em.DataSources.getValue(path, defaultValue);
26+
return this.dataResolver.getDataValue();
1927
}
2028

2129
getInnerHTML() {
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,96 @@
1+
import { DataSourcesEvents, DataSourceListener } from '../types';
2+
import { stringToPath } from '../../utils/mixins';
3+
import { Model } from '../../common';
4+
import EditorModel from '../../editor/model/Editor';
5+
import DataVariable, { DataVariableType } from './DataVariable';
6+
import { DataResolver } from '../types';
7+
import { DataCondition, DataConditionType } from './conditional_variables/DataCondition';
8+
import { DataCollectionVariableType } from './data_collection/constants';
9+
import DataCollectionVariable from './data_collection/DataCollectionVariable';
10+
11+
export interface DataResolverListenerProps {
12+
em: EditorModel;
13+
resolver: DataResolver;
14+
onUpdate: (value: any) => void;
15+
}
16+
17+
export default class DataResolverListener {
18+
private listeners: DataSourceListener[] = [];
19+
private em: EditorModel;
20+
private onUpdate: (value: any) => void;
21+
private model = new Model();
22+
resolver: DataResolver;
23+
24+
constructor(props: DataResolverListenerProps) {
25+
this.em = props.em;
26+
this.resolver = props.resolver;
27+
this.onUpdate = props.onUpdate;
28+
this.listenToResolver();
29+
}
30+
31+
private onChange = () => {
32+
const value = this.resolver.getDataValue();
33+
this.onUpdate(value);
34+
};
35+
36+
listenToResolver() {
37+
const { resolver, model } = this;
38+
this.removeListeners();
39+
let listeners: DataSourceListener[] = [];
40+
const type = resolver.attributes.type;
41+
42+
switch (type) {
43+
case DataCollectionVariableType:
44+
listeners = this.listenToDataCollectionVariable(resolver as DataCollectionVariable);
45+
break;
46+
case DataVariableType:
47+
listeners = this.listenToDataVariable(resolver as DataVariable);
48+
break;
49+
case DataConditionType:
50+
listeners = this.listenToConditionalVariable(resolver as DataCondition);
51+
break;
52+
}
53+
54+
listeners.forEach((ls) => model.listenTo(ls.obj, ls.event, this.onChange));
55+
this.listeners = listeners;
56+
}
57+
58+
private listenToConditionalVariable(dataVariable: DataCondition) {
59+
const { em } = this;
60+
const dataListeners = dataVariable.getDependentDataVariables().flatMap((dataVariable) => {
61+
return this.listenToDataVariable(new DataVariable(dataVariable, { em }));
62+
});
63+
64+
return dataListeners;
65+
}
66+
67+
private listenToDataVariable(dataVariable: DataVariable) {
68+
const { em } = this;
69+
const dataListeners: DataSourceListener[] = [];
70+
const { path } = dataVariable.attributes;
71+
const normPath = stringToPath(path || '').join('.');
72+
const [ds, dr] = em.DataSources.fromPath(path!);
73+
ds && dataListeners.push({ obj: ds.records, event: 'add remove reset' });
74+
dr && dataListeners.push({ obj: dr, event: 'change' });
75+
dataListeners.push(
76+
{ obj: dataVariable, event: 'change:path change:defaultValue' },
77+
{ obj: em.DataSources.all, event: 'add remove reset' },
78+
{ obj: em, event: `${DataSourcesEvents.path}:${normPath}` },
79+
);
80+
81+
return dataListeners;
82+
}
83+
84+
private listenToDataCollectionVariable(dataVariable: DataCollectionVariable) {
85+
return [{ obj: dataVariable, event: 'change:value' }];
86+
}
87+
88+
private removeListeners() {
89+
this.listeners.forEach((ls) => this.model.stopListening(ls.obj, ls.event, this.onChange));
90+
this.listeners = [];
91+
}
92+
93+
destroy() {
94+
this.removeListeners();
95+
}
96+
}

packages/core/src/data_sources/model/DataSource.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@
3131

3232
import { AddOptions, collectionEvents, CombinedModelConstructorOptions, Model, RemoveOptions } from '../../common';
3333
import EditorModel from '../../editor/model/Editor';
34-
import { DataSourceTransformers, DataSourceType, DataSourceProps, RecordPropsType, DataRecordProps } from '../types';
34+
import { DataSourceTransformers, DataSourceType, DataSourceProps, DataRecordProps } from '../types';
3535
import DataRecord from './DataRecord';
3636
import DataRecords from './DataRecords';
3737
import DataSources from './DataSources';
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,15 @@
11
import { Model } from '../../common';
22
import EditorModel from '../../editor/model/Editor';
3-
import { stringToPath } from '../../utils/mixins';
43

5-
export const DataVariableType = 'data-variable';
6-
export type DataVariableDefinition = {
4+
export const DataVariableType = 'data-variable' as const;
5+
6+
export interface DataVariableProps {
77
type: typeof DataVariableType;
88
path: string;
99
defaultValue?: string;
10-
};
10+
}
1111

12-
export default class DataVariable extends Model {
12+
export default class DataVariable extends Model<DataVariableProps> {
1313
em?: EditorModel;
1414

1515
defaults() {
@@ -20,33 +20,13 @@ export default class DataVariable extends Model {
2020
};
2121
}
2222

23-
constructor(attrs: DataVariableDefinition, options: any) {
24-
super(attrs, options);
23+
constructor(props: DataVariableProps, options: { em?: EditorModel }) {
24+
super(props, options);
2525
this.em = options.em;
26-
this.listenToDataSource();
27-
}
28-
29-
listenToDataSource() {
30-
const { path } = this.attributes;
31-
const resolvedPath = stringToPath(path).join('.');
32-
33-
if (this.em) {
34-
this.listenTo(this.em.DataSources, `change:${resolvedPath}`, this.onDataSourceChange);
35-
}
36-
}
37-
38-
onDataSourceChange() {
39-
const newValue = this.getDataValue();
40-
this.set({ value: newValue });
4126
}
4227

4328
getDataValue() {
4429
const { path, defaultValue } = this.attributes;
45-
if (!this.em) {
46-
throw new Error('EditorModel instance is not provided for a data variable.');
47-
}
48-
const val = this.em?.DataSources.getValue(path, defaultValue);
49-
50-
return val;
30+
return this.em?.DataSources.getValue(path!, defaultValue);
5131
}
5232
}

packages/core/src/data_sources/model/DataVariableListenerManager.ts

-88
This file was deleted.

packages/core/src/data_sources/model/StyleDataVariable.ts

-9
This file was deleted.

packages/core/src/data_sources/model/TraitDataVariable.ts

+4-4
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,14 @@
1-
import DataVariable, { DataVariableDefinition } from './DataVariable';
1+
import DataVariable, { DataVariableProps } from './DataVariable';
22
import Trait from '../../trait_manager/model/Trait';
33
import { TraitProperties } from '../../trait_manager/types';
44

5-
export type TraitDataVariableDefinition = TraitProperties & DataVariableDefinition;
5+
export interface TraitDataVariableProps extends Omit<TraitProperties, 'type'>, DataVariableProps {}
66

77
export default class TraitDataVariable extends DataVariable {
88
trait?: Trait;
99

10-
constructor(attrs: TraitDataVariableDefinition, options: any) {
11-
super(attrs, options);
10+
constructor(props: TraitDataVariableProps, options: any) {
11+
super(props, options);
1212
this.trait = options.trait;
1313
}
1414

Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
import Component from '../../../dom_components/model/Component';
2+
import { ComponentDefinition, ComponentOptions } from '../../../dom_components/model/types';
3+
import { toLowerCase } from '../../../utils/mixins';
4+
import { DataCondition, DataConditionProps, DataConditionType } from './DataCondition';
5+
6+
export default class ComponentDataCondition extends Component {
7+
dataResolver: DataCondition;
8+
9+
constructor(props: DataConditionProps, opt: ComponentOptions) {
10+
const { condition, ifTrue, ifFalse } = props;
11+
const dataConditionInstance = new DataCondition(condition, ifTrue, ifFalse, { em: opt.em });
12+
super(
13+
{
14+
...props,
15+
type: DataConditionType,
16+
components: dataConditionInstance.getDataValue(),
17+
},
18+
opt,
19+
);
20+
this.dataResolver = dataConditionInstance;
21+
this.dataResolver.onValueChange = this.handleConditionChange.bind(this);
22+
}
23+
24+
private handleConditionChange() {
25+
this.dataResolver.reevaluate();
26+
this.components(this.dataResolver.getDataValue());
27+
}
28+
29+
static isComponent(el: HTMLElement) {
30+
return toLowerCase(el.tagName) === DataConditionType;
31+
}
32+
33+
toJSON(): ComponentDefinition {
34+
return this.dataResolver.toJSON();
35+
}
36+
}

0 commit comments

Comments
 (0)