@webqit/oohtml 3.1.14 → 3.1.15

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -14,7 +14,7 @@
14
14
  "wicg-proposal"
15
15
  ],
16
16
  "homepage": "https://webqit.io/tooling/oohtml",
17
- "version": "3.1.14",
17
+ "version": "3.1.15",
18
18
  "license": "MIT",
19
19
  "repository": {
20
20
  "type": "git",
@@ -24,43 +24,83 @@ export default function init( $config = {} ) {
24
24
  realtime.call( window, config );
25
25
  }
26
26
 
27
+ /**
28
+ * @init
29
+ *
30
+ * @param Object config
31
+ *
32
+ * @return String
33
+ */
34
+ function lidUtil( config ) {
35
+ const { lidrefPrefix, lidrefSeparator, } = config.tokens;
36
+ return {
37
+ escape( str, mode = 1 ) { return [ ...str ].map( x => !/\w/.test( x ) ? ( mode === 2 ? `\\\\${ x }` : `\\${ x }` ) : x ).join( '' ); },
38
+ lidrefPrefix( escapeMode = 0 ) { return escapeMode ? this.escape( lidrefPrefix, escapeMode ) : lidrefPrefix; },
39
+ lidrefSeparator( escapeMode = 0 ) { return escapeMode ? this.escape( lidrefSeparator, escapeMode ) : lidrefSeparator; },
40
+ isUuid( str, escapeMode = 0 ) { return str.startsWith( this.lidrefPrefix( escapeMode ) ) && str.includes( this.lidrefSeparator( escapeMode ) ); },
41
+ isLidref( str, escapeMode = 0 ) { return str.startsWith( this.lidrefPrefix( escapeMode ) ) && !str.includes( this.lidrefSeparator( escapeMode ) ); },
42
+ toUuid( hash, lid, escapeMode = 0 ) { return `${ this.lidrefPrefix( escapeMode ) }${ hash }${ this.lidrefSeparator( escapeMode ) }${ lid }`; },
43
+ uuidToLid( str, escapeMode = 0 ) { return this.isUuid( str ) ? str.split( this.lidrefSeparator( escapeMode ) )[ 1 ] : str; },
44
+ uuidToLidref( str, escapeMode = 0 ) { return this.isUuid( str ) ? `${ this.lidrefPrefix( escapeMode ) }${ str.split( this.lidrefSeparator( escapeMode ) )[ 1 ] }` : str; },
45
+ }
46
+ }
47
+
27
48
  /**
28
49
  * @rewriteSelector
29
50
  *
30
51
  * @param String selectorText
52
+ * @param String namespaceUUID
31
53
  * @param String scopeSelector
32
- * @param Bool isCssSelector
54
+ * @param Bool escapeMode
55
+ *
56
+ * @return String
33
57
  */
34
- export function rewriteSelector( selectorText, scopeSelector = null, isCssSelector = false ) {
58
+ export function rewriteSelector( selectorText, namespaceUUID, scopeSelector = null, escapeMode = 0 ) {
35
59
  const window = this, { webqit: { oohtml: { configs: { NAMESPACED_HTML: config } } } } = window;
36
- const { lidrefPrefix, lidrefSeparator } = config.tokens;
60
+ const $lidUtil = lidUtil( config );
37
61
  // Match :scope and relative ID selector
38
- const regex = new RegExp( `${ scopeSelector ? `:scope|` : '' }#${ [ ...lidrefPrefix ].map( x => !/\w/.test( x ) ? ( !isCssSelector ? `\\${ x }` : `\\\\${ x }` ) : x ).join( '' ) }([\\w-]|\\\\.)+`, 'g' );
62
+ const regex = new RegExp( `${ scopeSelector ? `:scope|` : '' }#(${ $lidUtil.lidrefPrefix( escapeMode + 1 ) })?([\\w]+${ $lidUtil.lidrefSeparator( escapeMode + 1 ) })?((?:[\\w-]|\\\\.)+)`, 'g' );
39
63
  // Parse potentially combined selectors individually and categorise into categories per whether they have :scope or not
40
64
  const [ cat1, cat2 ] = _splitOuter( selectorText, ',' ).reduce( ( [ cat1, cat2 ], selector ) => {
41
65
  // The deal: match and replace
42
66
  let quotesMatch, hadScopeSelector;
43
- selector = selector.replace( regex, ( match, unused/**/, index ) => {
67
+ selector = selector.replace( regex, ( match, lidrefPrefixMatch, lidrefSeparatorMatch, id, index ) => {
44
68
  if ( !quotesMatch ) { // Lazy: stuff
45
69
  // Match strings between quotes (single or double) and use that qualify matches above
46
70
  // The string: String.raw`She said, "Hello, John. I\"m your friend." or "you're he're" 'f\'"j\'"f'jfjf`;
47
71
  // Should yield: `"Hello, John. I\\"m your friend."`, `"you're he're"`, `'f\\'"j\\'"f'`
48
72
  quotesMatch = [ ...selector.matchAll( /(["'])(?:(?=(\\?))\2.)*?\1/g ) ];
49
73
  }
74
+ if ( quotesMatch[ 0 ] )
50
75
  // Qualify match
51
- if ( quotesMatch.some( q => index > q.index && index + match.length < q.index + match.length ) ) return match;
76
+ if ( quotesMatch.some( q => index > q.index && index + match.length < q.index + q[ 0 ].length ) ) return match;
52
77
  // Replace :scope
53
78
  if ( match === ':scope' ) {
54
79
  hadScopeSelector = true;
55
80
  return scopeSelector;
56
81
  }
57
- // Replace relative ID selector
58
- const lidref = match.replace( `#${ !isCssSelector ? lidrefPrefix : [ ...lidrefPrefix ].map( x => !/\w/.test( x ) ? `\\${ x }` : x ).join( '' ) }`, '' );
82
+ const isLidref = lidrefPrefixMatch && !lidrefSeparatorMatch;
83
+ const isUuid = lidrefPrefixMatch && lidrefSeparatorMatch;
84
+ if ( isUuid ) {
85
+ return `#${ $lidUtil.escape( match.replace( '#', '' ), 1 ) }`;
86
+ }
87
+ // Rewrite relative ID selector
88
+ let lowerBoundFactor = false;
89
+ if ( isLidref ) {
90
+ if ( config.attr.lid === 'id' && namespaceUUID ) {
91
+ return `#${ $lidUtil.toUuid( namespaceUUID, id, 1 ) }`;
92
+ }
93
+ // Fallback to attr-based
94
+ lowerBoundFactor = true;
95
+ }
96
+ // Rewrite absolute ID selector
97
+ let rewrite;
59
98
  if ( config.attr.lid === 'id' ) {
60
- return `[id^="${ lidrefPrefix }"][id$="${ lidrefSeparator }${ lidref }"]`;
99
+ rewrite = `[id^="${ $lidUtil.lidrefPrefix( escapeMode ) }"][id$="${ $lidUtil.lidrefSeparator( escapeMode ) }${ id }"]`;
61
100
  } else {
62
- return `[${ window.CSS.escape( config.attr.lid ) }="${ lidref }"]`;
101
+ rewrite = `:is(#${ id },[${ window.CSS.escape( config.attr.lid ) }="${ id }"])`;
63
102
  }
103
+ return scopeSelector && lowerBoundFactor ? `:is(${ rewrite }):not(${ scopeSelector } [${ config.attr.namespace }] *)` : rewrite;
64
104
  } );
65
105
  // Category 2 has :scope and category 1 does not
66
106
  return hadScopeSelector ? [ cat1, cat2.concat( selector ) ] : [ cat1.concat( selector ), cat2 ];
@@ -82,7 +122,7 @@ export function rewriteSelector( selectorText, scopeSelector = null, isCssSelect
82
122
  *
83
123
  * @return Object
84
124
  */
85
- function getNamespaceObject( node ) {
125
+ export function getNamespaceObject( node ) {
86
126
  if ( !_( node ).has( 'namespace' ) ) {
87
127
  const namespaceObj = Object.create( null );
88
128
  _( node ).set( 'namespace', namespaceObj );
@@ -90,6 +130,17 @@ function getNamespaceObject( node ) {
90
130
  return _( node ).get( 'namespace' );
91
131
  }
92
132
 
133
+ /**
134
+ * @param Element node
135
+ *
136
+ * @return String
137
+ */
138
+ export function getNamespaceUUID( node ) {
139
+ const window = this, { webqit: { oohtml: { configs: { NAMESPACED_HTML: config } } } } = window;
140
+ const namespaceObj = getNamespaceObject( node instanceof window.Document ? node : ( node.closest( `[${ config.attr.namespace }]` ) || node.ownerDocument ) );
141
+ return _fromHash( namespaceObj ) || _toHash( namespaceObj );
142
+ }
143
+
93
144
  /**
94
145
  * Exposes Namespaced HTML with native APIs.
95
146
  *
@@ -120,7 +171,6 @@ function exposeAPIs( config ) {
120
171
  */
121
172
  function realtime( config ) {
122
173
  const window = this, { webqit: { Observer, realdom, oohtml: { configs }, DOMNamingContext } } = window;
123
- const { lidrefPrefix, lidrefSeparator } = config.tokens;
124
174
 
125
175
  // ------------
126
176
  // NAMESPACE
@@ -149,31 +199,25 @@ function realtime( config ) {
149
199
  const idRefAttrs = [ 'for', 'list', 'form', 'aria-activedescendant', 'aria-details', 'aria-errormessage', ];
150
200
  const attrList = [ config.attr.lid, ...idRefsAttrs, ...idRefAttrs ];
151
201
  const relMap = { id: 'id'/* just in case it's in attrList */, for: 'htmlFor', 'aria-owns': 'ariaOwns', 'aria-controls': 'ariaControls', 'aria-labelledby': 'ariaLabelledBy', 'aria-describedby': 'ariaDescribedBy', 'aria-flowto': 'ariaFlowto', 'aria-activedescendant': 'ariaActiveDescendant', 'aria-details': 'ariaDetails', 'aria-errormessage': 'ariaErrorMessage' };
152
- const isUuid = str => str.startsWith( lidrefPrefix ) && str.includes( lidrefSeparator );
153
- const isLidref = str => str.startsWith( lidrefPrefix ) && !str.includes( lidrefSeparator );
154
- const toUuid = ( hash, lid ) => `${ lidrefPrefix }${ hash }${ lidrefSeparator }${ lid }`;
155
- const uuidToLid = str => isUuid( str ) ? str.split( lidrefSeparator )[ 1 ] : str;
156
- const uuidToLidref = str => isUuid( str ) ? `${ lidrefPrefix }${ str.split( lidrefSeparator )[ 1 ] }` : str;
202
+ const $lidUtil = lidUtil( config );
157
203
 
158
204
  // Intercept getAttribute()
159
- const getAttribute = Object.getOwnPropertyDescriptor( window.Element.prototype, 'getAttribute' );
160
- Object.defineProperty( window.Element.prototype, 'getAttribute', { ...getAttribute, value( attrName ) {
161
- const value = getAttribute.value.call( this, attrName );
162
- return !_( this, 'lock' ).get( attrName ) && attrList.includes( attrName ) ? ( attrName === 'id' ? uuidToLid : uuidToLidref )( value ) : value;
205
+ const getAttributeDescr = Object.getOwnPropertyDescriptor( window.Element.prototype, 'getAttribute' );
206
+ Object.defineProperty( window.Element.prototype, 'getAttribute', { ...getAttributeDescr, value( attrName ) {
207
+ const value = getAttributeDescr.value.call( this, attrName );
208
+ return !_( this, 'lock' ).get( attrName ) && attrList.includes( attrName ) ? ( attrName === 'id' ? $lidUtil.uuidToLid : $lidUtil.uuidToLidref ).call( $lidUtil, value ) : value;
163
209
  } } );
164
210
  // Intercept getElementById()
165
- const getElementById = Object.getOwnPropertyDescriptor( window.Document.prototype, 'getElementById' );
166
- Object.defineProperty( window.Document.prototype, 'getElementById', { ...getElementById, value( id ) {
167
- if ( !isLidref( id ) ) return getElementById.value.call( this, id );
168
- const node = this.querySelector( rewriteSelector.call( window, `#${ id }` ) );
169
- return node;// !node?.closest( config.namespaceSelector ) ? node : null; // Cool, but not consistent with querySelector(All)() results
211
+ const getElementByIdDescr = Object.getOwnPropertyDescriptor( window.Document.prototype, 'getElementById' );
212
+ Object.defineProperty( window.Document.prototype, 'getElementById', { ...getElementByIdDescr, value( id ) {
213
+ return this.querySelector( `#${ id }`/* Will be rewritten at querySelector() */ );
170
214
  } } );
171
215
  // Intercept querySelector() and querySelectorAll()
172
216
  for ( const queryApi of [ 'querySelector', 'querySelectorAll' ] ) {
173
217
  for ( nodeApi of [ window.Document, window.Element ] ) {
174
- const querySelector = Object.getOwnPropertyDescriptor( nodeApi.prototype, queryApi );
175
- Object.defineProperty( nodeApi.prototype, queryApi, { ...querySelector, value( selector ) {
176
- return querySelector.value.call( this, rewriteSelector.call( window, selector ) );
218
+ const querySelectorDescr = Object.getOwnPropertyDescriptor( nodeApi.prototype, queryApi );
219
+ Object.defineProperty( nodeApi.prototype, queryApi, { ...querySelectorDescr, value( selector ) {
220
+ return querySelectorDescr.value.call( this, rewriteSelector.call( window, selector, getNamespaceUUID.call( window, this ) ) );
177
221
  } } );
178
222
  }
179
223
  }
@@ -182,15 +226,21 @@ function realtime( config ) {
182
226
  if ( !( attrName in relMap ) ) continue;
183
227
  const domApis = attrName === 'for' ? [ window.HTMLLabelElement, window.HTMLOutputElement ] : [ window.Element ];
184
228
  for ( const domApi of domApis ) {
185
- const idReflection = Object.getOwnPropertyDescriptor( domApi.prototype, relMap[ attrName ] );
186
- if ( !idReflection ) continue;
187
- Object.defineProperty( domApi.prototype, relMap[ attrName ], { ...idReflection, get() {
188
- return ( attrName === 'id' ? uuidToLid : uuidToLidref )( idReflection.get.call( this, attrName ) || '' );
229
+ const propertyDescr = Object.getOwnPropertyDescriptor( domApi.prototype, relMap[ attrName ] );
230
+ if ( !propertyDescr ) continue;
231
+ Object.defineProperty( domApi.prototype, relMap[ attrName ], { ...propertyDescr, get() {
232
+ return ( attrName === 'id' ? $lidUtil.uuidToLid : $lidUtil.uuidToLidref ).call( $lidUtil, propertyDescr.get.call( this, attrName ) || '' );
189
233
  } } );
190
234
  }
191
235
  }
192
- // Reflect the custom [config.attr.lid] attribute
236
+ // Hide implementation details on the Attr node too.
237
+ const propertyDescr = Object.getOwnPropertyDescriptor( window.Attr.prototype, 'value' );
238
+ Object.defineProperty( window.Attr.prototype, 'value', { ...propertyDescr, get() {
239
+ const value = propertyDescr.get.call( this );
240
+ return attrList.includes( this.name ) ? ( this.name === 'id' ? $lidUtil.uuidToLid : $lidUtil.uuidToLidref ).call( $lidUtil, value ) : value;
241
+ } } );
193
242
  if ( config.attr.lid !== 'id' ) {
243
+ // Reflect the custom [config.attr.lid] attribute
194
244
  Object.defineProperty( window.Element.prototype, config.attr.lid, { configurable: true, enumerable: true, get() {
195
245
  return this.getAttribute( config.attr.lid );
196
246
  }, set( value ) {
@@ -210,10 +260,10 @@ function realtime( config ) {
210
260
  // Get down to work
211
261
  const namespaceObj = _( entry ).get( 'ownerNamespace' );
212
262
  if ( attrName === config.attr.lid ) {
213
- const lid = uuidToLid( oldValue );
263
+ const lid = $lidUtil.uuidToLid( oldValue );
214
264
  if ( Observer.get( namespaceObj, lid ) === entry ) { Observer.deleteProperty( namespaceObj, lid ); }
215
265
  } else {
216
- const newAttrValue = oldValue.split( ' ' ).map( lid => ( lid = lid.trim() ) && uuidToLidref( lid ) ).join( ' ' );
266
+ const newAttrValue = oldValue.split( ' ' ).map( lid => ( lid = lid.trim() ) && $lidUtil.uuidToLidref( lid ) ).join( ' ' );
217
267
  entry.setAttribute( attrName, newAttrValue );
218
268
  }
219
269
  // Release locking
@@ -229,14 +279,14 @@ function realtime( config ) {
229
279
  const namespaceObj = _( entry ).get( 'ownerNamespace' );
230
280
  const namespaceUUID = _( entry ).get( 'namespaceUUID' );
231
281
  if ( attrName === config.attr.lid ) {
232
- const lid = uuidToLid( value );
282
+ const lid = $lidUtil.uuidToLid( value );
233
283
  if ( Observer.get( namespaceObj, lid ) !== entry ) {
234
284
  // Setup new namespace relationships
235
- entry.setAttribute( 'id', toUuid( namespaceUUID, lid ) );
285
+ entry.setAttribute( 'id', $lidUtil.toUuid( namespaceUUID, lid ) );
236
286
  Observer.set( namespaceObj, lid, entry );
237
287
  }
238
288
  } else {
239
- const newAttrValue = value.split( ' ' ).map( lid => ( lid = lid.trim() ) && !isLidref( lid ) ? lid : toUuid( namespaceUUID, lid.replace( lidrefPrefix, '' ) ) ).join( ' ' );
289
+ const newAttrValue = value.split( ' ' ).map( lid => ( lid = lid.trim() ) && !$lidUtil.isLidref( lid ) ? lid : $lidUtil.toUuid( namespaceUUID, lid.replace( $lidUtil.lidrefPrefix(), '' ) ) ).join( ' ' );
240
290
  entry.setAttribute( attrName, newAttrValue );
241
291
  }
242
292
  // Release locking
@@ -297,8 +347,8 @@ function realtime( config ) {
297
347
  // ------------
298
348
  let prevTarget;
299
349
  const activateTarget = () => {
300
- if ( !window.location.hash?.startsWith( `#${ lidrefPrefix }` ) ) return;
301
- const path = window.location.hash?.substring( `#${ lidrefPrefix }`.length ).split( '/' ).map( s => s.trim() ).filter( s => s ) || [];
350
+ if ( !window.location.hash?.startsWith( `#${ $lidUtil.lidrefPrefix() }` ) ) return;
351
+ const path = window.location.hash?.substring( `#${ $lidUtil.lidrefPrefix() }`.length ).split( '/' ).map( s => s.trim() ).filter( s => s ) || [];
302
352
  const currTarget = path.reduce( ( prev, segment ) => prev && prev[ config.api.namespace ][ segment ], window.document );
303
353
  if ( prevTarget && config.target.attr ) { prevTarget.toggleAttribute( config.target.attr, false ); }
304
354
  if ( currTarget && currTarget !== window.document ) {
@@ -2,8 +2,8 @@
2
2
  /**
3
3
  * @imports
4
4
  */
5
- import { rewriteSelector } from '../namespaced-html/index.js';
6
- import { _init, _toHash, _splitOuter } from '../util.js';
5
+ import { rewriteSelector, getNamespaceUUID } from '../namespaced-html/index.js';
6
+ import { _init, _toHash } from '../util.js';
7
7
 
8
8
  /**
9
9
  * @init
@@ -63,79 +63,85 @@ function realtime( config ) {
63
63
  if ( handled.has( style ) ) return;
64
64
  handled.add( style );
65
65
  if ( !style.scoped ) return;
66
+ style.parentNode[ config.api.styleSheets ].push( style );
66
67
  // Do compilation
67
68
  const sourceHash = _toHash( style.textContent );
68
- let compiledSheet, supportsHAS = CSS.supports( 'selector(:has(a,b))' );
69
- if ( !( compiledSheet = oohtml.Style.compileCache.get( sourceHash ) ) ) {
70
- const scopeSelector = supportsHAS ? `:has(> style[rand-${ sourceHash }])` : `[rand-${ sourceHash }]`;
71
- compiledSheet = createAdoptableStylesheet.call( window, style, scopeSelector );
72
- //compiledSheet = style.sheet; upgradeSheet( style.sheet, /*!window.CSSScopeRule &&*/ scopeSelector );
73
- oohtml.Style.compileCache.set( sourceHash, compiledSheet );
74
- }
75
- // Run now!!!
76
- style.parentNode[ config.api.styleSheets ].push( style );
77
- Object.defineProperty( style, 'sheet', { value: compiledSheet, configurable: true } );
69
+ const supportsHAS = CSS.supports( 'selector(:has(a,b))' );
70
+ const scopeSelector = supportsHAS ? `:has(> style[rand-${ sourceHash }])` : `[rand-${ sourceHash }]`;
71
+ const supportsScope = window.CSSScopeRule && false/* Disabled for buggy behaviour: rewriting selectorText within an @scope block invalidates the scoping */;
78
72
  ( supportsHAS ? style : style.parentNode ).toggleAttribute( `rand-${ sourceHash }`, true );
79
- style.textContent = '\n/*[ Shared style sheet ]*/\n';
73
+ if ( false ) {
74
+ let compiledSheet;
75
+ if ( !( compiledSheet = oohtml.Style.compileCache.get( sourceHash ) ) ) {
76
+ compiledSheet = createAdoptableStylesheet.call( window, style, null, supportsScope, scopeSelector );
77
+ oohtml.Style.compileCache.set( sourceHash, compiledSheet );
78
+ }
79
+ // Run now!!!
80
+ Object.defineProperty( style, 'sheet', { value: compiledSheet, configurable: true } );
81
+ style.textContent = '\n/*[ Shared style sheet ]*/\n';
82
+ } else {
83
+ const namespaceUUID = getNamespaceUUID.call( window, style );
84
+ upgradeSheet.call( this, style.sheet, namespaceUUID, !supportsScope && scopeSelector );
85
+ }
80
86
  } );
81
87
  }, { live: true, timing: 'intercept', generation: 'entrants' } );
82
88
  // ---
83
89
  }
84
90
 
85
- function createAdoptableStylesheet( style, scopeSelector ) {
86
- const window = this, textContent = style.textContent, supportsScope = window.CSSScopeRule && false/* Disabled for buggy behaviour: rewriting selectorText within an @scope block invalidates the scoping */;
91
+ function createAdoptableStylesheet( style, namespaceUUID, supportsScope, scopeSelector ) {
92
+ const window = this, textContent = style.textContent;
87
93
  let styleSheet, cssText = supportsScope ? `@scope (${ scopeSelector }) {\n${ textContent.trim() }\n}` : textContent.trim();
88
94
  try {
89
95
  styleSheet = new window.CSSStyleSheet;
90
96
  styleSheet.replaceSync( cssText );
91
- upgradeSheet( styleSheet, !supportsScope && scopeSelector );
97
+ upgradeSheet.call( this, styleSheet, namespaceUUID, !supportsScope && scopeSelector );
92
98
  document.adoptedStyleSheets.push( styleSheet );
93
99
  } catch( e ) {
94
100
  const style = window.document.createElement( 'style' );
95
101
  window.document.body.appendChild( style );
96
102
  style.textContent = cssText;
97
103
  styleSheet = style.sheet;
98
- upgradeSheet( styleSheet, !supportsScope && scopeSelector );
104
+ upgradeSheet.call( this, styleSheet, namespaceUUID, !supportsScope && scopeSelector );
99
105
  }
100
106
  return styleSheet;
101
107
  }
102
108
 
103
- function upgradeSheet( styleSheet, scopeSelector = null ) {
109
+ function upgradeSheet( styleSheet, namespaceUUID, scopeSelector = null ) {
104
110
  const l = styleSheet?.cssRules.length || -1;
105
111
  for ( let i = 0; i < l; ++i ) {
106
112
  const cssRule = styleSheet.cssRules[ i ];
107
113
  if ( cssRule instanceof CSSImportRule ) {
108
114
  // Handle imported stylesheets
109
- //upgradeSheet( cssRule.styleSheet, scopeSelector );
115
+ //upgradeSheet( cssRule.styleSheet, namespaceUUID, scopeSelector );
110
116
  continue;
111
117
  }
112
- upgradeRule( cssRule, scopeSelector );
118
+ upgradeRule.call( this, cssRule, namespaceUUID, scopeSelector );
113
119
  }
114
120
  }
115
121
 
116
- function upgradeRule( cssRule, scopeSelector = null ) {
122
+ function upgradeRule( cssRule, namespaceUUID, scopeSelector = null ) {
117
123
  if ( cssRule instanceof CSSStyleRule ) {
118
124
  // Resolve relative IDs and scoping (for non-@scope browsers)
119
- upgradeSelector( cssRule, scopeSelector );
125
+ upgradeSelector.call( this, cssRule, namespaceUUID, scopeSelector );
120
126
  return;
121
127
  }
122
128
  if ( [ window.CSSScopeRule, window.CSSMediaRule, window.CSSContainerRule, window.CSSSupportsRule, window.CSSLayerBlockRule ].some( type => type && cssRule instanceof type ) ) {
123
129
  // Parse @rule blocks
124
130
  const l = cssRule.cssRules.length;
125
131
  for ( let i = 0; i < l; ++i ) {
126
- upgradeRule( cssRule.cssRules[ i ], scopeSelector );
132
+ upgradeRule.call( this, cssRule.cssRules[ i ], namespaceUUID, scopeSelector );
127
133
  }
128
134
  }
129
135
  }
130
136
 
131
- function upgradeSelector( cssRule, scopeSelector = null ) {
132
- const newSelectorText = rewriteSelector( cssRule.selectorText, scopeSelector, true );
137
+ function upgradeSelector( cssRule, namespaceUUID, scopeSelector = null ) {
138
+ const newSelectorText = rewriteSelector.call( this, cssRule.selectorText, namespaceUUID, scopeSelector, 1 );
133
139
  cssRule.selectorText = newSelectorText;
134
140
  // Parse nested blocks. (CSS nesting)
135
141
  if ( cssRule.cssRules ) {
136
142
  const l = cssRule.cssRules.length;
137
143
  for ( let i = 0; i < l; ++i ) {
138
- upgradeSelector( cssRule.cssRules[ i ], /* Nesting has nothing to do with scopeSelector */ );
144
+ upgradeSelector.call( this, cssRule.cssRules[ i ], namespaceUUID, /* Nesting has nothing to do with scopeSelector */ );
139
145
  }
140
146
  }
141
147
  }