Browse Source

Merge branch 'improve-component-api' into dev

pull/1705/head
Artur Arseniev 7 years ago
parent
commit
3b034c45ac
  1. 66
      src/dom_components/index.js
  2. 9
      src/dom_components/model/Component.js
  3. 3
      src/dom_components/view/ComponentLinkView.js
  4. 17
      src/dom_components/view/ComponentView.js
  5. 4
      src/parser/index.js
  6. 11
      src/parser/model/ParserHtml.js
  7. 61
      test/specs/dom_components/index.js

66
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,28 +509,47 @@ 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 {
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') {
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 +563,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 +585,14 @@ module.exports = () => {
return;
},
/**
* Return the array of all types
* @return {Array}
*/
getTypes() {
return componentTypes;
},
selectAdd(component, opts = {}) {
if (component) {
component.set({

9
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();
@ -727,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;
},

3
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) {

17
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();
},

4
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);
},

11
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;

61
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;
@ -179,7 +179,7 @@ describe('DOM Components', () => {
obj.addType(id, {
model: {
defaults: {
testProp,
testProp
}
}
});
@ -189,6 +189,63 @@ 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(`<div test-prop="${testProp}"></div>`);
const comp = obj.getComponents().at(0);
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(`<div>${testText}</div>`);
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(`<div test-prop="${testProp}"></div>`);
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();

Loading…
Cancel
Save