Browse Source

Add `setAttributes`, `getAttributes`, `setClass` and `addClass` to Component

pull/437/head
Artur Arseniev 9 years ago
parent
commit
f87e924ce5
  1. 70
      src/dom_components/model/Component.js
  2. 6
      src/dom_components/model/ComponentText.js
  3. 9
      src/dom_components/view/ComponentTextView.js
  4. 10
      src/domain_abstract/model/Styleable.js
  5. 29
      src/selector_manager/index.js
  6. 74
      test/specs/dom_components/model/Component.js
  7. 31
      test/specs/selector_manager/index.js

70
src/dom_components/model/Component.js

@ -69,7 +69,7 @@ module.exports = Backbone.Model.extend(Styleable).extend({
icon: '', icon: '',
// Component related style // Component related style
style: {}, style: '',
// Key-value object of the component's attributes // Key-value object of the component's attributes
attributes: '', attributes: '',
@ -98,7 +98,7 @@ module.exports = Backbone.Model.extend(Styleable).extend({
}, },
initialize(props = {}, opt = {}) { initialize(props = {}, opt = {}) {
const em = opt.sm || {}; const em = opt.sm || opt.em || {};
// Check void elements // Check void elements
if(opt && opt.config && if(opt && opt.config &&
@ -108,6 +108,7 @@ module.exports = Backbone.Model.extend(Styleable).extend({
this.opt = opt; this.opt = opt;
this.sm = em; this.sm = em;
this.em = em;
this.config = props; this.config = props;
this.set('attributes', this.get('attributes') || {}); this.set('attributes', this.get('attributes') || {});
this.listenTo(this, 'change:script', this.scriptUpdated); this.listenTo(this, 'change:script', this.scriptUpdated);
@ -132,6 +133,71 @@ module.exports = Backbone.Model.extend(Styleable).extend({
this.init(); this.init();
}, },
/**
* Update attributes of the model
* @param {Object} attrs Key value attributes
* @example
* model.setAttributes({id: 'test', 'data-key': 'value'});
*/
setAttributes(attrs) {
attrs = { ...attrs };
// Handle classes
const classes = attrs.class;
classes && this.setClass(classes);
delete attrs.class;
// Handle style
const style = attrs.style;
style && this.setStyle(style);
delete attrs.style;
this.set('attributes', attrs);
},
/**
* Return attributes
* @return {Object}
*/
getAttributes() {
return this.get('attributes');
},
/**
* Add classes
* @param {Array|string} classes Array or string of classes
* @return {Array} Array of added selectors
* @example
* model.addClass('class1');
* model.addClass('class1 class2');
* model.addClass(['class1', 'class2']);
* // -> [SelectorObject, ...]
*/
addClass(classes) {
const added = this.em.get('SelectorManager').addClass(classes);
return this.get('classes').add(added);
},
/**
* Set classes (resets current collection)
* @param {Array|string} classes Array or string of classes
* @return {Array} Array of added selectors
* @example
* model.setClass('class1');
* model.setClass('class1 class2');
* model.setClass(['class1', 'class2']);
* // -> [SelectorObject, ...]
*/
setClass(classes) {
this.get('classes').reset();
return this.addClass(classes);
},
initClasses() { initClasses() {
const classes = this.normalizeClasses(this.get('classes') || this.config.classes || []); const classes = this.normalizeClasses(this.get('classes') || this.config.classes || []);
this.set('classes', new Selectors(classes)); this.set('classes', new Selectors(classes));

6
src/dom_components/model/ComponentText.js

@ -1,11 +1,11 @@
var Component = require('./Component'); const Component = require('./Component');
module.exports = Component.extend({ module.exports = Component.extend({
defaults: _.extend({}, Component.prototype.defaults, { defaults: { ...Component.prototype.defaults,
type: 'text', type: 'text',
droppable: false, droppable: false,
editable: true, editable: true,
}), },
}); });

9
src/dom_components/view/ComponentTextView.js

@ -23,14 +23,13 @@ module.exports = ComponentView.extend({
* @private * @private
* */ * */
enableEditing() { enableEditing() {
if (this.rteEnabled) { const rte = this.rte;
if (this.rteEnabled || !this.model.get('editable')) {
return; return;
} }
const editable = this.model.get('editable'); if (rte) {
const rte = this.rte;
if (rte && editable) {
try { try {
this.activeRte = rte.enable(this, this.activeRte); this.activeRte = rte.enable(this, this.activeRte);
} catch (err) { } catch (err) {

10
src/domain_abstract/model/Styleable.js

@ -1,3 +1,7 @@
import { isString } from 'underscore';
import ParserHtml from 'parser/model/ParserHtml';
const parseStyle = ParserHtml().parseStyle;
export default { export default {
/** /**
@ -20,10 +24,14 @@ export default {
/** /**
* Set new style object * Set new style object
* @param {Object} prop * @param {Object|string} prop
* @param {Object} opts * @param {Object} opts
*/ */
setStyle(prop = {}, opts = {}) { setStyle(prop = {}, opts = {}) {
if (isString(prop)) {
prop = parseStyle(prop);
}
this.set('style', Object.assign({}, prop), opts); this.set('style', Object.assign({}, prop), opts);
}, },

29
src/selector_manager/index.js

@ -1,8 +1,4 @@
/** /**
* * [add](#add)
* * [get](#get)
* * [getAll](#getall)
*
* Selectors in GrapesJS are used in CSS Composer inside Rules and in Components as classes. To get better this concept let's take * Selectors in GrapesJS are used in CSS Composer inside Rules and in Components as classes. To get better this concept let's take
* a look at this code: * a look at this code:
* *
@ -52,6 +48,9 @@
* statesLabel: '- Selecte State -', * statesLabel: '- Selecte State -',
* } * }
*/ */
import { isString } from 'underscore'
module.exports = config => { module.exports = config => {
var c = config || {}, var c = config || {},
defaults = require('./config/config'), defaults = require('./config/config'),
@ -139,6 +138,28 @@ module.exports = config => {
return selector; return selector;
}, },
/**
* Add class selectors
* @param {Array|string} classes Array or string of classes
* @return {Array} Array of added selectors
* @example
* sm.addClass('class1');
* sm.addClass('class1 class2');
* sm.addClass(['class1', 'class2']);
* // -> [SelectorObject, ...]
*/
addClass(classes) {
const added = [];
if (isString(classes)) {
classes = classes.trim().split(' ');
}
classes.forEach(name => added.push(selectors.add({name})))
return added;
},
/** /**
* Get the selector by its name * Get the selector by its name
* @param {String} name Selector name * @param {String} name Selector name

74
test/specs/dom_components/model/Component.js

@ -6,18 +6,22 @@ const ComponentLink = require('dom_components/model/ComponentLink');
const ComponentMap = require('dom_components/model/ComponentMap'); const ComponentMap = require('dom_components/model/ComponentMap');
const ComponentVideo = require('dom_components/model/ComponentVideo'); const ComponentVideo = require('dom_components/model/ComponentVideo');
const Components = require('dom_components/model/Components'); const Components = require('dom_components/model/Components');
const Selector = require('selector_manager/model/Selector');
const Editor = require('editor/model/Editor');
const $ = Backbone.$; const $ = Backbone.$;
module.exports = { module.exports = {
run() { run() {
var obj; let obj;
var dcomp; let dcomp;
var compOpts; let compOpts;
let em;
describe('Component', () => { describe('Component', () => {
beforeEach(() => { beforeEach(() => {
obj = new Component(); em = new Editor({});
obj = new Component({}, {em});
dcomp = new DomComponents(); dcomp = new DomComponents();
compOpts = { compOpts = {
componentTypes: dcomp.componentTypes, componentTypes: dcomp.componentTypes,
@ -116,6 +120,68 @@ module.exports = {
expect(obj).toEqual({tagName: 'span'}); expect(obj).toEqual({tagName: 'span'});
}); });
it('setClass single class string', () => {
obj.setClass('class1');
const result = obj.get('classes').models;
expect(result.length).toEqual(1);
expect(result[0] instanceof Selector).toEqual(true);
expect(result[0].get('name')).toEqual('class1');
});
it('setClass multiple class string', () => {
obj.setClass('class1 class2');
const result = obj.get('classes').models;
expect(result.length).toEqual(2);
});
it('setClass single class array', () => {
obj.setClass(['class1']);
const result = obj.get('classes').models;
expect(result.length).toEqual(1);
});
it('setClass multiple class array', () => {
obj.setClass(['class1', 'class2']);
const result = obj.get('classes').models;
expect(result.length).toEqual(2);
});
it('addClass multiple array', () => {
obj.addClass(['class1', 'class2']);
const result = obj.get('classes').models;
expect(result.length).toEqual(2);
});
it('addClass avoid same name classes', () => {
obj.addClass(['class1', 'class2']);
obj.addClass(['class1', 'class3']);
const result = obj.get('classes').models;
expect(result.length).toEqual(3);
});
it('setAttributes', () => {
obj.setAttributes({
id: 'test',
'data-test': 'value',
class: 'class1 class2',
style: 'color: white; background: #fff'
});
expect(obj.getAttributes()).toEqual({
id: 'test',
'data-test': 'value',
});
expect(obj.get('classes').length).toEqual(2);
expect(obj.getStyle()).toEqual({
color: 'white',
background: '#fff',
});
});
it('setAttributes overwrites correctly', () => {
obj.setAttributes({id: 'test', 'data-test': 'value'});
obj.setAttributes({'data-test': 'value2'});
expect(obj.getAttributes()).toEqual({'data-test': 'value2'});
});
}); });
describe('Image Component', () => { describe('Image Component', () => {

31
test/specs/selector_manager/index.js

@ -1,4 +1,5 @@
var SelectorManager = require('selector_manager'); var SelectorManager = require('selector_manager');
var Selector = require('selector_manager/model/Selector');
var Models = require('./model/SelectorModels'); var Models = require('./model/SelectorModels');
var ClassTagView = require('./view/ClassTagView'); var ClassTagView = require('./view/ClassTagView');
var ClassTagsView = require('./view/ClassTagsView'); var ClassTagsView = require('./view/ClassTagsView');
@ -75,6 +76,36 @@ describe('SelectorManager', () => {
expect(obj.get('test')).toEqual(undefined); expect(obj.get('test')).toEqual(undefined);
}); });
it('addClass single class string', () => {
const result = obj.addClass('class1');
expect(result.length).toEqual(1);
expect(result[0] instanceof Selector).toEqual(true);
expect(result[0].get('name')).toEqual('class1');
});
it('addClass multiple class string', () => {
const result = obj.addClass('class1 class2');
expect(result.length).toEqual(2);
expect(obj.getAll().length).toEqual(2);
});
it('addClass single class array', () => {
const result = obj.addClass(['class1']);
expect(result.length).toEqual(1);
});
it('addClass multiple class array', () => {
const result = obj.addClass(['class1', 'class2']);
expect(result.length).toEqual(2);
});
it('addClass Avoid same name classes', () => {
obj.addClass('class1');
const result = obj.addClass('class1');
expect(obj.getAll().length).toEqual(1);
expect(result.length).toEqual(1);
});
}); });
Models.run(); Models.run();

Loading…
Cancel
Save