diff --git a/src/dom_components/model/Component.ts b/src/dom_components/model/Component.ts index 6aabc0d74..d97f67652 100644 --- a/src/dom_components/model/Component.ts +++ b/src/dom_components/model/Component.ts @@ -882,15 +882,21 @@ export default class Component extends StyleableModel { this.off(event, this.initTraits); this.__loadTraits(); const attrs = { ...this.get('attributes') }; + const traitDataVariableAttr: ObjectAny = {}; const traits = this.traits; traits.each((trait) => { if (!trait.changeProp) { const name = trait.getName(); const value = trait.getInitValue(); + if (trait.dataVariable) { + traitDataVariableAttr[name] = trait.dataVariable; + } if (name && value) attrs[name] = value; } }); traits.length && this.set('attributes', attrs); + // store the trait data-variable attributes outside the attributes object so you can load a project with data-variable attributes + Object.keys(traitDataVariableAttr).length && this.set('attributes-data-variable', traitDataVariableAttr); this.on(event, this.initTraits); changed && em && em.trigger('component:toggled'); return this; diff --git a/test/specs/data_sources/__snapshots__/serialization.ts.snap b/test/specs/data_sources/__snapshots__/serialization.ts.snap new file mode 100644 index 000000000..915b90232 --- /dev/null +++ b/test/specs/data_sources/__snapshots__/serialization.ts.snap @@ -0,0 +1,164 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`DataSource Serialization .getProjectData ComponentDataVariable 1`] = ` +{ + "assets": [], + "pages": [ + { + "frames": [ + { + "component": { + "components": [ + { + "components": [ + { + "path": "component-serialization.id1.content", + "type": "data-variable", + "value": "default", + }, + ], + "tagName": "h1", + "type": "text", + }, + ], + "docEl": { + "tagName": "html", + }, + "head": { + "type": "head", + }, + "stylable": [ + "background", + "background-color", + "background-image", + "background-repeat", + "background-attachment", + "background-position", + "background-size", + ], + "type": "wrapper", + }, + "id": "data-variable-id", + }, + ], + "id": "data-variable-id", + "type": "main", + }, + ], + "styles": [], + "symbols": [], +} +`; + +exports[`DataSource Serialization .getProjectData StyleDataVariable 1`] = ` +{ + "assets": [], + "pages": [ + { + "frames": [ + { + "component": { + "components": [ + { + "attributes": { + "id": "data-variable-id", + }, + "content": "Hello World", + "tagName": "h1", + "type": "text", + }, + ], + "docEl": { + "tagName": "html", + }, + "head": { + "type": "head", + }, + "stylable": [ + "background", + "background-color", + "background-image", + "background-repeat", + "background-attachment", + "background-position", + "background-size", + ], + "type": "wrapper", + }, + "id": "data-variable-id", + }, + ], + "id": "data-variable-id", + "type": "main", + }, + ], + "styles": [ + { + "selectors": [ + "data-variable-id", + ], + "style": { + "color": { + "path": "colors-data.id1.color", + "type": "data-variable", + "value": "black", + }, + }, + }, + ], + "symbols": [], +} +`; + +exports[`DataSource Serialization .getProjectData TraitDataVariable 1`] = ` +{ + "assets": [], + "pages": [ + { + "frames": [ + { + "component": { + "components": [ + { + "attributes": { + "value": "test-value", + }, + "attributes-data-variable": { + "value": { + "path": "test-input.id1.value", + "type": "data-variable", + "value": "default", + }, + }, + "tagName": "input", + "void": true, + }, + ], + "docEl": { + "tagName": "html", + }, + "head": { + "type": "head", + }, + "stylable": [ + "background", + "background-color", + "background-image", + "background-repeat", + "background-attachment", + "background-position", + "background-size", + ], + "type": "wrapper", + }, + "id": "data-variable-id", + }, + ], + "id": "data-variable-id", + "type": "main", + }, + ], + "styles": [], + "symbols": [], +} +`; diff --git a/test/specs/data_sources/serialization.ts b/test/specs/data_sources/serialization.ts index 84214975b..9f83e0f5a 100644 --- a/test/specs/data_sources/serialization.ts +++ b/test/specs/data_sources/serialization.ts @@ -1,11 +1,45 @@ -import Editor from '../../../src/editor/model/Editor'; +import Editor from '../../../src/editor'; import DataSourceManager from '../../../src/data_sources'; import { DataSourceProps } from '../../../src/data_sources/types'; import ComponentWrapper from '../../../src/dom_components/model/ComponentWrapper'; import { DataVariableType } from '../../../src/data_sources/model/DataVariable'; +import EditorModel from '../../../src/editor/model/Editor'; + +// Filter out the unique ids and selectors replaced with 'data-variable-id' +// Makes the snapshot more stable +function filterObjectForSnapshot(obj: any, parentKey: string = ''): any { + const result: any = {}; + + for (const key in obj) { + if (key === 'id') { + result[key] = 'data-variable-id'; + continue; + } + + if (key === 'selectors') { + result[key] = obj[key].map(() => 'data-variable-id'); + continue; + } + + if (typeof obj[key] === 'object' && obj[key] !== null) { + if (Array.isArray(obj[key])) { + result[key] = obj[key].map((item: any) => + typeof item === 'object' ? filterObjectForSnapshot(item, key) : item, + ); + } else { + result[key] = filterObjectForSnapshot(obj[key], key); + } + } else { + result[key] = obj[key]; + } + } + + return result; +} describe('DataSource Serialization', () => { - let em: Editor; + let editor: Editor; + let em: EditorModel; let dsm: DataSourceManager; let fixtures: HTMLElement; let cmpRoot: ComponentWrapper; @@ -18,10 +52,11 @@ describe('DataSource Serialization', () => { }; beforeEach(() => { - em = new Editor({ + editor = new Editor({ mediaCondition: 'max-width', avoidInlineStyle: true, }); + em = editor.getModel(); dsm = em.DataSources; document.body.innerHTML = '
'; const { Pages, Components } = em; @@ -61,4 +96,116 @@ describe('DataSource Serialization', () => { const html = em.getHtml(); expect(html).toMatchInlineSnapshot('"

Hello World

"'); }); + + // DataSources TODO + test.todo('component .getCss'); + + // DataSources TODO + test.todo('component .getJs'); + + describe('.getProjectData', () => { + test('ComponentDataVariable', () => { + const dataVariable = { + type: DataVariableType, + value: 'default', + path: `${datasource.id}.id1.content`, + }; + + cmpRoot.append({ + tagName: 'h1', + type: 'text', + components: [dataVariable], + })[0]; + + const projectData = editor.getProjectData(); + const page = projectData.pages[0]; + const frame = page.frames[0]; + const component = frame.component.components[0]; + expect(component.components[0]).toEqual(dataVariable); + + const snapshot = filterObjectForSnapshot(projectData); + expect(snapshot).toMatchSnapshot(``); + }); + + test('StyleDataVariable', () => { + const styleDataSource: DataSourceProps = { + id: 'colors-data', + records: [{ id: 'id1', color: 'red' }], + }; + dsm.add(styleDataSource); + + const dataVariable = { + type: DataVariableType, + value: 'black', + path: 'colors-data.id1.color', + }; + + cmpRoot.append({ + tagName: 'h1', + type: 'text', + content: 'Hello World', + style: { + color: dataVariable, + }, + })[0]; + + const projectData = editor.getProjectData(); + const page = projectData.pages[0]; + const frame = page.frames[0]; + const component = frame.component.components[0]; + const componentId = component.attributes.id; + expect(componentId).toBeDefined(); + + const styleSelector = projectData.styles.find((style: any) => style.selectors[0] === `#${componentId}`); + expect(styleSelector.style).toEqual({ + color: dataVariable, + }); + + const snapshot = filterObjectForSnapshot(projectData); + expect(snapshot).toMatchSnapshot(``); + }); + + test('TraitDataVariable', () => { + const record = { id: 'id1', value: 'test-value' }; + const inputDataSource: DataSourceProps = { + id: 'test-input', + records: [record], + }; + dsm.add(inputDataSource); + + const dataVariable = { + type: DataVariableType, + value: 'default', + path: `${inputDataSource.id}.id1.value`, + }; + + cmpRoot.append({ + tagName: 'input', + traits: [ + 'name', + { + type: 'text', + label: 'Value', + name: 'value', + value: dataVariable, + }, + ], + })[0]; + + const projectData = editor.getProjectData(); + const page = projectData.pages[0]; + const frame = page.frames[0]; + const component = frame.component.components[0]; + expect(component).toHaveProperty('attributes-data-variable'); + expect(component['attributes-data-variable']).toEqual({ + value: dataVariable, + }); + expect(component.attributes).toEqual({ + value: record.value, + }); + + const snapshot = filterObjectForSnapshot(projectData); + expect(snapshot).toMatchSnapshot(``); + }); + }); });