From e73f08fd1d78e6eddd944f2f592d63c598fff4fa Mon Sep 17 00:00:00 2001 From: Artur Arseniev Date: Sat, 22 Dec 2018 16:32:33 +0100 Subject: [PATCH 1/7] Add getTypes method and improve the parserHtml method --- src/dom_components/index.js | 46 +++++++++++++++++++++--------- src/parser/index.js | 4 ++- src/parser/model/ParserHtml.js | 11 +++++-- test/specs/dom_components/index.js | 18 +++++++++++- 4 files changed, 62 insertions(+), 17 deletions(-) diff --git a/src/dom_components/index.js b/src/dom_components/index.js index cc8f1cfe4..0914fb58f 100644 --- a/src/dom_components/index.js +++ b/src/dom_components/index.js @@ -20,6 +20,9 @@ * * [clear](#clear) * * [load](#load) * * [store](#store) + * * [addType](#addtype) + * * [getType](#gettype) + * * [getTypes](#gettypes) * * [render](#render) * * @module DomComponents @@ -506,9 +509,11 @@ module.exports = () => { }, /** - * Add new component type - * @param {string} type - * @param {Object} methods + * Add new component type. + * Read more about this in [Define New Component](https://grapesjs.com/docs/modules/Components.html#define-new-component) + * @param {string} type Component ID + * @param {Object} methods Component methods + * @return {this} */ addType(type, methods) { const compType = this.getType(type); @@ -519,15 +524,18 @@ module.exports = () => { // If the model/view is a simple object I need to extend it if (typeof model === 'object') { - methods.model = modelToExt.extend({ - ...model, - defaults: { - ...modelToExt.prototype.defaults, - ...(model.defaults || {}), + methods.model = modelToExt.extend( + { + ...model, + defaults: { + ...modelToExt.prototype.defaults, + ...(model.defaults || {}) + } }, - }, { - isComponent: isComponent || (() => 0), - }); + { + isComponent: isComponent || (() => 0) + } + ); } if (typeof view === 'object') { @@ -541,11 +549,15 @@ module.exports = () => { methods.id = type; componentTypes.unshift(methods); } + + return this; }, /** - * Get component type - * @param {string} type + * Get component type. + * Read more about this in [Define New Component](https://grapesjs.com/docs/modules/Components.html#define-new-component) + * @param {string} type Component ID + * @return {Object} Component type defintion, eg. `{ model: ..., view: ... }` */ getType(type) { var df = componentTypes; @@ -559,6 +571,14 @@ module.exports = () => { return; }, + /** + * Return the array of all types + * @return {Array} + */ + getTypes() { + return componentTypes; + }, + selectAdd(component, opts = {}) { if (component) { component.set({ diff --git a/src/parser/index.js b/src/parser/index.js index b45924300..6853cac00 100644 --- a/src/parser/index.js +++ b/src/parser/index.js @@ -47,6 +47,7 @@ module.exports = () => { conf.Parser = this; pHtml = new parserHtml(conf); pCss = new parserCss(conf); + this.em = conf.em; return this; }, @@ -56,7 +57,8 @@ module.exports = () => { * @return {Object} */ parseHtml(str) { - pHtml.compTypes = this.compTypes; + const { em, compTypes } = this; + pHtml.compTypes = em ? em.get('DomComponents').getTypes() : compTypes; return pHtml.parse(str, pCss); }, diff --git a/src/parser/model/ParserHtml.js b/src/parser/model/ParserHtml.js index 7c3937040..61d767fcc 100644 --- a/src/parser/model/ParserHtml.js +++ b/src/parser/model/ParserHtml.js @@ -81,8 +81,15 @@ module.exports = config => { // Iterate over all available Component Types and // the first with a valid result will be that component for (let it = 0; it < ct.length; it++) { - obj = ct[it].model.isComponent(node); - if (obj) break; + const compType = ct[it]; + obj = compType.model.isComponent(node); + + if (obj) { + if (typeof obj !== 'object') { + obj = { type: compType.id }; + } + break; + } } model = obj; diff --git a/test/specs/dom_components/index.js b/test/specs/dom_components/index.js index 474133b70..640c3638f 100644 --- a/test/specs/dom_components/index.js +++ b/test/specs/dom_components/index.js @@ -179,7 +179,7 @@ describe('DOM Components', () => { obj.addType(id, { model: { defaults: { - testProp, + testProp } } }); @@ -189,6 +189,22 @@ describe('DOM Components', () => { expect(comp.get('type')).toEqual(id); expect(comp.get('testProp')).toEqual(testProp); }); + + test('Add new component type with custom isComponent', () => { + obj = em.get('DomComponents'); + const id = 'test-type'; + const testProp = 'testValue'; + obj.addType(id, { + isComponent: el => { + return el.getAttribute('test-prop') === testProp; + } + }); + expect(obj.componentTypes[0].id).toEqual(id); + obj.addComponent(`
`); + const comp = obj.getComponents().at(0); + expect(comp.get('type')).toEqual(id); + expect(comp.getAttributes()['test-prop']).toEqual(testProp); + }); }); ComponentModels.run(); From 8422aa1dbaa631973df23fd442ea652b4c84f710 Mon Sep 17 00:00:00 2001 From: Artur Arseniev Date: Sat, 22 Dec 2018 18:56:11 +0100 Subject: [PATCH 2/7] Allow to extend model and view in addType --- src/dom_components/index.js | 20 ++++++++++++--- test/specs/dom_components/index.js | 41 ++++++++++++++++++++++++++++++ 2 files changed, 58 insertions(+), 3 deletions(-) diff --git a/src/dom_components/index.js b/src/dom_components/index.js index 0914fb58f..c84172984 100644 --- a/src/dom_components/index.js +++ b/src/dom_components/index.js @@ -516,11 +516,25 @@ module.exports = () => { * @return {this} */ addType(type, methods) { + const { + model = {}, + view = {}, + isComponent, + extend, + extendView + } = methods; const compType = this.getType(type); - const typeToExtend = compType ? compType : this.getType('default'); + const extendType = this.getType(extend); + const extendViewType = this.getType(extendView); + const typeToExtend = extendType + ? extendType + : compType + ? compType + : this.getType('default'); const modelToExt = typeToExtend.model; - const viewToExt = typeToExtend.view; - const { model = {}, view = {}, isComponent } = methods; + const viewToExt = extendViewType + ? extendViewType.view + : typeToExtend.view; // If the model/view is a simple object I need to extend it if (typeof model === 'object') { diff --git a/test/specs/dom_components/index.js b/test/specs/dom_components/index.js index 640c3638f..cfabd6b02 100644 --- a/test/specs/dom_components/index.js +++ b/test/specs/dom_components/index.js @@ -205,6 +205,47 @@ describe('DOM Components', () => { expect(comp.get('type')).toEqual(id); expect(comp.getAttributes()['test-prop']).toEqual(testProp); }); + + test('Extend component type with custom model and view', () => { + obj = em.get('DomComponents'); + const id = 'text'; + const testProp = 'testValue'; + const testText = 'Some text'; + const initialTypes = obj.getTypes().length; + obj.addType('text', { + model: { + defaults: { + testProp + } + }, + view: { + onRender() { + this.el.style.backgroundColor = 'red'; + } + } + }); + expect(obj.getTypes().length).toBe(initialTypes); + obj.addComponent(`
${testText}
`); + const comp = obj.getComponents().at(0); + expect(comp.get('type')).toBe(id); + expect(comp.get('testProp')).toBe(testProp); + expect(comp.get('editable')).toBe(true); + }); + + test('Add new component type by extending another one', () => { + obj = em.get('DomComponents'); + const id = 'test-type'; + const testProp = 'testValue'; + obj.addType(id, { + extend: 'text', + isComponent: el => el.getAttribute('test-prop') === testProp + }); + obj.addComponent(`
`); + expect(obj.getTypes()[0].id).toEqual(id); + const comp = obj.getComponents().at(0); + expect(comp.get('type')).toBe(id); + expect(comp.get('editable')).toBe(true); + }); }); ComponentModels.run(); From 71996a7e445c80be800dd80a94fd33c3d32f0824 Mon Sep 17 00:00:00 2001 From: Artur Arseniev Date: Sat, 22 Dec 2018 19:00:01 +0100 Subject: [PATCH 3/7] Stylistic update in addType --- test/specs/dom_components/index.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/specs/dom_components/index.js b/test/specs/dom_components/index.js index cfabd6b02..6f6e29aff 100644 --- a/test/specs/dom_components/index.js +++ b/test/specs/dom_components/index.js @@ -9,7 +9,7 @@ const Editor = require('editor/model/Editor'); const utils = require('./../test_utils.js'); describe('DOM Components', () => { - describe.only('Main', () => { + describe('Main', () => { var em; var obj; var config; From 44a9e00b76835ab4d952842461ac08d7a00c26dd Mon Sep 17 00:00:00 2001 From: Artur Arseniev Date: Sun, 23 Dec 2018 13:54:01 +0100 Subject: [PATCH 4/7] Add default attributes in the creation of new components --- src/dom_components/model/Component.js | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/dom_components/model/Component.js b/src/dom_components/model/Component.js index 39bd3c8a0..8d4036126 100644 --- a/src/dom_components/model/Component.js +++ b/src/dom_components/model/Component.js @@ -170,7 +170,10 @@ const Component = Backbone.Model.extend(Styleable).extend( this.em = em; this.config = opt.config || {}; this.ccid = Component.createId(this); - this.set('attributes', this.get('attributes') || {}); + this.set('attributes', { + ...(this.defaults.attributes || {}), + ...(this.get('attributes') || {}) + }); this.initClasses(); this.initTraits(); this.initComponents(); From fea303e7afe4a83f3556691a71ce952d5db1d7ee Mon Sep 17 00:00:00 2001 From: Artur Arseniev Date: Sun, 23 Dec 2018 14:19:19 +0100 Subject: [PATCH 5/7] Emit `component:clone` event on the component which was cloned --- src/dom_components/model/Component.js | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/dom_components/model/Component.js b/src/dom_components/model/Component.js index 8d4036126..068e8fb20 100644 --- a/src/dom_components/model/Component.js +++ b/src/dom_components/model/Component.js @@ -730,7 +730,9 @@ const Component = Backbone.Model.extend(Styleable).extend( } const cloned = new this.constructor(attr, opts); - em && em.trigger('component:clone', cloned); + const event = 'component:clone'; + em && em.trigger(event, cloned); + this.trigger(event, cloned); return cloned; }, From d32ca0cec6cb14ac9178aeee9026310e2fa900e1 Mon Sep 17 00:00:00 2001 From: Artur Arseniev Date: Mon, 24 Dec 2018 17:43:33 +0100 Subject: [PATCH 6/7] Clear old attributes in updateAttributes --- src/dom_components/view/ComponentView.js | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/src/dom_components/view/ComponentView.js b/src/dom_components/view/ComponentView.js index 1dd8e5540..efd76bcbf 100644 --- a/src/dom_components/view/ComponentView.js +++ b/src/dom_components/view/ComponentView.js @@ -1,5 +1,5 @@ import Backbone from 'backbone'; -import { isArray, isEmpty } from 'underscore'; +import { isArray, isEmpty, each, keys } from 'underscore'; const Components = require('../model/Components'); const ComponentsView = require('./ComponentsView'); @@ -232,17 +232,26 @@ module.exports = Backbone.View.extend({ * @private * */ updateAttributes() { - const model = this.model; + const attrs = []; + const { model, $el, el } = this; const defaultAttr = { 'data-gjs-type': model.get('type') || 'default' }; if (model.get('highlightable')) { defaultAttr['data-highlightable'] = 1; } - this.$el.attr({ + // Remove all current attributes + each(el.attributes, attr => attrs.push(attr.nodeName)); + attrs.forEach(attr => $el.removeAttr(attr)); + const attr = { ...defaultAttr, ...model.getAttributes() - }); + }; + + // Remove all `false` attributes + keys(attr).forEach(key => attr[key] === false && delete attr[key]); + + $el.attr(attr); this.updateStyle(); }, From f1bf0a014dc3eb4b9f1278c12c92a51ae7cc1281 Mon Sep 17 00:00:00 2001 From: Artur Arseniev Date: Wed, 26 Dec 2018 14:41:39 +0100 Subject: [PATCH 7/7] Update ComponentLinkView --- src/dom_components/view/ComponentLinkView.js | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/dom_components/view/ComponentLinkView.js b/src/dom_components/view/ComponentLinkView.js index 3c6dbcaec..09a921441 100644 --- a/src/dom_components/view/ComponentLinkView.js +++ b/src/dom_components/view/ComponentLinkView.js @@ -1,5 +1,4 @@ -var Backbone = require('backbone'); -var ComponentView = require('./ComponentTextView'); +const ComponentView = require('./ComponentTextView'); module.exports = ComponentView.extend({ render(...args) {