@@ -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
0 commit comments