Browse Source

Update css parser and renderer

pull/36/head
Artur Arseniev 10 years ago
parent
commit
6e1d8d27d6
  1. 227
      index.html
  2. 94
      src/code_manager/model/CssGenerator.js
  3. 6
      src/css_composer/view/CssRuleView.js
  4. 6
      src/editor/config/config.js
  5. 16
      src/parser/model/ParserCss.js
  6. 2
      src/style_manager/view/SectorsView.js
  7. 47
      test/specs/code_manager/model/CodeModels.js
  8. 6
      test/specs/css_composer/view/CssRuleView.js
  9. 32
      test/specs/parser/model/ParserCss.js

227
index.html

@ -191,118 +191,6 @@
</footer>
<style>
.footer-under{
background-color: #312833;
padding-bottom: 100px;
padding-top: 100px;
height: 500px;
color:#eee;
position: relative;
font-weight: 100;
font-family: Helvetica,serif;
}
.led{
border-radius: 100%;
width: 10px;
height: 10px;
background-color: rgba(0, 0, 0, 0.15);
float: left;
margin: 2px;
transition: all 5s ease;
}
.led:hover{
background-color: #c29fca;/* #eac229 */
box-shadow: 0 0 5px #9d7aa5, 0 0 10px #e6c3ee;/* 0 0 10px 0 #efc111 */
transition: all 0s ease;
}
.copyright {
background-color: rgba(0, 0, 0, 0.15);
color: rgba(238, 238, 238, 0.5);
bottom: 0;
padding: 1em 0;
position: absolute;
width: 100%;
font-size: 0.75em;
}
.made-with{
float: left;
width: 50%;
padding: 5px 0;
}
.foot-social-btns{
float: right;
width: 50%;
text-align: right;
padding: 5px 0;
}
.foot-list {
float: left;
width: 200px;
}
.foot-list-title {
font-weight: 400;
margin-bottom: 10px;
padding: 0.5em 0;
}
.foot-list-item {
color: rgba(238, 238, 238, 0.8);
font-size: 0.8em;
padding: 0.5em 0;
}
.foot-list-item:hover {
color: rgba(238, 238, 238, 1);
}
.foot-lists, .form-sub{
float: left;
width: 50%;
}
.foot-form-cont{
width: 300px;
float: right;
}
.foot-form-title{
color: rgba(255,255,255,0.75);
font-weight: 400;
margin-bottom: 10px;
padding: 0.5em 0;
text-align: right;
font-size: 2em;
}
.foot-form-desc{
font-size: 0.8em;
color: rgba(255,255,255,0.55);
line-height: 20px;
text-align: right;
margin-bottom: 15px;
}
.sub-input{
width: 100%;
margin-bottom: 15px;
padding: 7px 10px;
border-radius: 2px;
color:#fff;
background-color: #554c57;
border: none;
}
.sub-btn{
width: 100%;
margin-bottom: 15px;
background-color: #785580;
border: none;
color:#fff;
border-radius: 2px;
padding: 7px 10px;
font-size: 1em;
cursor: pointer;
}
.sub-btn:hover{
background-color: #91699a;
}
.sub-btn:active{
background-color: #573f5c;
}
.clearfix{ clear:both}
.header-banner{
padding-top: 35px;
@ -574,6 +462,121 @@
.pc-enterprise{
background-color: #d66a96;
}
.footer-under{
background-color: #312833;
padding-bottom: 100px;
padding-top: 100px;
height: 500px;
color:#eee;
position: relative;
font-weight: 100;
font-family: Helvetica,serif;
}
.led{
border-radius: 100%;
width: 10px;
height: 10px;
background-color: rgba(0, 0, 0, 0.15);
float: left;
margin: 2px;
transition: all 5s ease;
}
.led:hover{
background-color: #c29fca;/* #eac229 */
box-shadow: 0 0 5px #9d7aa5, 0 0 10px #e6c3ee;/* 0 0 10px 0 #efc111 */
transition: all 0s ease;
}
.copyright {
background-color: rgba(0, 0, 0, 0.15);
color: rgba(238, 238, 238, 0.5);
bottom: 0;
padding: 1em 0;
position: absolute;
width: 100%;
font-size: 0.75em;
}
.made-with{
float: left;
width: 50%;
padding: 5px 0;
}
.foot-social-btns{
float: right;
width: 50%;
text-align: right;
padding: 5px 0;
}
.foot-list {
float: left;
width: 200px;
}
.foot-list-title {
font-weight: 400;
margin-bottom: 10px;
padding: 0.5em 0;
}
.foot-list-item {
color: rgba(238, 238, 238, 0.8);
font-size: 0.8em;
padding: 0.5em 0;
}
.foot-list-item:hover {
color: rgba(238, 238, 238, 1);
}
.foot-lists, .form-sub{
float: left;
width: 50%;
}
.foot-form-cont{
width: 300px;
float: right;
}
.foot-form-title{
color: rgba(255,255,255,0.75);
font-weight: 400;
margin-bottom: 10px;
padding: 0.5em 0;
text-align: right;
font-size: 2em;
}
.foot-form-desc{
font-size: 0.8em;
color: rgba(255,255,255,0.55);
line-height: 20px;
text-align: right;
margin-bottom: 15px;
}
.sub-input{
width: 100%;
margin-bottom: 15px;
padding: 7px 10px;
border-radius: 2px;
color:#fff;
background-color: #554c57;
border: none;
}
.sub-btn{
width: 100%;
margin-bottom: 15px;
background-color: #785580;
border: none;
color:#fff;
border-radius: 2px;
padding: 7px 10px;
font-size: 1em;
cursor: pointer;
}
.sub-btn:hover{
background-color: #91699a;
}
.sub-btn:active{
background-color: #573f5c;
}
@media (max-width: 992px){
.container-width{
background-color:#fa0707;
}
}
pc-regular
</style>
</div>

94
src/code_manager/model/CssGenerator.js

@ -11,9 +11,10 @@ define(['backbone'],
/**
* Get CSS from components
* @param {Model} model
* @return {String}
*/
buildFromComp: function(model){
buildFromComp: function(model) {
var coll = model.get('components') || model,
code = '';
@ -43,43 +44,84 @@ define(['backbone'],
},
/** @inheritdoc */
build: function(model, cssc)
{
build: function(model, cssc) {
this.compCls = [];
var code = this.buildFromComp(model);
var compCls = this.compCls;
if(cssc){
var rules = cssc.getRules();
var mediaRules = {};
rules.each(function(rule){
var selectors = rule.get('selectors');
var ruleStyle = rule.get('style');
var state = rule.get('state');
var strSel = '';
var found = 0;
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 = '';
if(ruleStyle && Object.keys(ruleStyle).length !== 0){
for(var prop2 in ruleStyle){
if(ruleStyle.hasOwnProperty(prop2))
strStyle += prop2 + ':' + ruleStyle[prop2] + ';';
}
}
if(strStyle)
code += strSel + '{' + strStyle + '}';
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;
},
});
});

6
src/css_composer/view/CssRuleView.js

@ -11,6 +11,7 @@ define(['backbone'],
this.config = o.config || {};
this.listenTo(this.model, 'change:style', this.render);
this.listenTo(this.model, 'change:state', this.render);
this.listenTo(this.model, 'change:maxWidth', this.render);
this.listenTo(this.model.get('selectors'), 'change', this.selChanged);
},
@ -63,9 +64,10 @@ define(['backbone'],
block = prpStr !== '' ? '{' + prpStr + '}' : '';
}
o = this.selStr && block ? this.selStr + stateStr + block : '';
if(width && o){
if(width && o)
o = '@media (max-width: ' + width + '){' + o + '}';
}
this.$el.html(o);
return this;
},

6
src/editor/config/config.js

@ -86,13 +86,13 @@ define(function () {
width: '',
},{
name: 'Tablet',
width: '991px',
width: '992px',
},{
name: 'Mobile landscape',
width: '767px',
width: '768px',
},{
name: 'Mobile portrait',
width: '479px',
width: '480px',
}],
},

16
src/parser/model/ParserCss.js

@ -41,10 +41,18 @@ define(function(require) {
for (var i = 0, len = nodes.length; i < len; i++) {
var node = nodes[i];
var sels = node.selectorText; // CSSMediaRule has conditionText (screen and (min-width: 480px))
//if(node.cssRules)
// it's a CSSMediaRule, need to go deeper
var sels = node.selectorText;
// It's a CSSMediaRule
if(node.cssRules){
var subRules = this.parseNode(node);
var width = node.conditionText.match(/-width:(.*)\)/i)[1];
for(var s = 0, lens = subRules.length; s < lens; s++){
var subRule = subRules[s];
subRule.maxWidth = width ? width.trim() : '';
}
result = result.concat(subRules);
}
if(!sels)
continue;

2
src/style_manager/view/SectorsView.js

@ -14,7 +14,7 @@ define(['backbone', './SectorView'],
this.listenTo( this.collection, 'add', this.addTo);
this.listenTo( this.collection, 'reset', this.render);
this.listenTo( this.target, 'change:selectedComponent targetClassAdded targetClassRemoved targetClassUpdated ' +
'targetStateUpdated', this.targetUpdated);
'targetStateUpdated change:device', this.targetUpdated);
},

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

@ -146,6 +146,53 @@ define([path + 'HtmlGenerator',
this.obj.build(comp, cssc).should.equal('.class1.class2{prop1:value1;}.class2{prop2:value2;}');
});
it('Rule with media query', function() {
var comp = new Component();
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 = new CssComposer();
var rule = cssc.newRule([cls1, cls2]);
rule.set('style',{'prop1':'value1'});
rule.set('maxWidth', '999px');
cssc.addRule(rule);
this.obj.build(comp, cssc).should.equal('@media (max-width: 999px){.class1.class2{prop1:value1;}}');
});
it('Rules mixed with media queries', function() {
var comp = new Component();
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 = new CssComposer();
var rule = cssc.newRule([cls1, cls2]);
rule.set('style',{'prop1':'value1'});
cssc.addRule(rule);
var rule2 = cssc.newRule(cls2);
rule2.set('style',{'prop2':'value2'});
cssc.addRule(rule2);
var rule3 = cssc.newRule(cls1, '', '999px');
rule3.set('style',{'prop3':'value3'});
cssc.addRule(rule3);
var rule4 = cssc.newRule(cls2, '', '999px');
rule4.set('style',{'prop4':'value4'});
cssc.addRule(rule4);
var rule5 = cssc.newRule(cls1, '', '100px');
rule5.set('style',{'prop5':'value5'});
cssc.addRule(rule5);
this.obj.build(comp, cssc).should.equal('.class1.class2{prop1:value1;}.class2{prop2:value2;}'+
'@media (max-width: 999px){.class1{prop3:value3;}.class2{prop4:value4;}}'+
'@media (max-width: 100px){.class1{prop5:value5;}}');
});
it("Avoid useless code", function() {
var comp = new Component();
var m1 = comp.get('components').add({tagName: 'article'});

6
test/specs/css_composer/view/CssRuleView.js

@ -99,6 +99,12 @@ define([path + 'CssRuleView', 'CssComposer/model/CssRule'],
this.regView.$el.html().should.equal('.test1.test2{prop:value;}');
});
it('Render media queries', function() {
this.regView.model.set('style', {'prop':'value'});
this.regView.model.set('maxWidth', '999px');
this.regView.$el.html().should.equal('@media (max-width: 999px){.test1.test2{prop:value;}}');
});
it('Empty on clear', function() {
this.regView.model.set('style', {'prop':'value'});
this.regView.model.set('style', {});

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

@ -111,6 +111,38 @@ define([path + 'model/ParserCss',],
obj.parse(str).should.deep.equal(result);
});
// Phantom don't find 'node.conditionText' so will skip it
it.skip('Parse rule inside media query', function() {
var str = '@media (max-width: 992px){ .test1.test2:hover{ color:red }}';
var result = {
selectors: ['test1', 'test2'],
style: { color: 'red'},
state: 'hover',
maxWidth: '992px',
};
obj.parse(str).should.deep.equal(result);
});
// Phantom don't find 'node.conditionText' so will skip it
it.skip('Parse rules inside media queries', function() {
var str = '.test1:hover{ color:white }@media (max-width: 992px){ .test1.test2:hover{ color:red } .test2{ color: blue }}';
var result = [{
selectors: ['test1'],
style: { color: 'white'},
state: 'hover',
},{
selectors: ['test1', 'test2'],
style: { color: 'red'},
state: 'hover',
maxWidth: '992px',
},{
selectors: ['test2'],
style: { color: 'blue'},
maxWidth: '992px',
}];
obj.parse(str).should.deep.equal(result);
});
});
}

Loading…
Cancel
Save