@webqit/oohtml 3.2.0 → 4.0.1

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.
@@ -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, getOwnerNamespaceObject, getNamespaceUUID } from '../namespaced-html/index.js';
6
+ import { _init, _toHash } from '../util.js';
7
7
 
8
8
  /**
9
9
  * @init
@@ -13,11 +13,11 @@ import { _init, _toHash, _splitOuter } from '../util.js';
13
13
  export default function init({ advanced = {}, ...$config }) {
14
14
  const { config, window } = _init.call( this, 'scoped-css', $config, {
15
15
  api: { styleSheets: 'styleSheets' },
16
- style: { retention: 'retain', mimeType: '', strategy: null },
16
+ style: { retention: 'retain', mimeTypes: 'text/css', strategy: null },
17
17
  } );
18
- config.styleSelector = (Array.isArray( config.style.mimeType ) ? config.style.mimeType : [ config.style.mimeType ] ).reduce( ( selector, mm ) => {
19
- const qualifier = mm ? `[type=${ window.CSS.escape( mm ) }]` : '';
20
- return selector.concat( `style${ qualifier }[scoped]` );
18
+ config.styleSelector = (Array.isArray( config.style.mimeTypes ) ? config.style.mimeTypes : config.style.mimeTypes.split( '|' ) ).concat( '' ).reduce( ( selector, mm ) => {
19
+ const qualifier = mm ? `[type="${ window.CSS.escape( mm ) }"]` : ':not([type])';
20
+ return selector.concat( `style${ qualifier }` );
21
21
  }, [] ).join( ',' );
22
22
  window.webqit.oohtml.Style = {
23
23
  compileCache: new Map,
@@ -62,80 +62,91 @@ function realtime( config ) {
62
62
  record.entrants.forEach( style => {
63
63
  if ( handled.has( style ) ) return;
64
64
  handled.add( style );
65
- if ( !style.scoped ) return;
66
65
  // Do compilation
67
66
  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 );
67
+ const supportsHAS = CSS.supports( 'selector(:has(a,b))' );
68
+ const scopeSelector = style.scoped && ( supportsHAS ? `:has(> style[rand-${ sourceHash }])` : `[rand-${ sourceHash }]` );
69
+ const supportsScope = style.scoped && window.CSSScopeRule && false/* Disabled for buggy behaviour: rewriting selectorText within an @scope block invalidates the scoping */;
70
+ if ( style.scoped ) {
71
+ style.parentNode[ config.api.styleSheets ].push( style );
72
+ ( supportsHAS ? style : style.parentNode ).toggleAttribute( `rand-${ sourceHash }`, true );
73
+ }
74
+ if ( style.scoped && style.hasAttribute( 'shared' ) ) {
75
+ let compiledSheet;
76
+ if ( !( compiledSheet = oohtml.Style.compileCache.get( sourceHash ) ) ) {
77
+ compiledSheet = createAdoptableStylesheet.call( window, style, null, supportsScope, scopeSelector );
78
+ oohtml.Style.compileCache.set( sourceHash, compiledSheet );
79
+ }
80
+ // Run now!!!
81
+ Object.defineProperty( style, 'sheet', { value: compiledSheet, configurable: true } );
82
+ style.textContent = '\n/*[ Shared style sheet ]*/\n';
83
+ } else {
84
+ const transform = () => {
85
+ const namespaceUUID = getNamespaceUUID( getOwnerNamespaceObject.call( window, style.scoped ? style : window.document ) );
86
+ upgradeSheet.call( this, style.sheet, namespaceUUID, !supportsScope && scopeSelector );
87
+ };
88
+ if ( style.isConnected ) { transform(); }
89
+ else { setTimeout( () => { transform(); }, 0 ); }
74
90
  }
75
- // Run now!!!
76
- style.parentNode[ config.api.styleSheets ].push( style );
77
- Object.defineProperty( style, 'sheet', { value: compiledSheet, configurable: true } );
78
- ( supportsHAS ? style : style.parentNode ).toggleAttribute( `rand-${ sourceHash }`, true );
79
- style.textContent = '\n/*[ Shared style sheet ]*/\n';
80
91
  } );
81
92
  }, { live: true, timing: 'intercept', generation: 'entrants' } );
82
93
  // ---
83
94
  }
84
95
 
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 */;
87
- let styleSheet, cssText = supportsScope ? `@scope (${ scopeSelector }) {\n${ textContent.trim() }\n}` : textContent.trim();
96
+ function createAdoptableStylesheet( style, namespaceUUID, supportsScope, scopeSelector ) {
97
+ const window = this, textContent = style.textContent;
98
+ let styleSheet, cssText = supportsScope && scopeSelector ? `@scope (${ scopeSelector }) {\n${ textContent.trim() }\n}` : textContent.trim();
88
99
  try {
89
100
  styleSheet = new window.CSSStyleSheet;
90
101
  styleSheet.replaceSync( cssText );
91
- upgradeSheet( styleSheet, !supportsScope && scopeSelector );
102
+ upgradeSheet.call( this, styleSheet, namespaceUUID, !supportsScope && scopeSelector );
92
103
  document.adoptedStyleSheets.push( styleSheet );
93
104
  } catch( e ) {
94
105
  const style = window.document.createElement( 'style' );
95
106
  window.document.body.appendChild( style );
96
107
  style.textContent = cssText;
97
108
  styleSheet = style.sheet;
98
- upgradeSheet( styleSheet, !supportsScope && scopeSelector );
109
+ upgradeSheet.call( this, styleSheet, namespaceUUID, !supportsScope && scopeSelector );
99
110
  }
100
111
  return styleSheet;
101
112
  }
102
113
 
103
- function upgradeSheet( styleSheet, scopeSelector = null ) {
114
+ function upgradeSheet( styleSheet, namespaceUUID, scopeSelector = null ) {
104
115
  const l = styleSheet?.cssRules.length || -1;
105
116
  for ( let i = 0; i < l; ++i ) {
106
117
  const cssRule = styleSheet.cssRules[ i ];
107
118
  if ( cssRule instanceof CSSImportRule ) {
108
119
  // Handle imported stylesheets
109
- //upgradeSheet( cssRule.styleSheet, scopeSelector );
120
+ //upgradeSheet( cssRule.styleSheet, namespaceUUID, scopeSelector );
110
121
  continue;
111
122
  }
112
- upgradeRule( cssRule, scopeSelector );
123
+ upgradeRule.call( this, cssRule, namespaceUUID, scopeSelector );
113
124
  }
114
125
  }
115
126
 
116
- function upgradeRule( cssRule, scopeSelector = null ) {
127
+ function upgradeRule( cssRule, namespaceUUID, scopeSelector = null ) {
117
128
  if ( cssRule instanceof CSSStyleRule ) {
118
129
  // Resolve relative IDs and scoping (for non-@scope browsers)
119
- upgradeSelector( cssRule, scopeSelector );
130
+ upgradeSelector.call( this, cssRule, namespaceUUID, scopeSelector );
120
131
  return;
121
132
  }
122
133
  if ( [ window.CSSScopeRule, window.CSSMediaRule, window.CSSContainerRule, window.CSSSupportsRule, window.CSSLayerBlockRule ].some( type => type && cssRule instanceof type ) ) {
123
134
  // Parse @rule blocks
124
135
  const l = cssRule.cssRules.length;
125
136
  for ( let i = 0; i < l; ++i ) {
126
- upgradeRule( cssRule.cssRules[ i ], scopeSelector );
137
+ upgradeRule.call( this, cssRule.cssRules[ i ], namespaceUUID, scopeSelector );
127
138
  }
128
139
  }
129
140
  }
130
141
 
131
- function upgradeSelector( cssRule, scopeSelector = null ) {
132
- const newSelectorText = rewriteSelector( cssRule.selectorText, scopeSelector, true );
142
+ function upgradeSelector( cssRule, namespaceUUID, scopeSelector = null ) {
143
+ const newSelectorText = rewriteSelector.call( this, cssRule.selectorText, namespaceUUID, scopeSelector, 1 );
133
144
  cssRule.selectorText = newSelectorText;
134
145
  // Parse nested blocks. (CSS nesting)
135
146
  if ( cssRule.cssRules ) {
136
147
  const l = cssRule.cssRules.length;
137
148
  for ( let i = 0; i < l; ++i ) {
138
- upgradeSelector( cssRule.cssRules[ i ], /* Nesting has nothing to do with scopeSelector */ );
149
+ upgradeSelector.call( this, cssRule.cssRules[ i ], namespaceUUID, /* Nesting has nothing to do with scopeSelector */ );
139
150
  }
140
151
  }
141
152
  }
@@ -3,7 +3,7 @@
3
3
  * @imports
4
4
  */
5
5
  import { resolveParams } from '@webqit/quantum-js/params';
6
- import { _init, _toHash, _fromHash } from '../util.js';
6
+ import { _, _init, _toHash, _fromHash } from '../util.js';
7
7
 
8
8
  /**
9
9
  * @init
@@ -12,13 +12,13 @@ import { _init, _toHash, _fromHash } from '../util.js';
12
12
  */
13
13
  export default function init({ advanced = {}, ...$config }) {
14
14
  const { config, window } = _init.call( this, 'scoped-js', $config, {
15
- script: { retention: 'retain', mimeType: '' },
15
+ script: { retention: 'retain', mimeTypes: 'module|text/javascript|application/javascript' },
16
16
  api: { scripts: 'scripts' },
17
17
  advanced: resolveParams(advanced),
18
18
  } );
19
- config.scriptSelector = ( Array.isArray( config.script.mimeType ) ? config.script.mimeType : [ config.script.mimeType ] ).reduce( ( selector, mm ) => {
20
- const qualifier = mm ? `[type=${ window.CSS.escape( mm ) } ]` : '';
21
- return selector.concat( `script${ qualifier }[scoped],script${ qualifier }[quantum]` );
19
+ config.scriptSelector = ( Array.isArray( config.script.mimeTypes ) ? config.script.mimeTypes : config.script.mimeTypes.split( '|' ) ).concat( '' ).reduce( ( selector, mm ) => {
20
+ const qualifier = mm ? `[type="${ window.CSS.escape( mm ) }"]` : ':not([type])';
21
+ return selector.concat( `script${ qualifier }` );
22
22
  }, [] ).join( ',' );
23
23
  window.webqit.oohtml.Script = {
24
24
  compileCache: [ new Map, new Map, ],
@@ -71,9 +71,13 @@ async function execute( config, execHash ) {
71
71
  script.textContent = await compiledScript.toString();
72
72
  }
73
73
  // Execute and save state
74
- const state = ( await compiledScript.bind( thisContext ) ).execute();
74
+ const documentRoot = script.getRootNode();
75
+ if ( !_( documentRoot ).has( 'scriptEnv' ) ) {
76
+ _( documentRoot ).set( 'scriptEnv', Object.create( null ) );
77
+ }
78
+ const state = ( await compiledScript.bind( thisContext, _( documentRoot ).get( 'scriptEnv' ) ) ).execute();
75
79
  if ( script.quantum ) { Object.defineProperty( script, 'state', { value: state } ); }
76
- realdom.realtime( window.document ).observe( script, () => {
80
+ realdom.realtime( documentRoot ).observe( script, () => {
77
81
  if ( script.quantum ) { state.dispose(); }
78
82
  if ( script.scoped ) { thisContext[ config.api.scripts ].splice( thisContext[ config.api.scripts ].indexOf( script, 1 ) ); }
79
83
  }, { subtree: true, timing: 'sync', generation: 'exits' } );
@@ -87,25 +91,26 @@ async function execute( config, execHash ) {
87
91
  * @return Void
88
92
  */
89
93
  function realtime( config ) {
90
- const window = this, { webqit: { oohtml, realdom, QuantumScript, QuantumAsyncScript, QuantumModule } } = window;
91
- if ( !window.HTMLScriptElement.supports ) { window.HTMLScriptElement.supports = () => false; }
92
- const potentialManualTypes = [ 'module' ].concat( config.script.mimeType || [] ), handled = new WeakSet;
94
+ const window = this, { webqit: { oohtml, realdom, QuantumScript, AsyncQuantumScript, QuantumModule } } = window;
95
+ if ( !window.HTMLScriptElement.supports ) { window.HTMLScriptElement.supports = type => [ 'text/javascript', 'application/javascript' ].includes( type ); }
96
+ const handled = new WeakSet;
93
97
  realdom.realtime( window.document ).subtree/*instead of observe(); reason: jsdom timing*/( config.scriptSelector, record => {
94
98
  record.entrants.forEach( script => {
95
99
  if ( handled.has( script ) ) return;
100
+ const textContent = ( script._ = script.textContent.trim() ) && script._.startsWith( '/*@oohtml*/if(false){' ) && script._.endsWith( '}/*@oohtml*/' ) ? script._.slice( 21, -12 ) : script.textContent;
101
+ if ( !script.scoped && !script.quantum && !textContent.includes( 'quantum' ) ) return;
96
102
  handled.add( script );
97
103
  // Do compilation
98
- const textContent = ( script._ = script.textContent.trim() ) && script._.startsWith( '/*@oohtml*/if(false){' ) && script._.endsWith( '}/*@oohtml*/' ) ? script._.slice( 21, -12 ) : script.textContent;
99
104
  const sourceHash = _toHash( textContent );
100
105
  const compileCache = oohtml.Script.compileCache[ script.quantum ? 0 : 1 ];
101
106
  let compiledScript;
102
107
  if ( !( compiledScript = compileCache.get( sourceHash ) ) ) {
103
108
  const { parserParams, compilerParams, runtimeParams } = config.advanced;
104
- compiledScript = new ( script.type === 'module' ? QuantumModule : (QuantumScript || QuantumAsyncScript) )( textContent, {
109
+ compiledScript = new ( script.type === 'module' ? QuantumModule : ( QuantumScript || AsyncQuantumScript ) )( textContent, {
105
110
  exportNamespace: `#${ script.id }`,
106
111
  fileName: `${ window.document.url?.split( '#' )?.[ 0 ] || '' }#${ script.id }`,
107
- parserParams,
108
- compilerParams: { ...compilerParams, startStatic: !script.quantum },
112
+ parserParams: { ...parserParams, quantumMode: script.quantum },
113
+ compilerParams,
109
114
  runtimeParams,
110
115
  } );
111
116
  compileCache.set( sourceHash, compiledScript );
@@ -114,7 +119,7 @@ function realtime( config ) {
114
119
  const thisContext = script.scoped ? script.parentNode || record.target : ( script.type === 'module' ? undefined : window );
115
120
  if ( script.scoped ) { thisContext[ config.api.scripts ].push( script ); }
116
121
  const execHash = _toHash( { script, compiledScript, thisContext } );
117
- const manualHandling = record.type === 'query' || ( potentialManualTypes.includes( script.type ) && !window.HTMLScriptElement.supports( script.type ) );
122
+ const manualHandling = record.type === 'query' || ( script.type && !window.HTMLScriptElement.supports( script.type ) );
118
123
  if ( manualHandling ) { oohtml.Script.execute( execHash ); } else {
119
124
  script.textContent = `webqit.oohtml.Script.execute( '${ execHash }' );`;
120
125
  }
package/src/util.js CHANGED
@@ -42,6 +42,17 @@ export function _init( name, $config, $defaults ) {
42
42
  return { config: window.webqit.oohtml.configs[ configKey ], realdom, window };
43
43
  }
44
44
 
45
+ export function getInternalAttrInteraction( node, attrName ) {
46
+ return _internals( node, 'internalAttrInteractions' ).get( attrName );
47
+ }
48
+ export function internalAttrInteraction( node, attrName, callback ) {
49
+ const savedAttrLocking = _internals( node, 'internalAttrInteractions' ).get( attrName );
50
+ _internals( node, 'internalAttrInteractions' ).set( attrName, true );
51
+ const value = callback();
52
+ _internals( node, 'internalAttrInteractions' ).set( attrName, savedAttrLocking );
53
+ return value;
54
+ }
55
+
45
56
  export function _compare( a, b, depth = 1, objectSizing = false ) {
46
57
  if ( depth && typeof a === 'object' && a && typeof b === 'object' && b && ( !objectSizing || Object.keys( a ).length === Object.keys( b ).length ) ) {
47
58
  for ( let key in a ) {
package/src/api.global.js DELETED
@@ -1,11 +0,0 @@
1
-
2
- /**
3
- * @imports
4
- */
5
- import * as QuantumJS from `@webqit/quantum-js`;
6
- import init from './index.js';
7
-
8
- /**
9
- * @init
10
- */
11
- init.call( window, QuantumJS );