@@ -139,14 +139,6 @@ export class ShadowCss {
139139
140140 constructor ( ) { }
141141
142- /*
143- * Shim a style element with the given selector. Returns cssText that can
144- * be included in the document via WebComponents.ShadowCSS.addCssToDocument(css).
145- */
146- shimStyle ( cssText : string , selector : string , hostSelector : string = '' ) : string {
147- return this . shimCssText ( cssText , selector , hostSelector ) ;
148- }
149-
150142 /*
151143 * Shim some cssText with the given selector. Returns cssText that can
152144 * be included in the document via WebComponents.ShadowCSS.addCssToDocument(css).
@@ -156,12 +148,12 @@ export class ShadowCss {
156148 * - hostSelector is the attribute added to the host itself.
157149 */
158150 shimCssText ( cssText : string , selector : string , hostSelector : string = '' ) : string {
151+ cssText = stripComments ( cssText ) ;
159152 cssText = this . _insertDirectives ( cssText ) ;
160153 return this . _scopeCssText ( cssText , selector , hostSelector ) ;
161154 }
162155
163- /** @internal */
164- _insertDirectives ( cssText : string ) : string {
156+ private _insertDirectives ( cssText : string ) : string {
165157 cssText = this . _insertPolyfillDirectivesInCssText ( cssText ) ;
166158 return this . _insertPolyfillRulesInCssText ( cssText ) ;
167159 }
@@ -180,8 +172,7 @@ export class ShadowCss {
180172 * scopeName menu-item {
181173 *
182174 **/
183- /** @internal */
184- _insertPolyfillDirectivesInCssText ( cssText : string ) : string {
175+ private _insertPolyfillDirectivesInCssText ( cssText : string ) : string {
185176 // Difference with webcomponents.js: does not handle comments
186177 return StringWrapper . replaceAllMapped ( cssText , _cssContentNextSelectorRe ,
187178 function ( m ) { return m [ 1 ] + '{' ; } ) ;
@@ -202,8 +193,7 @@ export class ShadowCss {
202193 * scopeName menu-item {...}
203194 *
204195 **/
205- /** @internal */
206- _insertPolyfillRulesInCssText ( cssText : string ) : string {
196+ private _insertPolyfillRulesInCssText ( cssText : string ) : string {
207197 // Difference with webcomponents.js: does not handle comments
208198 return StringWrapper . replaceAllMapped ( cssText , _cssContentRuleRe , function ( m ) {
209199 var rule = m [ 0 ] ;
@@ -221,8 +211,7 @@ export class ShadowCss {
221211 *
222212 * scopeName .foo { ... }
223213 */
224- /** @internal */
225- _scopeCssText ( cssText : string , scopeSelector : string , hostSelector : string ) : string {
214+ private _scopeCssText ( cssText : string , scopeSelector : string , hostSelector : string ) : string {
226215 var unscoped = this . _extractUnscopedRulesFromCssText ( cssText ) ;
227216 cssText = this . _insertPolyfillHostInCssText ( cssText ) ;
228217 cssText = this . _convertColonHost ( cssText ) ;
@@ -250,8 +239,7 @@ export class ShadowCss {
250239 * menu-item {...}
251240 *
252241 **/
253- /** @internal */
254- _extractUnscopedRulesFromCssText ( cssText : string ) : string {
242+ private _extractUnscopedRulesFromCssText ( cssText : string ) : string {
255243 // Difference with webcomponents.js: does not handle comments
256244 var r = '' , m ;
257245 var matcher = RegExpWrapper . matcher ( _cssContentUnscopedRuleRe , cssText ) ;
@@ -271,8 +259,7 @@ export class ShadowCss {
271259 *
272260 * scopeName.foo > .bar
273261 */
274- /** @internal */
275- _convertColonHost ( cssText : string ) : string {
262+ private _convertColonHost ( cssText : string ) : string {
276263 return this . _convertColonRule ( cssText , _cssColonHostRe , this . _colonHostPartReplacer ) ;
277264 }
278265
@@ -291,14 +278,12 @@ export class ShadowCss {
291278 *
292279 * scopeName.foo .bar { ... }
293280 */
294- /** @internal */
295- _convertColonHostContext ( cssText : string ) : string {
281+ private _convertColonHostContext ( cssText : string ) : string {
296282 return this . _convertColonRule ( cssText , _cssColonHostContextRe ,
297283 this . _colonHostContextPartReplacer ) ;
298284 }
299285
300- /** @internal */
301- _convertColonRule ( cssText : string , regExp : RegExp , partReplacer : Function ) : string {
286+ private _convertColonRule ( cssText : string , regExp : RegExp , partReplacer : Function ) : string {
302287 // p1 = :host, p2 = contents of (), p3 rest of rule
303288 return StringWrapper . replaceAllMapped ( cssText , regExp , function ( m ) {
304289 if ( isPresent ( m [ 2 ] ) ) {
@@ -316,70 +301,46 @@ export class ShadowCss {
316301 } ) ;
317302 }
318303
319- /** @internal */
320- _colonHostContextPartReplacer ( host : string , part : string , suffix : string ) : string {
304+ private _colonHostContextPartReplacer ( host : string , part : string , suffix : string ) : string {
321305 if ( StringWrapper . contains ( part , _polyfillHost ) ) {
322306 return this . _colonHostPartReplacer ( host , part , suffix ) ;
323307 } else {
324308 return host + part + suffix + ', ' + part + ' ' + host + suffix ;
325309 }
326310 }
327311
328- /** @internal */
329- _colonHostPartReplacer ( host : string , part : string , suffix : string ) : string {
312+ private _colonHostPartReplacer ( host : string , part : string , suffix : string ) : string {
330313 return host + StringWrapper . replace ( part , _polyfillHost , '' ) + suffix ;
331314 }
332315
333316 /*
334317 * Convert combinators like ::shadow and pseudo-elements like ::content
335318 * by replacing with space.
336319 */
337- /** @internal */
338- _convertShadowDOMSelectors ( cssText : string ) : string {
320+ private _convertShadowDOMSelectors ( cssText : string ) : string {
339321 for ( var i = 0 ; i < _shadowDOMSelectorsRe . length ; i ++ ) {
340322 cssText = StringWrapper . replaceAll ( cssText , _shadowDOMSelectorsRe [ i ] , ' ' ) ;
341323 }
342324 return cssText ;
343325 }
344326
345327 // change a selector like 'div' to 'name div'
346- /** @internal */
347- _scopeSelectors ( cssText : string , scopeSelector : string , hostSelector : string ) : string {
348- var parts = splitCurlyBlocks ( cssText ) ;
349- var result = [ ] ;
350- for ( var i = 0 ; i < parts . length ; i += 2 ) {
351- var selectorTextWithCommands = parts [ i ] ;
352- var selectorStart = selectorTextWithCommands . lastIndexOf ( ';' ) + 1 ;
353- var selectorText =
354- selectorTextWithCommands . substring ( selectorStart , selectorTextWithCommands . length ) ;
355- var ruleContent = parts [ i + 1 ] ;
356- var selectorMatch = RegExpWrapper . firstMatch ( _singleSelectorRe , selectorText ) ;
357- if ( isPresent ( selectorMatch ) && ruleContent . length > 0 ) {
358- var selPrefix = selectorMatch [ 1 ] ;
359- var selAt = isPresent ( selectorMatch [ 2 ] ) ? selectorMatch [ 2 ] : '' ;
360- var selector = selectorMatch [ 3 ] ;
361- var selSuffix = selectorMatch [ 4 ] ;
362- if ( selAt . length === 0 || selAt == '@page' ) {
363- var scopedSelector =
364- this . _scopeSelector ( selector , scopeSelector , hostSelector , this . strictStyling ) ;
365- selectorText = `${ selPrefix } ${ selAt } ${ scopedSelector } ${ selSuffix } ` ;
366- } else if ( selAt == '@media' && ruleContent [ 0 ] == OPEN_CURLY &&
367- ruleContent [ ruleContent . length - 1 ] == CLOSE_CURLY ) {
368- var scopedContent = this . _scopeSelectors ( ruleContent . substring ( 1 , ruleContent . length - 1 ) ,
369- scopeSelector , hostSelector ) ;
370- ruleContent = `${ OPEN_CURLY } ${ scopedContent } ${ CLOSE_CURLY } ` ;
371- }
328+ private _scopeSelectors ( cssText : string , scopeSelector : string , hostSelector : string ) : string {
329+ return processRules ( cssText , ( rule : CssRule ) => {
330+ var selector = rule . selector ;
331+ var content = rule . content ;
332+ if ( rule . selector [ 0 ] != '@' || rule . selector . startsWith ( '@page' ) ) {
333+ selector =
334+ this . _scopeSelector ( rule . selector , scopeSelector , hostSelector , this . strictStyling ) ;
335+ } else if ( rule . selector . startsWith ( '@media' ) ) {
336+ content = this . _scopeSelectors ( rule . content , scopeSelector , hostSelector ) ;
372337 }
373- result . push ( selectorTextWithCommands . substring ( 0 , selectorStart ) ) ;
374- result . push ( selectorText ) ;
375- result . push ( ruleContent ) ;
376- }
377- return result . join ( '' ) ;
338+ return new CssRule ( selector , content ) ;
339+ } ) ;
378340 }
379341
380- /** @internal */
381- _scopeSelector ( selector : string , scopeSelector : string , hostSelector : string ,
382- strict : boolean ) : string {
342+ private _scopeSelector ( selector : string , scopeSelector : string , hostSelector : string ,
343+ strict : boolean ) : string {
383344 var r = [ ] , parts = selector . split ( ',' ) ;
384345 for ( var i = 0 ; i < parts . length ; i ++ ) {
385346 var p = parts [ i ] ;
@@ -394,30 +355,28 @@ export class ShadowCss {
394355 return r . join ( ', ' ) ;
395356 }
396357
397- /** @internal */
398- _selectorNeedsScoping ( selector : string , scopeSelector : string ) : boolean {
358+ private _selectorNeedsScoping ( selector : string , scopeSelector : string ) : boolean {
399359 var re = this . _makeScopeMatcher ( scopeSelector ) ;
400360 return ! isPresent ( RegExpWrapper . firstMatch ( re , selector ) ) ;
401361 }
402362
403- /** @internal */
404- _makeScopeMatcher ( scopeSelector : string ) : RegExp {
363+ private _makeScopeMatcher ( scopeSelector : string ) : RegExp {
405364 var lre = / \[ / g;
406365 var rre = / \] / g;
407366 scopeSelector = StringWrapper . replaceAll ( scopeSelector , lre , '\\[' ) ;
408367 scopeSelector = StringWrapper . replaceAll ( scopeSelector , rre , '\\]' ) ;
409368 return RegExpWrapper . create ( '^(' + scopeSelector + ')' + _selectorReSuffix , 'm' ) ;
410369 }
411370
412- /** @internal */
413- _applySelectorScope ( selector : string , scopeSelector : string , hostSelector : string ) : string {
371+ private _applySelectorScope ( selector : string , scopeSelector : string ,
372+ hostSelector : string ) : string {
414373 // Difference from webcomponentsjs: scopeSelector could not be an array
415374 return this . _applySimpleSelectorScope ( selector , scopeSelector , hostSelector ) ;
416375 }
417376
418377 // scope via name and [is=name]
419- /** @internal */
420- _applySimpleSelectorScope ( selector : string , scopeSelector : string , hostSelector : string ) : string {
378+ private _applySimpleSelectorScope ( selector : string , scopeSelector : string ,
379+ hostSelector : string ) : string {
421380 if ( isPresent ( RegExpWrapper . firstMatch ( _polyfillHostRe , selector ) ) ) {
422381 var replaceBy = this . strictStyling ? `[${ hostSelector } ]` : scopeSelector ;
423382 selector = StringWrapper . replace ( selector , _polyfillHostNoCombinator , replaceBy ) ;
@@ -428,9 +387,8 @@ export class ShadowCss {
428387 }
429388
430389 // return a selector with [name] suffix on each simple selector
431- // e.g. .foo.bar > .zot becomes .foo[name].bar[name] > .zot[name]
432- /** @internal */
433- _applyStrictSelectorScope ( selector : string , scopeSelector : string ) : string {
390+ // e.g. .foo.bar > .zot becomes .foo[name].bar[name] > .zot[name] /** @internal */
391+ private _applyStrictSelectorScope ( selector : string , scopeSelector : string ) : string {
434392 var isRe = / \[ i s = ( [ ^ \] ] * ) \] / g;
435393 scopeSelector = StringWrapper . replaceAllMapped ( scopeSelector , isRe , ( m ) => m [ 1 ] ) ;
436394 var splits = [ ' ' , '>' , '+' , '~' ] , scoped = selector , attrName = '[' + scopeSelector + ']' ;
@@ -455,8 +413,7 @@ export class ShadowCss {
455413 return scoped ;
456414 }
457415
458- /** @internal */
459- _insertPolyfillHostInCssText ( selector : string ) : string {
416+ private _insertPolyfillHostInCssText ( selector : string ) : string {
460417 selector = StringWrapper . replaceAll ( selector , _colonHostContextRe , _polyfillHostContext ) ;
461418 selector = StringWrapper . replaceAll ( selector , _colonHostRe , _polyfillHost ) ;
462419 return selector ;
@@ -493,34 +450,72 @@ var _polyfillHostRe = RegExpWrapper.create(_polyfillHost, 'im');
493450var _colonHostRe = / : h o s t / gim;
494451var _colonHostContextRe = / : h o s t - c o n t e x t / gim;
495452
496- var _singleSelectorRe = / ^ ( \s * ) ( @ \S + ) ? ( .* ?) ( \s * ) $ / g;
453+ var _commentRe = / \/ \* [ \s \S ] * ?\* \/ / g;
454+
455+ function stripComments ( input :string ) :string {
456+ return StringWrapper . replaceAllMapped ( input , _commentRe , ( _ ) => '' ) ;
457+ }
497458
459+ var _ruleRe = / ( \s * ) ( [ ^ ; \{ \} ] + ?) ( \s * ) ( (?: { % B L O C K % } ? \s * ; ? ) | (?: \s * ; ) ) / g;
498460var _curlyRe = / ( [ { } ] ) / g;
499- var OPEN_CURLY = '{' ;
500- var CLOSE_CURLY = '}' ;
461+ const OPEN_CURLY = '{' ;
462+ const CLOSE_CURLY = '}' ;
463+ const BLOCK_PLACEHOLDER = '%BLOCK%' ;
501464
502- export function splitCurlyBlocks ( cssText :string ) :string [ ] {
503- var parts = StringWrapper . split ( cssText , _curlyRe ) ;
504- var result = [ ] ;
465+ export class CssRule {
466+ constructor ( public selector :string , public content :string ) { }
467+ }
468+
469+ export function processRules ( input :string , ruleCallback :Function ) :string {
470+ var inputWithEscapedBlocks = escapeBlocks ( input ) ;
471+ var nextBlockIndex = 0 ;
472+ return StringWrapper . replaceAllMapped ( inputWithEscapedBlocks . escapedString , _ruleRe , function ( m ) {
473+ var selector = m [ 2 ] ;
474+ var content = '' ;
475+ var suffix = m [ 4 ] ;
476+ var contentPrefix = '' ;
477+ if ( isPresent ( m [ 4 ] ) && m [ 4 ] . startsWith ( '{' + BLOCK_PLACEHOLDER ) ) {
478+ content = inputWithEscapedBlocks . blocks [ nextBlockIndex ++ ] ;
479+ suffix = m [ 4 ] . substring ( BLOCK_PLACEHOLDER . length + 1 ) ;
480+ contentPrefix = '{' ;
481+ }
482+ var rule = ruleCallback ( new CssRule ( selector , content ) ) ;
483+ return `${ m [ 1 ] } ${ rule . selector } ${ m [ 3 ] } ${ contentPrefix } ${ rule . content } ${ suffix } ` ;
484+ } ) ;
485+ }
486+
487+ class StringWithEscapedBlocks {
488+ constructor ( public escapedString :string , public blocks :string [ ] ) { }
489+ }
490+
491+ function escapeBlocks ( input :string ) :StringWithEscapedBlocks {
492+ var inputParts = StringWrapper . split ( input , _curlyRe ) ;
493+ var resultParts = [ ] ;
494+ var escapedBlocks = [ ] ;
505495 var bracketCount = 0 ;
506- var currentCurlyParts = [ ] ;
507- for ( var partIndex = 0 ; partIndex < parts . length ; partIndex ++ ) {
508- var part = parts [ partIndex ] ;
509- currentCurlyParts . push ( part ) ;
510- if ( part == OPEN_CURLY ) {
511- bracketCount ++ ;
512- } else if ( part == CLOSE_CURLY ) {
496+ var currentBlockParts = [ ] ;
497+ for ( var partIndex = 0 ; partIndex < inputParts . length ; partIndex ++ ) {
498+ var part = inputParts [ partIndex ] ;
499+ if ( part == CLOSE_CURLY ) {
513500 bracketCount -- ;
514501 }
515- if ( bracketCount === 0 ) {
516- result . push ( currentCurlyParts . join ( '' ) ) ;
517- currentCurlyParts = [ ] ;
502+ if ( bracketCount > 0 ) {
503+ currentBlockParts . push ( part ) ;
504+ } else {
505+ if ( currentBlockParts . length > 0 ) {
506+ escapedBlocks . push ( currentBlockParts . join ( '' ) ) ;
507+ resultParts . push ( BLOCK_PLACEHOLDER ) ;
508+ currentBlockParts = [ ] ;
509+ }
510+ resultParts . push ( part ) ;
511+ }
512+ if ( part == OPEN_CURLY ) {
513+ bracketCount ++ ;
518514 }
519515 }
520- result . push ( currentCurlyParts . join ( '' ) ) ;
521- if ( result . length >= 2 && result [ result . length - 1 ] == '' && result [ result . length - 2 ] == '' ) {
522- result = result . slice ( 0 , result . length - 2 ) ;
516+ if ( currentBlockParts . length > 0 ) {
517+ escapedBlocks . push ( currentBlockParts . join ( '' ) ) ;
518+ resultParts . push ( BLOCK_PLACEHOLDER ) ;
523519 }
524- return result ;
520+ return new StringWithEscapedBlocks ( resultParts . join ( '' ) , escapedBlocks ) ;
525521}
526-
0 commit comments