Skip to content

Commit

Permalink
Merge pull request #1556 from Polymer/xstyle
Browse files Browse the repository at this point in the history
Xstyle
  • Loading branch information
kevinpschaaf committed May 19, 2015
2 parents 538db4e + f20fe20 commit 041b732
Show file tree
Hide file tree
Showing 20 changed files with 1,244 additions and 702 deletions.
6 changes: 6 additions & 0 deletions polymer.html
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,10 @@
this._prepConstructor();
// template
this._prepTemplate();
// styles
this._prepStyles();
// style properties
this._prepStyleProperties();
// template markup
this._prepAnnotations();
// accessors
Expand All @@ -56,6 +60,8 @@
this._poolContent();
// manage configuration
this._setupConfigure();
// setup style properties
this._setupStyleProperties();
// host stack
this._pushHost();
// instantiate template
Expand Down
205 changes: 116 additions & 89 deletions src/lib/css-parse.html
Original file line number Diff line number Diff line change
Expand Up @@ -13,101 +13,126 @@
Extremely simple css parser. Intended to be not more than what we need
and definitely not necessarly correct =).
*/
(function() {
Polymer.CssParse = (function() {

// given a string of css, return a simple rule tree
function parse(text) {
text = clean(text);
return parseCss(lex(text), text);
}
var api = {
// given a string of css, return a simple rule tree
parse: function(text) {
text = this._clean(text);
return this._parseCss(this._lex(text), text);
},

// remove stuff we don't care about that may hinder parsing
function clean(cssText) {
return cssText.replace(rx.comments, '').replace(rx.port, '');
}
// remove stuff we don't care about that may hinder parsing
_clean: function (cssText) {
return cssText.replace(rx.comments, '').replace(rx.port, '');
},

// super simple {...} lexer that returns a node tree
function lex(text) {
var root = {start: 0, end: text.length};
var n = root;
for (var i=0, s=0, l=text.length; i < l; i++) {
switch (text[i]) {
case OPEN_BRACE:
//console.group(i);
if (!n.rules) {
n.rules = [];
}
var p = n;
var previous = p.rules[p.rules.length-1];
n = {start: i+1, parent: p, previous: previous};
p.rules.push(n);
break;
case CLOSE_BRACE:
//console.groupEnd(n.start);
n.end = i+1;
n = n.parent || root;
break;
// super simple {...} lexer that returns a node tree
_lex: function(text) {
var root = {start: 0, end: text.length};
var n = root;
for (var i=0, s=0, l=text.length; i < l; i++) {
switch (text[i]) {
case this.OPEN_BRACE:
//console.group(i);
if (!n.rules) {
n.rules = [];
}
var p = n;
var previous = p.rules[p.rules.length-1];
n = {start: i+1, parent: p, previous: previous};
p.rules.push(n);
break;
case this.CLOSE_BRACE:
//console.groupEnd(n.start);
n.end = i+1;
n = n.parent || root;
break;
}
}
}
return root;
}
return root;
},

// add selectors/cssText to node tree
function parseCss(node, text) {
var t = text.substring(node.start, node.end-1);
node.parsedCssText = node.cssText = t.trim();
if (node.parent) {
var ss = node.previous ? node.previous.end : node.parent.start;
t = text.substring(ss, node.start-1);
// TODO(sorvell): ad hoc; make selector include only after last ;
// helps with mixin syntax
t = t.substring(t.lastIndexOf(';')+1);
node.parsedSelector = node.selector = t.trim();
}
var r$ = node.rules;
if (r$) {
for (var i=0, l=r$.length, r; (i<l) && (r=r$[i]); i++) {
parseCss(r, text);
}
}
return node;
}

// stringify parsed css.
function stringify(node, preserveProperties, text) {
text = text || '';
// calc rule cssText
var cssText = '';
if (node.cssText || node.rules) {
// add selectors/cssText to node tree
_parseCss: function(node, text) {
var t = text.substring(node.start, node.end-1);
node.parsedCssText = node.cssText = t.trim();
if (node.parent) {
var ss = node.previous ? node.previous.end : node.parent.start;
t = text.substring(ss, node.start-1);
// TODO(sorvell): ad hoc; make selector include only after last ;
// helps with mixin syntax
t = t.substring(t.lastIndexOf(';')+1);
var s = node.parsedSelector = node.selector = t.trim();
node.atRule = (s.indexOf(AT_START) === 0);
// note, support a subset of rule types...
if (node.atRule) {
if (s.indexOf(MEDIA_START) === 0) {
node.type = this.types.MEDIA_RULE;
} else if (s.match(rx.keyframesRule)) {
node.type = this.types.KEYFRAMES_RULE;
}
} else {
if (s.indexOf(VAR_START) === 0) {
node.type = this.types.MIXIN_RULE;
} else {
node.type = this.types.STYLE_RULE;
}
}
}
var r$ = node.rules;
if (r$ && (preserveProperties || !hasMixinRules(r$))) {
if (r$) {
for (var i=0, l=r$.length, r; (i<l) && (r=r$[i]); i++) {
cssText = stringify(r, preserveProperties, cssText);
this._parseCss(r, text);
}
} else {
cssText = preserveProperties ? node.cssText :
removeCustomProps(node.cssText);
cssText = cssText.trim();
if (cssText) {
cssText = ' ' + cssText + '\n';
}
}
}
// emit rule iff there is cssText
if (cssText) {
if (node.selector) {
text += node.selector + ' ' + OPEN_BRACE + '\n';
return node;
},

// stringify parsed css.
stringify: function(node, preserveProperties, text) {
text = text || '';
// calc rule cssText
var cssText = '';
if (node.cssText || node.rules) {
var r$ = node.rules;
if (r$ && (preserveProperties || !hasMixinRules(r$))) {
for (var i=0, l=r$.length, r; (i<l) && (r=r$[i]); i++) {
cssText = this.stringify(r, preserveProperties, cssText);
}
} else {
cssText = preserveProperties ? node.cssText :
removeCustomProps(node.cssText);
cssText = cssText.trim();
if (cssText) {
cssText = ' ' + cssText + '\n';
}
}
}
text += cssText;
if (node.selector) {
text += CLOSE_BRACE + '\n\n';
// emit rule iff there is cssText
if (cssText) {
if (node.selector) {
text += node.selector + ' ' + this.OPEN_BRACE + '\n';
}
text += cssText;
if (node.selector) {
text += this.CLOSE_BRACE + '\n\n';
}
}
}
return text;
}
return text;
},

types: {
STYLE_RULE: 1,
KEYFRAMES_RULE: 7,
MEDIA_RULE: 4,
MIXIN_RULE: 1000
},

var OPEN_BRACE = '{';
var CLOSE_BRACE = '}';
OPEN_BRACE: '{',
CLOSE_BRACE: '}'

};

function hasMixinRules(rules) {
return (rules[0].selector.indexOf(VAR_START) >= 0);
Expand All @@ -117,25 +142,27 @@
return cssText
.replace(rx.customProp, '')
.replace(rx.mixinProp, '')
.replace(rx.mixinApply, '');
.replace(rx.mixinApply, '')
.replace(rx.varApply, '');
}

var VAR_START = '--';
var MEDIA_START = '@media';
var AT_START = '@';

// helper regexp's
var rx = {
comments: /\/\*[^*]*\*+([^/*][^*]*\*+)*\//gim,
port: /@import[^;]*;/gim,
customProp: /--[^;{]*?:[^{};]*?;/gim,
mixinProp: /--[^;{]*?:[^{;]*?{[^}]*?};?/gim,
mixinApply: /@apply[\s]*\([^)]*?\)[\s]*;/gim
mixinApply: /@apply[\s]*\([^)]*?\)[\s]*;/gim,
varApply: /[^;:]*?:[^;]*var[^;]*;/gim,
keyframesRule: /^@[^\s]*keyframes/,
};

// exports
Polymer.CssParse = {
parse: parse,
stringify: stringify
};
return api;

})();

Expand Down
28 changes: 16 additions & 12 deletions src/lib/custom-style.html
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,8 @@

var nativeShadow = Polymer.Settings.useNativeShadow;
var propertyUtils = Polymer.StyleProperties;
var styleUtil = Polymer.StyleUtil;
var styleDefaults = Polymer.StyleDefaults;

Polymer({

Expand All @@ -81,9 +83,9 @@
if (this._appliesToDocument) {
// used applied element from HTMLImports polyfill or this
var e = this.__appliedElement || this;
this.__cssRules = Polymer.StyleUtil.parser.parse(e.textContent);
propertyUtils.decorateRules(this.__cssRules);
this._rulesToDefaultProperties(this.__cssRules);
var rules = styleUtil.rulesForStyle(e);
propertyUtils.decorateStyles([e]);
this._rulesToDefaultProperties(rules);
// NOTE: go async to give a chance to collect properties into
// the StyleDefaults before applying
this.async(this._applyStyle);
Expand All @@ -95,39 +97,41 @@
_applyStyle: function() {
// used applied element from HTMLImports polyfill or this
var e = this.__appliedElement || this;
var props = this._styleProperties = this._computeStyleProperties();
this._computeStyleProperties();
var props = this._styleProperties;
var self = this;
e.textContent = Polymer.StyleUtil.toCssText(this.__cssRules,
e.textContent = styleUtil.toCssText(styleUtil.rulesForStyle(e),
function(rule) {
// polyfill lack of support for :root
if (rule.selector === ':root') {
rule.selector = 'body';
}
var css = rule.cssText = rule.parsedCssText;
if (rule.properties.consumes) {
if (rule.propertyInfo.cssText) {
// TODO(sorvell): factor better
// remove property assignments so next function isn't confused
css = css.replace(propertyUtils.rx.VAR_ASSIGN, '');
// replace with reified properties, scenario is same as mixin
rule.cssText = propertyUtils.valueForMixin(css, props);
rule.cssText = propertyUtils.valueForProperties(css, props);
}
if (!nativeShadow) {
Polymer.StyleTransformer.rootRule(rule);
}
});
}
);
},

_rulesToDefaultProperties: function(rules) {
// produce css containing only property assignments.
Polymer.StyleUtil.forEachStyleRule(rules, function(rule) {
if (!rule.properties.produces) {
styleUtil.forEachStyleRule(rules, function(rule) {
if (!rule.propertyInfo.properties) {
rule.cssText = '';
}
});
// tell parser to emit css that includes properties.
var cssText = Polymer.StyleUtil.parser.stringify(rules, true);
var cssText = styleUtil.parser.stringify(rules, true);
if (cssText) {
Polymer.StyleDefaults.applyCss(cssText);
styleDefaults.applyCss(cssText);
}
}

Expand Down
Loading

0 comments on commit 041b732

Please sign in to comment.