Skip to content
This repository was archived by the owner on Mar 13, 2018. It is now read-only.

Commit 6db75b5

Browse files
committed
also, shimmed styles that include polyfill specific comments can now contain :host to refer to the host element.
1 parent ca89c64 commit 6db75b5

3 files changed

Lines changed: 78 additions & 39 deletions

File tree

src/ShadowCSS.js

Lines changed: 53 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -141,7 +141,7 @@ var ShadowCSS = {
141141
// Shim styles for a given root associated with a name and extendsName
142142
// 1. cache root styles by name
143143
// 2. optionally tag root nodes with scope name
144-
// 3. shim polyfill directives /* @polyfill */
144+
// 3. shim polyfill directives /* @polyfill */ and /* @polyfill-rule */
145145
// 4. shim @host and scoping
146146
shimStyling: function(root, name, extendsName) {
147147
// use caching to make working with styles nodes easier and to facilitate
@@ -151,10 +151,11 @@ var ShadowCSS = {
151151
if (this.strictStyling) {
152152
this.applyScopeToContent(root, name);
153153
}
154-
this.shimPolyfillDirectives(def.rootStyles, name);
154+
// insert @polyfill and @polyfill-rule rules into style elements
155+
// scoping process takes care of shimming these
156+
this.insertPolyfillDirectives(def.rootStyles);
157+
this.insertPolyfillRules(def.rootStyles);
155158
var cssText = this.stylesToShimmedCssText(def.scopeStyles, name);
156-
// note: it's critical that polyfill-rules are not shimmed.
157-
cssText += '\n\n' + this.extractPolyfillRules(def.scopeStyles, name);
158159
// provide shimmedStyle for user extensibility
159160
def.shimmedStyle = cssTextToStyle(cssText);
160161
if (root) {
@@ -205,49 +206,61 @@ var ShadowCSS = {
205206
*
206207
* For example, we convert this rule:
207208
*
208-
* (comment start) @polyfill @host g-menu-item (comment end)
209-
* shadow::-webkit-distributed(g-menu-item) {
209+
* (comment start) @polyfill :host menu-item (comment end)
210+
* shadow::-webkit-distributed(menu-item) {
210211
*
211212
* to this:
212213
*
213-
* scopeName g-menu-item {
214+
* scopeName menu-item {
214215
*
215216
**/
216-
shimPolyfillDirectives: function(styles, name) {
217+
insertPolyfillDirectives: function(styles, name) {
217218
if (styles) {
218219
Array.prototype.forEach.call(styles, function(s) {
219-
s.textContent = this.convertPolyfillDirectives(s.textContent, name);
220+
s.textContent = this.insertPolyfillDirectivesInCssText(s.textContent);
220221
}, this);
221222
}
222223
},
223-
convertPolyfillDirectives: function(cssText, name) {
224-
var r = '', l = 0, matches, selector;
224+
insertPolyfillDirectivesInCssText: function(cssText, name) {
225+
var r = '', l = 0, matches;
225226
while (matches = cssPolyfillCommentRe.exec(cssText)) {
226227
r += cssText.substring(l, matches.index);
227228
// remove end comment delimiter (*/)
228-
selector = matches[1].slice(0, -2).replace(hostRe, name);
229-
r += this.scopeSelector(selector, name) + '{';
229+
r += matches[1].slice(0, -2) + '{';
230230
l = cssPolyfillCommentRe.lastIndex;
231231
}
232232
r += cssText.substring(l, cssText.length);
233233
return r;
234234
},
235-
extractPolyfillRules: function(styles, name) {
235+
/*
236+
* Process styles to add rules which will only apply under the polyfill
237+
*
238+
* For example, we convert this rule:
239+
*
240+
* (comment start) @polyfill-rule :host menu-item {
241+
* ... } (comment end)
242+
*
243+
* to this:
244+
*
245+
* scopeName menu-item {...}
246+
*
247+
**/
248+
insertPolyfillRules: function(styles, name) {
236249
if (styles) {
237-
var cssText = '';
238250
Array.prototype.forEach.call(styles, function(s) {
239-
cssText += this.extractPolyfillRulesFromCssText(s.textContent, name) +
240-
'\n\n';
251+
s.textContent = this.insertPolyfillRulesInCssText(s.textContent);
241252
}, this);
242253
}
243-
return cssText;
244254
},
245-
extractPolyfillRulesFromCssText: function(cssText, name) {
246-
var r = '', l = 0, matches, selector;
255+
insertPolyfillRulesInCssText: function(cssText, name) {
256+
var r = '', l = 0, matches;
247257
while (matches = cssPolyfillRuleCommentRe.exec(cssText)) {
248-
rule = matches[1].slice(0, -1).replace(hostRe, name);
249-
r += rule + '\n\n';
258+
r += cssText.substring(l, matches.index);
259+
// remove end comment delimiter (*/)
260+
r += matches[1].slice(0, -1);
261+
l = cssPolyfillCommentRe.lastIndex;
250262
}
263+
r += cssText.substring(l, cssText.length);
251264
return r;
252265
},
253266
// apply @host and scope shimming
@@ -325,6 +338,7 @@ var ShadowCSS = {
325338
},
326339
convertScopedStyles: function(styles, name) {
327340
var cssText = stylesToCssText(styles).replace(hostRuleRe, '');
341+
cssText = this.insertPolyfillHostInCssText(cssText);
328342
cssText = this.convertPseudos(cssText);
329343
var rules = cssToRules(cssText);
330344
cssText = this.scopeRules(rules, name);
@@ -368,9 +382,19 @@ var ShadowCSS = {
368382
var re = new RegExp('^' + matchScope + selectorReSuffix, 'm');
369383
return !selector.match(re);
370384
},
385+
insertPolyfillHostInCssText: function(selector) {
386+
return selector.replace(hostRe, polyfillHost).replace(colonHostRe,
387+
polyfillHost);
388+
},
371389
// scope via name and [is=name]
372390
applySimpleSelectorScope: function(selector, name) {
373-
return name + ' ' + selector + ', ' + '[is=' + name + '] ' + selector;
391+
var ancestor = name + ' ', is = '[is=' + name + '] ';
392+
if (selector.match(polyfillHostRe)) {
393+
return selector.replace(polyfillHostRe, ancestor) + ', ' +
394+
selector.replace(polyfillHostRe, is);
395+
} else {
396+
return ancestor + selector + ', ' + is + selector;
397+
}
374398
},
375399
// return a selector with [name] suffix on each simple selector
376400
// e.g. .foo.bar > .zot becomes .foo[name].bar[name] > .zot[name]
@@ -381,7 +405,8 @@ var ShadowCSS = {
381405
splits.forEach(function(sep) {
382406
var parts = scoped.split(sep);
383407
scoped = parts.map(function(p) {
384-
var t = p.trim();
408+
// remove :host since it should be unnecessary
409+
var t = p.trim().replace(polyfillHostRe, '');
385410
if (t && (splits.indexOf(t) < 0) && (t.indexOf(attrName) < 0)) {
386411
p = t.replace(/([^:]*)(:*)(.*)/, '$1' + attrName + '$2$3')
387412
}
@@ -411,7 +436,10 @@ var hostRuleRe = /@host[^{]*{(([^}]*?{[^{]*?}[\s\S]*?)+)}/gim,
411436
cssPolyfillRuleCommentRe = /\/\*\s@polyfill-rule([^*]*\*+([^/*][^*]*\*+)*)\//gim,
412437
cssPseudoRe = /::(x-[^\s{,(]*)/gim,
413438
selectorReSuffix = '([>\\s~+\[.,{:][\\s\\S]*)?$',
414-
hostRe = /@host/gim;
439+
hostRe = /@host/gim,
440+
colonHostRe = /\:host/gim,
441+
polyfillHost = '-host',
442+
polyfillHostRe = /-host/gim;
415443

416444
function stylesToCssText(styles, preserveComments) {
417445
var cssText = '';

test/html/styling/polyfill-directive.html

Lines changed: 22 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
-->
77
<html>
88
<head>
9-
<title>Psuedo scoped styling</title>
9+
<title>polyfill directive</title>
1010
<script src="../../../platform.js" shadow></script>
1111
<script src="register.js"></script>
1212
<script src="../../../../tools/test/htmltest.js"></script>
@@ -16,8 +16,12 @@
1616
<x-foo>
1717
<div>Green?</div>
1818
</x-foo>
19+
20+
<x-bar>
21+
<div>Green?</div>
22+
</x-bar>
1923

20-
<template id="x-foo"">
24+
<template id="x-foo">
2125
<style>
2226
@host {
2327
* {
@@ -26,31 +30,39 @@
2630
}
2731
}
2832

29-
/*@polyfill @host > div */
33+
/*@polyfill :host > div */
3034
::-webkit-distributed(*) {
3135
background: green;
3236
}
3337

34-
/*@polyfill @host > div */
38+
/*@polyfill :host > div */
3539
::-webkit-distributed(*) {
3640
color: red;
3741
}
3842

3943
</style>
4044
<content></content>
4145
</template>
46+
47+
4248

4349
<script>
4450
XFoo = register('x-foo', '', HTMLElement.prototype);
51+
XBar = register('x-bar', 'x-foo', HTMLElement.prototype);
4552

53+
function test(selector) {
54+
var n = document.querySelector(selector);
55+
nDiv = n.firstElementChild;
56+
chai.assert.equal(getComputedStyle(nDiv).backgroundColor,
57+
'rgb(0, 128, 0)', '@polyfill styles are applied');
58+
chai.assert.equal(getComputedStyle(nDiv).color,
59+
'rgb(255, 0, 0)', '@polyfill styles are applied');
60+
}
61+
4662
document.addEventListener('WebComponentsReady', function() {
4763
setTimeout(function() {
48-
var foo = document.querySelector('x-foo');
49-
fooDiv = foo.firstElementChild;
50-
chai.assert.equal(getComputedStyle(fooDiv).backgroundColor,
51-
'rgb(0, 128, 0)', '@polyfill styles are applied');
52-
chai.assert.equal(getComputedStyle(fooDiv).color,
53-
'rgb(255, 0, 0)', '@polyfill styles are applied');
64+
test('x-foo');
65+
test('x-bar');
5466
done();
5567
});
5668
});

test/html/styling/polyfill-rule.html

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
-->
77
<html>
88
<head>
9-
<title>Psuedo scoped styling</title>
9+
<title>polyfill rule</title>
1010
<script src="../../../platform.js" shadow></script>
1111
<script src="register.js"></script>
1212
<script src="../../../../tools/test/htmltest.js"></script>
@@ -17,12 +17,11 @@
1717
<div class="zonk">red?</div>
1818
</x-foo>
1919

20-
<template id="x-foo"">
20+
<template id="x-foo">
2121
<style>
22-
/* @polyfill-rule .zonk {
22+
/* @polyfill-rule :host > .zonk {
2323
background: red;
2424
} */
25-
2625
</style>
2726
<content></content>
2827
</template>

0 commit comments

Comments
 (0)