Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Xstyle #1556

Merged
merged 25 commits into from
May 19, 2015
Merged

Xstyle #1556

Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
9b6ca7b
Support property use inside calc, simplify parsing and avoid re-parsi…
May 11, 2015
7c0a8eb
minor optimization
May 12, 2015
5abe3b8
Add @extend feature (not used yet)
May 12, 2015
a583554
Merge branch '0.8-preview' into 0.8-xstyle
May 12, 2015
d8b0bae
add basic rule types to css-parser
May 12, 2015
65f8521
Add a host based cache for custom property styles and clean up cachin…
May 14, 2015
3c3663e
Merge branch '0.8-preview' into 0.8-xstyle
May 14, 2015
80b7b20
minor refactoring
May 14, 2015
9c98ce8
Factoring; remove var(...); from stringified css by default.
May 14, 2015
6095478
Integrate basic extends support.
May 14, 2015
92ebf2f
@extends: add support for nested style rules
May 14, 2015
0e12417
fix typos
May 14, 2015
bc90680
fix test on IE.
May 14, 2015
ab6fefa
custom-style: make property calculation more lazy and ensure any cach…
May 14, 2015
eadab33
updateStyles: always cascade update to root, even if element does not…
May 14, 2015
6bbbdb5
add support for extending '%' selectors and strip unused '%' extendors.
May 14, 2015
e999a92
Merge branch '0.8-preview' into 0.8-xstyle
May 14, 2015
8bab868
style property optimizations: reify only used properties and cache st…
May 16, 2015
972a69f
minor fixes based on review.
May 16, 2015
0f5bfa5
Fix for #1490: style scoping sag elements on IE.
May 18, 2015
8a56643
Merge branch 'master' into xstyle
May 18, 2015
0973feb
minor changes based on review.
May 18, 2015
c563e08
cache style info object rather than style itself.
May 19, 2015
6389759
add comment.
May 19, 2015
f20fe20
remove unused code.
May 19, 2015
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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