Browse Source

Merge branch 'dev' of github.com:artf/grapesjs into dev

pull/76/head
tangkikodo 9 years ago
parent
commit
bf3ee681b9
  1. 2
      bower.json
  2. 26
      dist/grapes.min.js
  3. 2
      package.json
  4. 33
      src/canvas/view/CanvasView.js
  5. 290
      src/code_manager/model/CssGenerator.js
  6. 34
      src/css_composer/main.js
  7. 7
      src/css_composer/model/CssRule.js
  8. 9
      src/css_composer/view/CssRuleView.js
  9. 31
      src/demo.js
  10. 4
      src/editor/config/config.js
  11. 18
      src/editor/main.js
  12. 4
      src/editor/model/Editor.js
  13. 50
      src/parser/model/ParserCss.js
  14. 23
      test/specs/code_manager/model/CodeModels.js
  15. 4
      test/specs/css_composer/e2e/CssComposer.js
  16. 31
      test/specs/parser/model/ParserCss.js

2
bower.json

@ -1,7 +1,7 @@
{
"name": "grapesjs",
"description": "Open source Web Template Editor",
"version": "0.4.38",
"version": "0.5.4",
"author": "Artur Arseniev",
"homepage": "http://grapesjs.com",
"main": [

26
dist/grapes.min.js

File diff suppressed because one or more lines are too long

2
package.json

@ -1,7 +1,7 @@
{
"name": "grapesjs",
"description": "Open source Web Template Editor",
"version": "0.4.38",
"version": "0.5.4",
"author": "Artur Arseniev",
"license": "BSD-3-Clause",
"homepage": "http://grapesjs.com",

33
src/canvas/view/CanvasView.js

@ -41,7 +41,7 @@ function(Backbone, FrameView) {
frame.el.onload = function () {
var scripts = that.config.scripts.slice(0), // clone
counter = 0;
function appendScript(scripts) {
if (scripts.length > 0) {
var script = document.createElement('script');
@ -61,7 +61,7 @@ function(Backbone, FrameView) {
* Render inside frame's body
* @private
*/
renderBody: function(){
renderBody: function() {
var wrap = this.model.get('frame').get('wrapper');
var em = this.config.em;
if(wrap) {
@ -71,19 +71,22 @@ function(Backbone, FrameView) {
var conf = em.get('Config');
body.append(wrap.render()).append(cssc.render());
var protCss = conf.protectedCss;
var frameCss = '.' + ppfx + 'dashed :not([contenteditable]) > *{outline: 1px dashed rgba(170,170,170,0.7); outline-offset: -2px}' +
'.' + ppfx + 'comp-selected{outline: 3px solid #3b97e3 !important}' +
'.' + ppfx + 'no-select{user-select: none; -webkit-user-select:none; -moz-user-select: none}'+
'.' + ppfx + 'freezed{opacity: 0.5; pointer-events: none}' +
'.' + ppfx + 'no-pointer{pointer-events: none}' +
'.' + ppfx + 'plh-image{background:#f5f5f5; border:none; height:50px; width:50px; display:block; outline:3px solid #ffca6f; cursor:pointer}' +
'.' + ppfx + 'grabbing{cursor: grabbing; cursor: -webkit-grabbing}' +
'* ::-webkit-scrollbar-track {background: rgba(0, 0, 0, 0.1)}' +
'* ::-webkit-scrollbar-thumb {background: rgba(255, 255, 255, 0.2)}' +
'* ::-webkit-scrollbar {width: 10px}' +
(conf.canvasCss || '');
if(protCss)
body.append('<style>' + frameCss + protCss + '</style>');
// I need all this styles to make the editor work properly
var frameCss = '* {box-sizing: border-box;} body{margin:0;height:auto;background-color:#fff} #wrapper{min-height:100%; overflow:auto}' +
'.' + ppfx + 'dashed :not([contenteditable]) > *{outline: 1px dashed rgba(170,170,170,0.7); outline-offset: -2px}' +
'.' + ppfx + 'comp-selected{outline: 3px solid #3b97e3 !important}' +
'.' + ppfx + 'no-select{user-select: none; -webkit-user-select:none; -moz-user-select: none}'+
'.' + ppfx + 'freezed{opacity: 0.5; pointer-events: none}' +
'.' + ppfx + 'no-pointer{pointer-events: none}' +
'.' + ppfx + 'plh-image{background:#f5f5f5; border:none; height:50px; width:50px; display:block; outline:3px solid #ffca6f; cursor:pointer}' +
'.' + ppfx + 'grabbing{cursor: grabbing; cursor: -webkit-grabbing}' +
'* ::-webkit-scrollbar-track {background: rgba(0, 0, 0, 0.1)}' +
'* ::-webkit-scrollbar-thumb {background: rgba(255, 255, 255, 0.2)}' +
'* ::-webkit-scrollbar {width: 10px}' +
(conf.canvasCss || '');
frameCss += protCss || '';
body.append('<style>' + frameCss + '</style>');
body.append(this.getJsContainer());
em.trigger('loaded');
this.frame.el.contentWindow.onscroll = this.onFrameScroll;

290
src/code_manager/model/CssGenerator.js

@ -1,145 +1,149 @@
define(['backbone'],
function (Backbone) {
/**
* @class CssGenerator
* */
return Backbone.Model.extend({
initialize: function() {
this.compCls = [];
},
/**
* Get CSS from component
* @param {Model} model
* @return {String}
*/
buildFromModel: function (model) {
var code = '';
var style = model.get('style');
var classes = model.get('classes');
// Let's know what classes I've found
if(classes) {
classes.each(function(model){
this.compCls.push(model.get('name'));
}, this);
}
if(style && Object.keys(style).length !== 0) {
code += '#' + model.cid + '{';
for(var prop in style){
if(style.hasOwnProperty(prop))
code += prop + ':' + style[prop] + ';';
}
code += '}';
}
return code;
},
/**
* Get CSS from components
* @param {Model} model
* @return {String}
*/
buildFromComp: function(model) {
var coll = model.get('components') || model,
code = '';
coll.each(function(m) {
var cln = m.get('components');
code += this.buildFromModel(m);
if(cln.length){
code += this.buildFromComp(cln);
}
}, this);
return code;
},
/** @inheritdoc */
build: function(model, cssc) {
this.compCls = [];
var code = this.buildFromModel(model);
code += this.buildFromComp(model);
var compCls = this.compCls;
if(cssc){
var rules = cssc.getAll();
var mediaRules = {};
rules.each(function(rule){
var width = rule.get('maxWidth');
// If width setted will render it later
if(width){
var mRule = mediaRules[width];
if(mRule)
mRule.push(rule);
else
mediaRules[width] = [rule];
return;
}
code += this.buildFromRule(rule);
}, this);
// Get media rules
for (var ruleW in mediaRules) {
var meRules = mediaRules[ruleW];
var ruleC = '';
for(var i = 0, len = meRules.length; i < len; i++){
ruleC += this.buildFromRule(meRules[i]);
}
if(ruleC)
code += '@media (max-width: ' + ruleW + '){' + ruleC + '}';
}
}
return code;
},
/**
* Get CSS from the rule model
* @param {Model} rule
* @return {string} CSS string
*/
buildFromRule: function(rule) {
var result = '';
var selectors = rule.get('selectors');
var ruleStyle = rule.get('style');
var state = rule.get('state');
var strSel = '';
var found = 0;
var compCls = this.compCls;
// Get string of selectors
selectors.each(function(selector){
strSel += '.' + selector.get('name');
if(compCls.indexOf(selector.get('name')) > -1)
found = 1;
});
if(strSel && found){
strSel += state ? ':' + state : '';
var strStyle = '';
// Get string of style properties
if(ruleStyle && Object.keys(ruleStyle).length !== 0){
for(var prop2 in ruleStyle){
if(ruleStyle.hasOwnProperty(prop2))
strStyle += prop2 + ':' + ruleStyle[prop2] + ';';
}
}
if(strStyle)
result += strSel + '{' + strStyle + '}';
}
return result;
},
});
function (Backbone) {
/**
* @class CssGenerator
* */
return Backbone.Model.extend({
initialize: function() {
this.compCls = [];
},
/**
* Get CSS from component
* @param {Model} model
* @return {String}
*/
buildFromModel: function (model) {
var code = '';
var style = model.get('style');
var classes = model.get('classes');
// Let's know what classes I've found
if(classes) {
classes.each(function(model){
this.compCls.push(model.get('name'));
}, this);
}
if(style && Object.keys(style).length !== 0) {
code += '#' + model.cid + '{';
for(var prop in style){
if(style.hasOwnProperty(prop))
code += prop + ':' + style[prop] + ';';
}
code += '}';
}
return code;
},
/**
* Get CSS from components
* @param {Model} model
* @return {String}
*/
buildFromComp: function(model) {
var coll = model.get('components') || model,
code = '';
coll.each(function(m) {
var cln = m.get('components');
code += this.buildFromModel(m);
if(cln.length){
code += this.buildFromComp(cln);
}
}, this);
return code;
},
/** @inheritdoc */
build: function(model, cssc) {
this.compCls = [];
var code = this.buildFromModel(model);
code += this.buildFromComp(model);
var compCls = this.compCls;
if(cssc){
var rules = cssc.getAll();
var mediaRules = {};
rules.each(function(rule){
var width = rule.get('maxWidth');
// If width setted will render it later
if(width){
var mRule = mediaRules[width];
if(mRule)
mRule.push(rule);
else
mediaRules[width] = [rule];
return;
}
code += this.buildFromRule(rule);
}, this);
// Get media rules
for (var ruleW in mediaRules) {
var meRules = mediaRules[ruleW];
var ruleC = '';
for(var i = 0, len = meRules.length; i < len; i++){
ruleC += this.buildFromRule(meRules[i]);
}
if(ruleC)
code += '@media (max-width: ' + ruleW + '){' + ruleC + '}';
}
}
return code;
},
/**
* Get CSS from the rule model
* @param {Model} rule
* @return {string} CSS string
*/
buildFromRule: function(rule) {
var result = '';
var selectorsAdd = rule.get('selectorsAdd');
var selectors = rule.get('selectors');
var ruleStyle = rule.get('style');
var state = rule.get('state');
var strSel = '';
var found = 0;
var compCls = this.compCls;
// Get string of selectors
selectors.each(function(selector){
strSel += '.' + selector.get('name');
if(compCls.indexOf(selector.get('name')) > -1)
found = 1;
});
// With 'found' will skip rules which selectors are not found in
// canvas components.
if ((strSel && found) || selectorsAdd) {
strSel += state ? ':' + state : '';
strSel += selectorsAdd ? (strSel ? ', ' : '') + selectorsAdd : '';
var strStyle = '';
// Get string of style properties
if(ruleStyle && Object.keys(ruleStyle).length !== 0){
for(var prop2 in ruleStyle){
if(ruleStyle.hasOwnProperty(prop2))
strStyle += prop2 + ':' + ruleStyle[prop2] + ';';
}
}
if(strStyle)
result += strSel + '{' + strStyle + '}';
}
return result;
},
});
});

34
src/css_composer/main.js

@ -107,17 +107,18 @@ define(function(require) {
* @param {Object} data Object of data to load
* @return {Object} Loaded rules
*/
load: function(data){
load: function(data) {
var d = data || '';
if(!d && c.stm)
d = c.em.getCacheLoad();
var obj = '';
if(d.style){
if(d.styles) {
try{
obj = JSON.parse(d.style);
obj = JSON.parse(d.styles);
}catch(err){}
}else if(d.css)
} else if (d.css) {
obj = c.em.get('Parser').parseCss(d.css);
}
if(obj)
rules.reset(obj);
@ -148,6 +149,7 @@ define(function(require) {
* @param {Array<Selector>} selectors Array of selectors
* @param {String} state Css rule state
* @param {String} width For which device this style is oriented
* @param {Object} opts Other options for the rule
* @return {Model}
* @example
* var sm = editor.SelectorManager;
@ -159,17 +161,18 @@ define(function(require) {
* color: '#fff',
* });
* */
add: function(selectors, state, width) {
add: function(selectors, state, width, opts) {
var s = state || '';
var w = width || '';
var opt = opts || {};
var rule = this.get(selectors, s, w);
if(rule)
return rule;
else{
rule = new CssRule({
state: s,
maxWidth: w,
});
else {
opt.state = s;
opt.maxWidth = w;
opt.selectors = '';
rule = new CssRule(opt);
rule.get('selectors').add(selectors);
rules.add(rule);
return rule;
@ -224,7 +227,8 @@ define(function(require) {
var opt = opts || {};
var result = [];
var d = data instanceof Array ? data : [data];
for(var i = 0, l = d.length; i < l; i++){
for (var i = 0, l = d.length; i < l; i++) {
var rule = d[i] || {};
if(!rule.selectors)
continue;
@ -234,19 +238,23 @@ define(function(require) {
var sl = rule.selectors;
var sels = sl instanceof Array ? sl : [sl];
var newSels = [];
for(var j = 0, le = sels.length; j < le; j++){
for (var j = 0, le = sels.length; j < le; j++) {
var selec = sm.add(sels[j]);
newSels.push(selec);
}
var model = this.add(newSels, rule.state, rule.maxWidth);
var model = this.add(newSels, rule.state, rule.maxWidth, rule);
if (opt.extend) {
var newStyle = _.extend({}, model.get('style'), rule.style || {});
model.set('style', newStyle);
} else {
model.set('style', rule.style || {});
}
result.push(model);
}
return result;
},

7
src/css_composer/model/CssRule.js

@ -5,12 +5,19 @@ define(['backbone', './Selectors'],
defaults: {
// Css selectors
selectors: {},
// Additional string css selectors
selectorsAdd: '',
// Css properties style
style: {},
// On which device width this rule should be rendered, eg. @media (max-width: 1000px)
maxWidth: '',
// State of the rule, eg: hover | pressed | focused
state: '',
// Indicates if the rule is stylable
stylable: true,
},

9
src/css_composer/view/CssRuleView.js

@ -27,12 +27,15 @@ define(['backbone'],
* @return {String}
* @private
*/
renderSelectors: function(){
renderSelectors: function() {
var sel = [];
this.model.get('selectors').each(function(m){
var model = this.model;
var add = model.get('selectorsAdd');
model.get('selectors').each(function(m){
sel.push('.' + m.get('name'));
});
return sel.join('');
var sels = sel.join('');
return sels + (sels && add ? ', ' : '') + add;
},
/**

31
src/demo.js

@ -15,6 +15,12 @@ require(['config/require-config'], function() {
fromElement: true,
clearOnRender: 0,
storageManager:{
autoload: 0,
storeComponents: 1,
storeStyles: 1,
},
/*
components: [{
//script: 'var el = this; setInterval(function(){el.style.marginLeft = Math.random() * 50 +"px";}, 1000)',
@ -71,11 +77,6 @@ require(['config/require-config'], function() {
}],
}],
*/
storageManager:{
autoload: 0,
storeComponents: 1,
storeStyles: 1,
},
commands: {
defaults : [{
@ -177,19 +178,7 @@ require(['config/require-config'], function() {
name: 'Left',
property: 'margin-left',
},],
}/*{
name : 'Center blocksss',
property : 'margins',
type : 'select',
defaults : '0',
list : [{
value : '0',
name : 'Normal',
},{
value : '0 auto',
name : 'Center',
}],
}*/],
}],
},{
name: 'Flex',
open: false,
@ -361,10 +350,9 @@ require(['config/require-config'], function() {
],
},
}
);
});
window.editor = editor;
@ -392,8 +380,7 @@ require(['config/require-config'], function() {
if(sender) sender.set('active', false);
if(confirm('Are you sure to clean the canvas?')) {
var comps = editor.DomComponents.clear();
localStorage.setItem('gjs-css', '');
localStorage.setItem('gjs-html', '');
localStorage.clear();
}
},
attributes: { title: 'Empty canvas' }

4
src/editor/config/config.js

@ -24,7 +24,7 @@ define(function () {
showOffsetsSelected: false,
// Clear the canvas when editor.render() is called
clearOnRender: true,
clearOnRender: false,
// Return JS of components inside HTML from 'editor.getHtml()'
jsInHtml: true,
@ -36,7 +36,7 @@ define(function () {
width: '100%',
// CSS that could only be seen (for instance, inside the code viewer)
protectedCss: '*{box-sizing: border-box;}body{margin:0;height:auto;background:#fff}#wrapper{min-height:100%; overflow:auto}',
protectedCss: '*{box-sizing: border-box;}body{margin:0;height:auto;background-color:#fff}#wrapper{min-height:100%; overflow:auto}',
// CSS for the iframe which containing the canvas, useful if you need to custom something inside
// (eg. the style of the selected component)

18
src/editor/main.js

@ -6,6 +6,7 @@
* * [getJs](#getjs)
* * [getComponents](#getcomponents)
* * [setComponents](#setcomponents)
* * [addComponents](#addcomponents)
* * [getStyle](#getstyle)
* * [setStyle](#setstyle)
* * [getSelected](#getselected)
@ -253,6 +254,23 @@ define(function (require){
return this;
},
/**
* Add components
* @param {Array<Object>|Object|string} components HTML string or components model
* @return {Model|Array<Model>}
* @example
* editor.addComponents('<div class="cls">New component</div>');
* // or
* editor.addComponents({
* type: 'text',
* classes:['cls'],
* content: 'New component'
* });
*/
addComponents: function(components) {
return this.getComponents().add(components);
},
/**
* Returns style in JSON format object
* @return {Object}

4
src/editor/model/Editor.js

@ -413,6 +413,7 @@ define(['backbone', 'backboneUndo', 'keymaster', 'Utils', 'StorageManager', 'Dev
sm.store(store, clb);
this.set('changesCount', 0);
this.trigger('storage:store', store);
return store;
},
@ -437,7 +438,7 @@ define(['backbone', 'backboneUndo', 'keymaster', 'Utils', 'StorageManager', 'Dev
* @return {Object}
* @private
*/
getCacheLoad: function(force){
getCacheLoad: function(force) {
var f = force ? 1 : 0;
if(this.cacheLoad && !f)
return this.cacheLoad;
@ -457,6 +458,7 @@ define(['backbone', 'backboneUndo', 'keymaster', 'Utils', 'StorageManager', 'Dev
});
this.cacheLoad = sm.load(load);
this.trigger('storage:load', this.cacheLoad);
return this.cacheLoad;
},

50
src/parser/model/ParserCss.js

@ -6,16 +6,21 @@ define(function(require) {
/**
* Parse selector string to array.
* Only concatenated classes are valid as CSS rules inside editor.
* Only classe based are valid as CSS rules inside editor, not valid
* selectors will be dropped as additional
* It's ok with the last part of the string as state (:hover, :active)
* @param {string} str Selectors string
* @return {Array<Array>}
* @return {Object}
* @example
* var res = ParserCss.parseSelector('.test1, .test1.test2, .test2.test3');
* var res = ParserCss.parseSelector('.test1, .test1.test2, .test2 .test3');
* console.log(res);
* // [['test1'], ['test1', 'test2'], ['test2', 'test3']]
* // {
* //result: [['test1'], ['test1', 'test2']],
* //add: ['.test2 .test3']
* //}
*/
parseSelector: function(str){
parseSelector: function(str) {
var add = [];
var result = [];
var sels = str.split(',');
for (var i = 0, len = sels.length; i < len; i++) {
@ -25,9 +30,14 @@ define(function(require) {
if (/^(\.{1}[\w\-]+)+(:{1,2}[\w\-()]+)?$/ig.test(sel)) {
var cls = sel.split('.').filter(Boolean);
result.push(cls);
} else {
add.push(sel);
}
}
return result;
return {
result: result,
add: add,
};
},
/**
@ -35,13 +45,14 @@ define(function(require) {
* @param {StyleSheet|CSSMediaRule} el
* @return {Array<Object>}
*/
parseNode: function(el){
parseNode: function(el) {
var result = [];
var nodes = el.cssRules;
for (var i = 0, len = nodes.length; i < len; i++) {
var node = nodes[i];
var sels = node.selectorText;
var selsAdd = [];
// It's a CSSMediaRule
if(node.cssRules) {
@ -61,15 +72,18 @@ define(function(require) {
if(!sels)
continue;
sels = this.parseSelector(sels);
var selsParsed = this.parseSelector(sels);
sels = selsParsed.result;
selsAdd = selsParsed.add;
// Create style object from the big one
var stl = node.style;
var style = {};
for(var j = 0, len2 = stl.length; j < len2; j++){
for (var j = 0, len2 = stl.length; j < len2; j++) {
style[stl[j]] = stl[stl[j]];
}
var lastRule = '';
// For each group of selectors
for (var k = 0, len3 = sels.length; k < len3; k++) {
var selArr = sels[k];
@ -85,9 +99,25 @@ define(function(require) {
model.selectors = selArr;
model.style = style;
lastRule = model;
result.push(model);
}
// Need to push somewhere not class-based selectors, if some rule was
// created will push them there, otherwise will create a new rule
if (selsAdd.length) {
var selsAddStr = selsAdd.join(', ');
if (lastRule) {
lastRule.selectorsAdd = selsAddStr;
} else {
result.push({
selectors: [],
selectorsAdd: selsAddStr,
style: style,
});
}
}
}
return result;
@ -98,7 +128,7 @@ define(function(require) {
* @param {string} str HTML string
* @return {Object|Array<Object>}
*/
parse: function(str){
parse: function(str) {
var el = document.createElement('style');
/*
el.innerHTML = ".cssClass {border: 2px solid black; background-color: blue;} " +

23
test/specs/code_manager/model/CodeModels.js

@ -128,7 +128,28 @@ define([path + 'HtmlGenerator',
rule.set('style',{'prop1':'value1', 'prop2':'value2'});
this.obj.build(comp, cssc).should.equal('.class1.class2{prop1:value1;prop2:value2;}');
this.obj.build(comp, cssc).should.equal('.class1.class2{prop1:value1;prop2:value2;}');
});
it('Build rules with mixed classes', function() {
var m1 = comp.get('components').add({tagName: 'article'});
var cls1 = m1.get('classes').add({name: 'class1'});
var cls2 = m1.get('classes').add({name: 'class2'});
var cssc = newCssComp();
var rule = cssc.add([cls1, cls2]);
rule.set('style',{'prop1':'value1', 'prop2':'value2'});
rule.set('selectorsAdd', '.class1 .class2, div > .class4');
this.obj.build(comp, cssc).should.equal('.class1.class2, .class1 .class2, div > .class4{prop1:value1;prop2:value2;}');
});
it('Build rules with only not class based selectors', function() {
var cssc = newCssComp();
var rule = cssc.add([]);
rule.set('style',{'prop1':'value1', 'prop2':'value2'});
rule.set('selectorsAdd', '.class1 .class2, div > .class4');
this.obj.build(comp, cssc).should.equal('.class1 .class2, div > .class4{prop1:value1;prop2:value2;}');
});
it('Build correctly with class styled out', function() {

4
test/specs/css_composer/e2e/CssComposer.js

@ -102,8 +102,9 @@ define(['GrapesJS'],function(GrapesJS) {
});
it('Add raw rule objects twice with addCollection do not duplucate rules', function() {
var rulesSet2Copy = JSON.parse(JSON.stringify(rulesSet2));
var coll1 = cssc.addCollection(rulesSet2);
var coll2 = cssc.addCollection(rulesSet2);
var coll2 = cssc.addCollection(rulesSet2Copy);
cssc.getAll().length.should.equal(3);
clsm.getAll().length.should.equal(3);
coll1.should.deep.equal(coll2);
@ -131,6 +132,7 @@ define(['GrapesJS'],function(GrapesJS) {
name: 'test1',
type: 'class',
}],
selectorsAdd: '',
state: '',
stylable: true,
style: {

31
test/specs/parser/model/ParserCss.js

@ -19,25 +19,25 @@ define([path + 'model/ParserCss',],
it('Parse selector', function() {
var str = '.test';
var result = [['test']];
obj.parseSelector(str).should.deep.equal(result);
obj.parseSelector(str).result.should.deep.equal(result);
});
it('Parse selectors', function() {
var str = '.test1, .test1.test2, .test2.test3';
var result = [['test1'], ['test1', 'test2'], ['test2', 'test3']];
obj.parseSelector(str).should.deep.equal(result);
obj.parseSelector(str).result.should.deep.equal(result);
});
it('Ignore not valid selectors', function() {
var str = '.test1.test2, .test2 .test3, div > .test4, #test.test5, .test6';
var result = [['test1', 'test2'], ['test6']];
obj.parseSelector(str).should.deep.equal(result);
obj.parseSelector(str).result.should.deep.equal(result);
});
it('Parse selectors with state', function() {
var str = '.test1. test2, .test2>test3, .test4.test5:hover';
var result = [['test4', 'test5:hover']];
obj.parseSelector(str).should.deep.equal(result);
obj.parseSelector(str).result.should.deep.equal(result);
});
it('Parse simple rule', function() {
@ -153,6 +153,29 @@ define([path + 'model/ParserCss',],
obj.parse(str).should.deep.equal(result);
});
it('Parse rules with not class-based selectors', function() {
var str = ' .class1 .class2, div > .class3 { color:red }';
var result = {
selectors: [],
selectorsAdd: '.class1 .class2, div > .class3',
style: { color: 'red'}
};
obj.parse(str).should.deep.equal(result);
});
it('Parse rule with mixed selectors', function() {
var str = ' .class1 .class2, .class3, div > .class4, .class5.class6 { color:red }';
var result = [{
selectors: ['class3'],
style: { color: 'red'}
},{
selectors: ['class5', 'class6'],
selectorsAdd: '.class1 .class2, div > .class4',
style: { color: 'red'}
}];
obj.parse(str).should.deep.equal(result);
});
});
}

Loading…
Cancel
Save