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

Commit 8d0f24e

Browse files
committed
make type extension version opt in and mutually exclusive with scoping via element name.
1 parent ebaaa0c commit 8d0f24e

3 files changed

Lines changed: 59 additions & 45 deletions

File tree

src/ShadowCSS.js

Lines changed: 49 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -156,7 +156,7 @@ var ShadowCSS = {
156156
// 2. optionally tag root nodes with scope name
157157
// 3. shim polyfill directives /* @polyfill */ and /* @polyfill-rule */
158158
// 4. shim @host and scoping
159-
shimStyling: function(root, name, extendsName) {
159+
shimStyling: function(root, name, extendsName, typeExtension) {
160160
// use caching to make working with styles nodes easier and to facilitate
161161
// lookup of extendee
162162
var def = this.registerDefinition(root, name, extendsName);
@@ -168,7 +168,8 @@ var ShadowCSS = {
168168
// scoping process takes care of shimming these
169169
this.insertPolyfillDirectives(def.rootStyles);
170170
this.insertPolyfillRules(def.rootStyles);
171-
var cssText = this.stylesToShimmedCssText(def.scopeStyles, name);
171+
var cssText = this.stylesToShimmedCssText(def.scopeStyles, name,
172+
typeExtension);
172173
// note: we only need to do rootStyles since these are unscoped.
173174
cssText += this.extractPolyfillUnscopedRules(def.rootStyles);
174175
// provide shimmedStyle for user extensibility
@@ -229,14 +230,14 @@ var ShadowCSS = {
229230
* scopeName menu-item {
230231
*
231232
**/
232-
insertPolyfillDirectives: function(styles, name) {
233+
insertPolyfillDirectives: function(styles) {
233234
if (styles) {
234235
Array.prototype.forEach.call(styles, function(s) {
235236
s.textContent = this.insertPolyfillDirectivesInCssText(s.textContent);
236237
}, this);
237238
}
238239
},
239-
insertPolyfillDirectivesInCssText: function(cssText, name) {
240+
insertPolyfillDirectivesInCssText: function(cssText) {
240241
return cssText.replace(cssPolyfillCommentRe, function(match, p1) {
241242
// remove end comment delimiter and add block start
242243
return p1.slice(0, -2) + '{';
@@ -255,14 +256,14 @@ var ShadowCSS = {
255256
* scopeName menu-item {...}
256257
*
257258
**/
258-
insertPolyfillRules: function(styles, name) {
259+
insertPolyfillRules: function(styles) {
259260
if (styles) {
260261
Array.prototype.forEach.call(styles, function(s) {
261262
s.textContent = this.insertPolyfillRulesInCssText(s.textContent);
262263
}, this);
263264
}
264265
},
265-
insertPolyfillRulesInCssText: function(cssText, name) {
266+
insertPolyfillRulesInCssText: function(cssText) {
266267
return cssText.replace(cssPolyfillRuleCommentRe, function(match, p1) {
267268
// remove end comment delimiter
268269
return p1.slice(0, -1);
@@ -300,42 +301,44 @@ var ShadowCSS = {
300301
return r;
301302
},
302303
// apply @host and scope shimming
303-
stylesToShimmedCssText: function(styles, name) {
304-
return this.shimAtHost(styles, name) + this.shimScoping(styles, name);
304+
stylesToShimmedCssText: function(styles, name, typeExtension) {
305+
return this.shimAtHost(styles, name, typeExtension) +
306+
this.shimScoping(styles, name, typeExtension);
305307
},
306308
// form: @host { .foo { declarations } }
307309
// becomes: scopeName.foo { declarations }
308-
shimAtHost: function(styles, name) {
310+
shimAtHost: function(styles, name, typeExtension) {
309311
if (styles) {
310-
return this.convertAtHostStyles(styles, name);
312+
return this.convertAtHostStyles(styles, name, typeExtension);
311313
}
312314
},
313-
convertAtHostStyles: function(styles, name) {
315+
convertAtHostStyles: function(styles, name, typeExtension) {
314316
var cssText = stylesToCssText(styles), self = this;
315317
cssText = cssText.replace(hostRuleRe, function(m, p1) {
316-
return self.scopeHostCss(p1, name);
318+
return self.scopeHostCss(p1, name, typeExtension);
317319
});
318320
cssText = rulesToCss(this.findAtHostRules(cssToRules(cssText),
319321
new RegExp('^' + name + selectorReSuffix, 'm')));
320322
return cssText;
321323
},
322-
scopeHostCss: function(cssText, name) {
324+
scopeHostCss: function(cssText, name, typeExtension) {
323325
var self = this;
324326
return cssText.replace(selectorRe, function(m, p1, p2) {
325-
return self.scopeHostSelector(p1, name) + ' ' + p2 + '\n\t';
327+
return self.scopeHostSelector(p1, name, typeExtension) + ' ' + p2 + '\n\t';
326328
});
327329
},
328330
// supports scopig by name and [is=name] syntax
329-
scopeHostSelector: function(selector, name) {
331+
scopeHostSelector: function(selector, name, typeExtension) {
330332
var r = [], parts = selector.split(','), is = '[is=' + name + ']';
331333
parts.forEach(function(p) {
332334
p = p.trim();
333335
// selector: *|:scope -> name
334336
if (p.match(hostElementRe)) {
335-
p = p.replace(hostElementRe, name + '$1$3, ' + is + '$1$3');
336-
// selector: .foo -> name.foo, [bar] -> name[bar]
337+
p = p.replace(hostElementRe, typeExtension ? is + '$1$3' :
338+
name + '$1$3');
339+
// selector: .foo -> name.foo (OR) [bar] -> name[bar]
337340
} else if (p.match(hostFixableRe)) {
338-
p = name + p + ', ' + is + p;
341+
p = typeExtension ? is + p : name + p;
339342
}
340343
r.push(p);
341344
}, this);
@@ -361,19 +364,20 @@ var ShadowCSS = {
361364
*
362365
* scopeName .foo { ... }
363366
*/
364-
shimScoping: function(styles, name) {
367+
shimScoping: function(styles, name, typeExtension) {
365368
if (styles) {
366-
return this.convertScopedStyles(styles, name);
369+
return this.convertScopedStyles(styles, name, typeExtension);
367370
}
368371
},
369-
convertScopedStyles: function(styles, name) {
372+
convertScopedStyles: function(styles, name, typeExtension) {
370373
var cssText = stylesToCssText(styles).replace(hostRuleRe, '');
371374
cssText = this.insertPolyfillHostInCssText(cssText);
372375
cssText = this.convertColonHost(cssText);
373376
cssText = this.convertPseudos(cssText);
374377
cssText = this.convertParts(cssText);
378+
cssText = this.convertCombinators(cssText);
375379
var rules = cssToRules(cssText);
376-
cssText = this.scopeRules(rules, name);
380+
cssText = this.scopeRules(rules, name, typeExtension);
377381
return cssText;
378382
},
379383
convertPseudos: function(cssText) {
@@ -399,12 +403,18 @@ var ShadowCSS = {
399403
p1 + p3;
400404
});
401405
},
406+
/*
407+
* Convert ^ and ^^ combinators by replacing with space.
408+
*/
409+
convertCombinators: function(cssText) {
410+
return cssText.replace('^^', ' ').replace('^', ' ');
411+
},
402412
// change a selector like 'div' to 'name div'
403-
scopeRules: function(cssRules, name) {
413+
scopeRules: function(cssRules, name, typeExtension) {
404414
var cssText = '';
405415
Array.prototype.forEach.call(cssRules, function(rule) {
406416
if (rule.selectorText && (rule.style && rule.style.cssText)) {
407-
cssText += this.scopeSelector(rule.selectorText, name,
417+
cssText += this.scopeSelector(rule.selectorText, name, typeExtension,
408418
this.strictStyling) + ' {\n\t';
409419
cssText += this.propertiesFromRule(rule) + '\n}\n\n';
410420
} else if (rule.media) {
@@ -417,37 +427,31 @@ var ShadowCSS = {
417427
}, this);
418428
return cssText;
419429
},
420-
scopeSelector: function(selector, name, strict) {
430+
scopeSelector: function(selector, name, typeExtension, strict) {
421431
var r = [], parts = selector.split(',');
422432
parts.forEach(function(p) {
423433
p = p.trim();
424-
if (this.selectorNeedsScoping(p, name)) {
434+
if (this.selectorNeedsScoping(p, name, typeExtension)) {
425435
p = strict ? this.applyStrictSelectorScope(p, name) :
426-
this.applySimpleSelectorScope(p, name);
436+
this.applySimpleSelectorScope(p, name, typeExtension);
427437
}
428438
r.push(p);
429439
}, this);
430440
return r.join(', ');
431441
},
432-
selectorNeedsScoping: function(selector, name) {
433-
var matchScope = '(' + name + '|\\[is=' + name + '\\])';
434-
var re = new RegExp('^' + matchScope + selectorReSuffix, 'm');
442+
selectorNeedsScoping: function(selector, name, typeExtension) {
443+
var matchScope = typeExtension ? name : '\\[is=' + name + '\\]';
444+
var re = new RegExp('^(' + matchScope + ')' + selectorReSuffix, 'm');
435445
return !selector.match(re);
436446
},
437-
insertPolyfillHostInCssText: function(selector) {
438-
return selector.replace(hostRe, polyfillHost).replace(colonHostRe,
439-
polyfillHost);
440-
},
441447
// scope via name and [is=name]
442-
applySimpleSelectorScope: function(selector, name) {
443-
var is = '[is=' + name + ']';
448+
applySimpleSelectorScope: function(selector, name, typeExtension) {
449+
var scoper = typeExtension ? '[is=' + name + ']' : name;
444450
if (selector.match(polyfillHostRe)) {
445-
selector = selector.replace(polyfillHostNoCombinator, name) + ', ' +
446-
selector.replace(polyfillHostNoCombinator, is);
447-
return selector.replace(polyfillHostRe, name + ' ') + ', ' +
448-
selector.replace(polyfillHostRe, is + ' ');
451+
selector = selector.replace(polyfillHostNoCombinator, scoper);
452+
return selector.replace(polyfillHostRe, scoper + ' ');
449453
} else {
450-
return name + ' ' + selector + ', ' + is + ' ' + selector;
454+
return scoper + ' ' + selector;
451455
}
452456
},
453457
// return a selector with [name] suffix on each simple selector
@@ -469,6 +473,10 @@ var ShadowCSS = {
469473
});
470474
return scoped;
471475
},
476+
insertPolyfillHostInCssText: function(selector) {
477+
return selector.replace(hostRe, polyfillHost).replace(colonHostRe,
478+
polyfillHost);
479+
},
472480
propertiesFromRule: function(rule) {
473481
var properties = rule.style.cssText;
474482
// TODO(sorvell): Chrome cssom incorrectly removes quotes from the content

test/html/styling/colon-host.html

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -202,6 +202,11 @@ <h4>Expected: 20px padding</h4>
202202
chai.assert.equal(zimStyle2.paddingLeft, '20px',
203203
':host styles are loaded via external sheet in import (paddingLeft)');
204204

205+
var btn = document.querySelector('[is=x-button]');
206+
var btnStyle = getComputedStyle(btn);
207+
chai.assert.equal(btnStyle.backgroundColor, 'rgb(0, 128, 0)',
208+
':host styles are shimmed for type extension (backgroundColor)');
209+
205210
done();
206211

207212

test/html/styling/register.js

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,10 @@
44

55
function register(name, extnds, proto, templates) {
66
extendsRegistry[name] = extnds;
7+
var typeExtension = extnds && extnds.indexOf('-') < 0;
78
var names = calcExtendsNames(name);
89
if (window.ShadowDOMPolyfill) {
9-
shim(templates, names);
10+
shim(templates, names, typeExtension);
1011
}
1112

1213
var config = {
@@ -24,7 +25,7 @@
2425
}
2526
})
2627
};
27-
if (extnds && extnds.indexOf('-') < 0) {
28+
if (typeExtension) {
2829
config.extends = extnds;
2930
}
3031
var ctor = document.register(name, config);
@@ -44,10 +45,10 @@
4445
return document.querySelector('#' + name);
4546
}
4647

47-
function shim(templates, names) {
48+
function shim(templates, names, typeExtension) {
4849
var n = names[names.length-1];
4950
var template = templateForName(n);
50-
Platform.ShadowCSS.shimStyling(template ? template.content : null, n, extendsRegistry[n]);
51+
Platform.ShadowCSS.shimStyling(template ? template.content : null, n, extendsRegistry[n], typeExtension);
5152
}
5253

5354
scope.register = register;

0 commit comments

Comments
 (0)