Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add collection components #6359

Merged
merged 113 commits into from
Feb 3, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
113 commits
Select commit Hold shift + click to select a range
21a08cc
Add collection component
mohamedsalem401 Dec 17, 2024
d49cd39
Add resolving collection variables
mohamedsalem401 Dec 17, 2024
4aee355
Allow data-variable paths as a collection's datasource
mohamedsalem401 Dec 17, 2024
7294394
make collection items undraggable and undroppable
mohamedsalem401 Dec 17, 2024
17b84fb
Add many info to the currentItem
mohamedsalem401 Dec 18, 2024
7db4187
fix passing a datasource as collection's datasource
mohamedsalem401 Dec 18, 2024
09da446
Allow nested collections
mohamedsalem401 Dec 19, 2024
2f6f13c
Fix collection iteration values
mohamedsalem401 Dec 19, 2024
9d142f4
Fix getting current item
mohamedsalem401 Dec 19, 2024
01e81f4
Use values from the innermost collection instead of the outermost one.
mohamedsalem401 Dec 19, 2024
4a22be0
Throw an error when using the name of a non-existent collection.
mohamedsalem401 Dec 19, 2024
72539f1
refactor componentCollectionKey
mohamedsalem401 Dec 19, 2024
ddab929
remove circular dependancy
mohamedsalem401 Dec 19, 2024
d631ca7
Add start and end index for collections
mohamedsalem401 Dec 19, 2024
a36aa30
Merge branch 'dev' of https://github.com/GrapesJS/grapesjs into colle…
mohamedsalem401 Dec 23, 2024
050a4cd
use symbols for collection components
mohamedsalem401 Dec 25, 2024
b142b14
refactor collection symbols
mohamedsalem401 Dec 25, 2024
a1ce18a
Refactor collections
mohamedsalem401 Dec 25, 2024
ed8ecbc
Refactor and format
mohamedsalem401 Dec 25, 2024
a1fea6e
Refactor collection keys
mohamedsalem401 Dec 25, 2024
8c734e2
Cleanup collectionStateMap
mohamedsalem401 Dec 25, 2024
c6f4ad4
Only use 1 symbol to be used for each item in the collections
mohamedsalem401 Dec 25, 2024
8fc9481
Fix path for static datasource
mohamedsalem401 Dec 30, 2024
16f15b8
Merge branch 'dev' of https://github.com/GrapesJS/grapesjs into colle…
mohamedsalem401 Dec 30, 2024
9837116
Add collection variables
mohamedsalem401 Jan 3, 2025
721f7b0
Refactor dynamic component watcher
mohamedsalem401 Jan 3, 2025
c123c18
Refactor mehods for dynamic value watchers
mohamedsalem401 Jan 3, 2025
6aa7244
Bind watcher to component in the constructor
mohamedsalem401 Jan 3, 2025
369caed
Move ovveriding collection variables to component watcher
mohamedsalem401 Jan 3, 2025
54320d4
Add collection component stringfication
mohamedsalem401 Jan 3, 2025
fe4b09f
Refactor getting collection items
mohamedsalem401 Jan 3, 2025
c425c7e
Update collection items on datasource updates
mohamedsalem401 Jan 6, 2025
e50fe16
Console errors instead of raising errors for collection component
mohamedsalem401 Jan 6, 2025
bc3e65a
Refactor watch dynamic datasource
mohamedsalem401 Jan 6, 2025
e2d4bbe
Refactor CollectionStateVariableType
mohamedsalem401 Jan 6, 2025
33f3129
Fix zero end_index issue
mohamedsalem401 Jan 6, 2025
9c094dd
Collection tests
mohamedsalem401 Jan 6, 2025
d02852e
Don't Add collection symbols to the list of global symbols
mohamedsalem401 Jan 7, 2025
782549b
Refactor resolving collection items
mohamedsalem401 Jan 7, 2025
fcc8c45
Fix collection items traits
mohamedsalem401 Jan 7, 2025
4c6d1e6
Fix droppable for collection component
mohamedsalem401 Jan 7, 2025
6432a9c
Log error if no definition is passed to collection component
mohamedsalem401 Jan 7, 2025
7d967d2
Update tests for collection symbols
mohamedsalem401 Jan 7, 2025
5e472c9
Fix collection variables not listening correctly
mohamedsalem401 Jan 7, 2025
3f0588d
Refactor resolving collection variables
mohamedsalem401 Jan 7, 2025
aaa2481
Fix updating collection symbols overrides in runtime
mohamedsalem401 Jan 7, 2025
33da8bf
Refactor collectionsStateMap propagation
mohamedsalem401 Jan 8, 2025
29d983e
Fix collection items propagation
mohamedsalem401 Jan 8, 2025
5587e44
Refactor setting dynamic attributes
mohamedsalem401 Jan 8, 2025
d2078d2
Edit properties propagation logic
mohamedsalem401 Jan 8, 2025
fc01907
Fix Collection props and attributes propagation
mohamedsalem401 Jan 9, 2025
5bd74d5
Update collection attributes tests
mohamedsalem401 Jan 9, 2025
8c5800f
Update collection component serialization tests
mohamedsalem401 Jan 10, 2025
b7d2793
Fix falsy value being treated as undefined
mohamedsalem401 Jan 10, 2025
697c11a
Udpate tests for Diffirent Collection variable types
mohamedsalem401 Jan 10, 2025
407cc89
Add tests for saving and loading collection components
mohamedsalem401 Jan 10, 2025
7b0ca1f
Merge branch 'dev' of https://github.com/GrapesJS/grapesjs into colle…
mohamedsalem401 Jan 10, 2025
de7a712
Make collection items undraggable
mohamedsalem401 Jan 10, 2025
0167fce
Change collection component definition options to camel case
mohamedsalem401 Jan 14, 2025
a9fec3d
Refactor propagation of collection map state
mohamedsalem401 Jan 14, 2025
6710b8f
Refactor collection type
mohamedsalem401 Jan 14, 2025
550499e
Delete null assertion
mohamedsalem401 Jan 14, 2025
d4fe2c3
Replace types with interfaces
mohamedsalem401 Jan 15, 2025
b9ebb75
Refactor keyIsCollectionItem
mohamedsalem401 Jan 15, 2025
e6f4a6e
Add missing opts in setId method
mohamedsalem401 Jan 15, 2025
535eba0
Remove console.log
mohamedsalem401 Jan 15, 2025
a6bb3e9
Replace `content` property for collection component testing
mohamedsalem401 Jan 15, 2025
5851eec
Fix collection component serialization tests
mohamedsalem401 Jan 15, 2025
68707db
Rename collection to DataCollection
mohamedsalem401 Jan 15, 2025
19007fa
Add collection variable component
mohamedsalem401 Jan 16, 2025
fedde43
Exclude "components" property from being dynamic
mohamedsalem401 Jan 16, 2025
0aeef2d
Improve DataCollectionVariable serialization
mohamedsalem401 Jan 16, 2025
ea01b76
Fix logic for updating data collection variable
mohamedsalem401 Jan 16, 2025
c3cd2a0
Fix tests
mohamedsalem401 Jan 16, 2025
2ad06d1
Change collection definition properties
mohamedsalem401 Jan 16, 2025
4297f12
Add more tests for Collection variable components
mohamedsalem401 Jan 16, 2025
cf774bb
Format
mohamedsalem401 Jan 16, 2025
0a15b69
Fix lint
mohamedsalem401 Jan 16, 2025
49b25ff
Merge branch 'dev' of https://github.com/GrapesJS/grapesjs into colle…
mohamedsalem401 Jan 16, 2025
9847e0c
Refactor collectionStateMap propagation logic
mohamedsalem401 Jan 19, 2025
d293d59
Make collectionId a required field
mohamedsalem401 Jan 20, 2025
3d3e9e1
Tests for nested collection components
mohamedsalem401 Jan 20, 2025
d5c64ff
Cleanup
mohamedsalem401 Jan 20, 2025
3c6e72f
Cleanup
mohamedsalem401 Jan 20, 2025
374dbc4
Fix collection component symbols
mohamedsalem401 Jan 20, 2025
1f00f16
Add tests for adding and removing records
mohamedsalem401 Jan 21, 2025
39d6de8
Format
mohamedsalem401 Jan 21, 2025
979d035
Fix updating datasource
mohamedsalem401 Jan 21, 2025
e9b46e7
Fix nested symbols not working on collection component
mohamedsalem401 Jan 21, 2025
c3172a6
Fix syncing collection items for nested collections
mohamedsalem401 Jan 21, 2025
dc13e11
Refactor
mohamedsalem401 Jan 21, 2025
84d5aca
Fix issue on updating collection datasource
mohamedsalem401 Jan 28, 2025
a3a9cce
Fix datacollection variable view not updating correctly
mohamedsalem401 Jan 28, 2025
0cd443d
Fix issue after dragging and then cloning a collection variable
mohamedsalem401 Jan 29, 2025
45348ee
Fix tests
mohamedsalem401 Jan 29, 2025
59d1045
Merge branch 'dev' of https://github.com/GrapesJS/grapesjs into colle…
mohamedsalem401 Jan 29, 2025
8a4db7d
Add testing data collection component variable HTML element
mohamedsalem401 Jan 29, 2025
214f425
Update the logic for getComponentDef
mohamedsalem401 Jan 29, 2025
acbd15c
Fallback to keyCollectionDefinition if no collection items were found
mohamedsalem401 Jan 29, 2025
3f4d138
Add collection model/view check
artf Jan 30, 2025
aab824f
Fix updating records issue
mohamedsalem401 Jan 30, 2025
9040859
Refactoring
artf Jan 31, 2025
fb94416
Move data components view
artf Jan 31, 2025
bec5d23
Update DynamicVariableListenerManager
artf Jan 31, 2025
f60840c
Cleanup
artf Jan 31, 2025
7666ce3
Up DataCondition
artf Jan 31, 2025
cdba6ac
Small refactor
artf Jan 31, 2025
ea4a9a8
Refactor to data resolvers
artf Jan 31, 2025
414f9bb
Use dataResolverWatchers
artf Jan 31, 2025
dfb815c
Up ComponentDataCollection
artf Jan 31, 2025
f02a1e6
Up reset
artf Jan 31, 2025
ef2bbfb
Updata ComponentDataVariable
artf Feb 1, 2025
29c85e2
Up ComponentDataCollectionVariable
artf Feb 1, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion README.md
2 changes: 0 additions & 2 deletions packages/core/src/css_composer/model/CssRule.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@ import { isEmptyObj, hasWin } from '../../utils/mixins';
import Selector, { SelectorProps } from '../../selector_manager/model/Selector';
import EditorModel from '../../editor/model/Editor';
import CssRuleView from '../view/CssRuleView';
import DynamicVariableListenerManager from '../../data_sources/model/DataVariableListenerManager';

/** @private */
export interface CssRuleProperties {
Expand Down Expand Up @@ -95,7 +94,6 @@ export default class CssRule extends StyleableModel<CssRuleProperties> {
em?: EditorModel;
opt: any;
views: CssRuleView[] = [];
dynamicVariableListeners: Record<string, DynamicVariableListenerManager> = {};

defaults() {
return {
Expand Down
14 changes: 11 additions & 3 deletions packages/core/src/data_sources/model/ComponentDataVariable.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,11 @@
import Component from '../../dom_components/model/Component';
import { ComponentOptions } from '../../dom_components/model/types';
import { toLowerCase } from '../../utils/mixins';
import { DataVariableType } from './DataVariable';
import DataVariable, { DataVariableProps, DataVariableType } from './DataVariable';

export default class ComponentDataVariable extends Component {
dataResolver: DataVariable;

get defaults() {
return {
// @ts-ignore
Expand All @@ -13,9 +16,14 @@ export default class ComponentDataVariable extends Component {
};
}

constructor(props: DataVariableProps, opt: ComponentOptions) {
super(props, opt);
const { type, path, defaultValue } = props;
this.dataResolver = new DataVariable({ type, path, defaultValue }, opt);
}

getDataValue() {
const { path, defaultValue } = this.attributes;
return this.em.DataSources.getValue(path, defaultValue);
return this.dataResolver.getDataValue();
}

getInnerHTML() {
Expand Down
96 changes: 96 additions & 0 deletions packages/core/src/data_sources/model/DataResolverListener.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
import { DataSourcesEvents, DataSourceListener } from '../types';
import { stringToPath } from '../../utils/mixins';
import { Model } from '../../common';
import EditorModel from '../../editor/model/Editor';
import DataVariable, { DataVariableType } from './DataVariable';
import { DataResolver } from '../types';
import { DataCondition, DataConditionType } from './conditional_variables/DataCondition';
import { DataCollectionVariableType } from './data_collection/constants';
import DataCollectionVariable from './data_collection/DataCollectionVariable';

export interface DataResolverListenerProps {
em: EditorModel;
resolver: DataResolver;
onUpdate: (value: any) => void;
}

export default class DataResolverListener {
private listeners: DataSourceListener[] = [];
private em: EditorModel;
private onUpdate: (value: any) => void;
private model = new Model();
resolver: DataResolver;

constructor(props: DataResolverListenerProps) {
this.em = props.em;
this.resolver = props.resolver;
this.onUpdate = props.onUpdate;
this.listenToResolver();
}

private onChange = () => {
const value = this.resolver.getDataValue();
this.onUpdate(value);
};

listenToResolver() {
const { resolver, model } = this;
this.removeListeners();
let listeners: DataSourceListener[] = [];
const type = resolver.attributes.type;

switch (type) {
case DataCollectionVariableType:
listeners = this.listenToDataCollectionVariable(resolver as DataCollectionVariable);
break;
case DataVariableType:
listeners = this.listenToDataVariable(resolver as DataVariable);
break;
case DataConditionType:
listeners = this.listenToConditionalVariable(resolver as DataCondition);
break;
}

listeners.forEach((ls) => model.listenTo(ls.obj, ls.event, this.onChange));
this.listeners = listeners;
}

private listenToConditionalVariable(dataVariable: DataCondition) {
const { em } = this;
const dataListeners = dataVariable.getDependentDataVariables().flatMap((dataVariable) => {
return this.listenToDataVariable(new DataVariable(dataVariable, { em }));
});

return dataListeners;
}

private listenToDataVariable(dataVariable: DataVariable) {
const { em } = this;
const dataListeners: DataSourceListener[] = [];
const { path } = dataVariable.attributes;
const normPath = stringToPath(path || '').join('.');
const [ds, dr] = em.DataSources.fromPath(path!);
ds && dataListeners.push({ obj: ds.records, event: 'add remove reset' });
dr && dataListeners.push({ obj: dr, event: 'change' });
dataListeners.push(
{ obj: dataVariable, event: 'change:path change:defaultValue' },
{ obj: em.DataSources.all, event: 'add remove reset' },
{ obj: em, event: `${DataSourcesEvents.path}:${normPath}` },
);

return dataListeners;
}

private listenToDataCollectionVariable(dataVariable: DataCollectionVariable) {
return [{ obj: dataVariable, event: 'change:value' }];
}

private removeListeners() {
this.listeners.forEach((ls) => this.model.stopListening(ls.obj, ls.event, this.onChange));
this.listeners = [];
}

destroy() {
this.removeListeners();
}
}
2 changes: 1 addition & 1 deletion packages/core/src/data_sources/model/DataSource.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@

import { AddOptions, collectionEvents, CombinedModelConstructorOptions, Model, RemoveOptions } from '../../common';
import EditorModel from '../../editor/model/Editor';
import { DataSourceTransformers, DataSourceType, DataSourceProps, RecordPropsType, DataRecordProps } from '../types';
import { DataSourceTransformers, DataSourceType, DataSourceProps, DataRecordProps } from '../types';
import DataRecord from './DataRecord';
import DataRecords from './DataRecords';
import DataSources from './DataSources';
Expand Down
36 changes: 8 additions & 28 deletions packages/core/src/data_sources/model/DataVariable.ts
Original file line number Diff line number Diff line change
@@ -1,15 +1,15 @@
import { Model } from '../../common';
import EditorModel from '../../editor/model/Editor';
import { stringToPath } from '../../utils/mixins';

export const DataVariableType = 'data-variable';
export type DataVariableDefinition = {
export const DataVariableType = 'data-variable' as const;

export interface DataVariableProps {
type: typeof DataVariableType;
path: string;
defaultValue?: string;
};
}

export default class DataVariable extends Model {
export default class DataVariable extends Model<DataVariableProps> {
em?: EditorModel;

defaults() {
Expand All @@ -20,33 +20,13 @@ export default class DataVariable extends Model {
};
}

constructor(attrs: DataVariableDefinition, options: any) {
super(attrs, options);
constructor(props: DataVariableProps, options: { em?: EditorModel }) {
super(props, options);
this.em = options.em;
this.listenToDataSource();
}

listenToDataSource() {
const { path } = this.attributes;
const resolvedPath = stringToPath(path).join('.');

if (this.em) {
this.listenTo(this.em.DataSources, `change:${resolvedPath}`, this.onDataSourceChange);
}
}

onDataSourceChange() {
const newValue = this.getDataValue();
this.set({ value: newValue });
}

getDataValue() {
const { path, defaultValue } = this.attributes;
if (!this.em) {
throw new Error('EditorModel instance is not provided for a data variable.');
}
const val = this.em?.DataSources.getValue(path, defaultValue);

return val;
return this.em?.DataSources.getValue(path!, defaultValue);
}
}

This file was deleted.

9 changes: 0 additions & 9 deletions packages/core/src/data_sources/model/StyleDataVariable.ts

This file was deleted.

8 changes: 4 additions & 4 deletions packages/core/src/data_sources/model/TraitDataVariable.ts
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
import DataVariable, { DataVariableDefinition } from './DataVariable';
import DataVariable, { DataVariableProps } from './DataVariable';
import Trait from '../../trait_manager/model/Trait';
import { TraitProperties } from '../../trait_manager/types';

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

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

constructor(attrs: TraitDataVariableDefinition, options: any) {
super(attrs, options);
constructor(props: TraitDataVariableProps, options: any) {
super(props, options);
this.trait = options.trait;
}

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
import Component from '../../../dom_components/model/Component';
import { ComponentDefinition, ComponentOptions } from '../../../dom_components/model/types';
import { toLowerCase } from '../../../utils/mixins';
import { DataCondition, DataConditionProps, DataConditionType } from './DataCondition';

export default class ComponentDataCondition extends Component {
dataResolver: DataCondition;

constructor(props: DataConditionProps, opt: ComponentOptions) {
const { condition, ifTrue, ifFalse } = props;
const dataConditionInstance = new DataCondition(condition, ifTrue, ifFalse, { em: opt.em });
super(
{
...props,
type: DataConditionType,
components: dataConditionInstance.getDataValue(),
},
opt,
);
this.dataResolver = dataConditionInstance;
this.dataResolver.onValueChange = this.handleConditionChange.bind(this);
}

private handleConditionChange() {
this.dataResolver.reevaluate();
this.components(this.dataResolver.getDataValue());
}

static isComponent(el: HTMLElement) {
return toLowerCase(el.tagName) === DataConditionType;
}

toJSON(): ComponentDefinition {
return this.dataResolver.toJSON();
}
}
Loading