diff --git a/src/css_composer/index.js b/src/css_composer/index.js index be8e9808a..b7323972e 100644 --- a/src/css_composer/index.js +++ b/src/css_composer/index.js @@ -382,6 +382,28 @@ module.exports = () => { return selector && this.get(selector, state, media); }, + setRule(selectors, style, opts = {}) { + const node = em.get('Parser').parserCss.checkNode({ + selectors, + style, + atRule: null, + params: null + })[0]; + const sm = em.get('SelectorManager'); + const selector = sm.add(node.selectors); + const rule = this.add(selector, node.state); + rule.setStyle(style, opts); + throw rule.toCSS(); + return rule; + }, + + getRule(selectors, opts = {}) { + const sm = em.get('SelectorManager'); + const node = em.get('Parser').parserCss.checkNode({ selectors })[0]; + const selector = sm.get(node.selectors); + return selector && this.get(selector, node.state); + }, + /** * Render the block of CSS rules * @return {HTMLElement} diff --git a/src/parser/index.js b/src/parser/index.js index 6853cac00..5b6663d01 100644 --- a/src/parser/index.js +++ b/src/parser/index.js @@ -48,6 +48,8 @@ module.exports = () => { pHtml = new parserHtml(conf); pCss = new parserCss(conf); this.em = conf.em; + this.parserCss = pCss; + this.parserHtml = pHtml; return this; }, diff --git a/src/parser/model/BrowserParserCss.js b/src/parser/model/BrowserParserCss.js index 4acd59b29..abf56291b 100644 --- a/src/parser/model/BrowserParserCss.js +++ b/src/parser/model/BrowserParserCss.js @@ -101,7 +101,7 @@ export const parseCondition = node => { * @param {Object} style Key-value object of style declarations * @return {Object} */ -export const createNode = (selectors, style, opts = {}) => { +export const createNode = (selectors, style = {}, opts = {}) => { const node = {}; const selLen = selectors.length; const lastClass = selectors[selLen - 1]; diff --git a/src/selector_manager/index.js b/src/selector_manager/index.js index d524eef33..13dccf17c 100644 --- a/src/selector_manager/index.js +++ b/src/selector_manager/index.js @@ -44,7 +44,7 @@ * @module SelectorManager */ -import { isString, isElement, isObject } from 'underscore'; +import { isString, isElement, isObject, isArray } from 'underscore'; const isId = str => isString(str) && str[0] == '#'; const isClass = str => isString(str) && str[0] == '.'; @@ -118,22 +118,9 @@ module.exports = config => { } }, - /** - * Add a new selector to collection if it's not already exists. Class type is a default one - * @param {String} name Selector name - * @param {Object} opts Selector options - * @param {String} [opts.label=''] Label for the selector, if it's not provided the label will be the same as the name - * @param {String} [opts.type=1] Type of the selector. At the moment, only 'class' (1) is available - * @return {Model} - * @example - * var selector = selectorManager.add('selectorName'); - * // Same as - * var selector = selectorManager.add('selectorName', { - * type: 1, - * label: 'selectorName' - * }); - * */ - add(name, opts = {}) { + addSelector(name, opt = {}) { + let opts = { ...opt }; + if (isObject(name)) { opts = name; } else { @@ -143,6 +130,8 @@ module.exports = config => { if (isId(opts.name)) { opts.name = opts.name.substr(1); opts.type = Selector.TYPE_ID; + } else if (isClass(opts.name)) { + opts.name = opts.name.substr(1); } if (opts.label && !opts.name) { @@ -161,6 +150,31 @@ module.exports = config => { return selector; }, + /** + * Add a new selector to collection if it's not already exists. Class type is a default one + * @param {String|Array} name Selector/s name + * @param {Object} opts Selector options + * @param {String} [opts.label=''] Label for the selector, if it's not provided the label will be the same as the name + * @param {String} [opts.type=1] Type of the selector. At the moment, only 'class' (1) is available + * @return {Model|Array} + * @example + * const selector = selectorManager.add('selectorName'); + * // Same as + * const selector = selectorManager.add('selectorName', { + * type: 1, + * label: 'selectorName' + * }); + * // Multiple selectors + * const selectors = selectorManager.add(['.class1', '.class2', '#id1']); + * */ + add(name, opts = {}) { + if (isArray(name)) { + return name.map(item => this.addSelector(item, opts)); + } else { + return this.addSelector(name, opts); + } + }, + /** * Add class selectors * @param {Array|string} classes Array or string of classes @@ -178,7 +192,14 @@ module.exports = config => { classes = classes.trim().split(' '); } - classes.forEach(name => added.push(selectors.add({ name }))); + classes.forEach(name => + added.push( + selectors.add({ + name, + type: Selector.TYPE_ID + }) + ) + ); return added; }, diff --git a/src/selector_manager/model/Selectors.js b/src/selector_manager/model/Selectors.js index a3a800b7a..f8ae05e9c 100644 --- a/src/selector_manager/model/Selectors.js +++ b/src/selector_manager/model/Selectors.js @@ -4,6 +4,8 @@ const Selector = require('./Selector'); module.exports = require('backbone').Collection.extend({ model: Selector, + modelId: attr => `${attr.name}_${attr.type}`, + getStyleable() { return filter( this.models, diff --git a/test/specs/css_composer/index.js b/test/specs/css_composer/index.js index 0d1ef288d..ad9eba809 100644 --- a/test/specs/css_composer/index.js +++ b/test/specs/css_composer/index.js @@ -7,7 +7,7 @@ const utils = require('./../test_utils.js'); const Editor = require('editor/model/Editor'); describe('Css Composer', () => { - describe('Main', () => { + describe.only('Main', () => { var obj; var em; var config; @@ -207,6 +207,15 @@ describe('Css Composer', () => { const rule = obj.getClassRule(name, { state }); expect(rule.selectorsToString()).toEqual(`.${name}:${state}`); }); + + test('Create a simple class-based rule with setRule', () => { + const selector = '.test'; + obj.setRule(selector, { color: 'red' }); + expect(obj.getAll().length).toEqual(1); + const rule = obj.getRule(selector); + expect(rule.selectorsToString()).toEqual(selector); + expect(rule.styleToString()).toEqual(`color:red;`); + }); }); Models.run(); diff --git a/test/specs/selector_manager/index.js b/test/specs/selector_manager/index.js index adb86bc29..da3497b6e 100644 --- a/test/specs/selector_manager/index.js +++ b/test/specs/selector_manager/index.js @@ -60,6 +60,13 @@ describe('SelectorManager', () => { expect(sel.get('label')).toEqual(name); }); + test('Check name property by adding as class', () => { + var name = 'test'; + var sel = obj.add(`.${name}`); + expect(sel.get('name')).toEqual(name); + expect(sel.get('label')).toEqual(name); + }); + test('Add 2 selectors', () => { obj.add('test'); obj.add('test2'); @@ -72,6 +79,45 @@ describe('SelectorManager', () => { expect(obj.getAll().length).toEqual(1); }); + test('Add multiple selectors', () => { + const result = obj.add([ + '.test1', + 'test1', + '.test2', + '.test2', + '#test3', + 'test3', + 'test3', + '#test3' + ]); + expect(Array.isArray(result)).toEqual(true); + expect(obj.getAll().length).toEqual(4); + expect( + obj + .getAll() + .at(0) + .getFullName() + ).toEqual('.test1'); + expect( + obj + .getAll() + .at(1) + .getFullName() + ).toEqual('.test2'); + expect( + obj + .getAll() + .at(2) + .getFullName() + ).toEqual('#test3'); + expect( + obj + .getAll() + .at(3) + .getFullName() + ).toEqual('.test3'); + }); + test('Get selector', () => { var name = 'test'; var sel = obj.add(name);