@webqit/oohtml 3.1.13 → 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/README.md +212 -217
- package/dist/bindings-api.js +1 -1
- package/dist/bindings-api.js.map +2 -2
- package/dist/context-api.js +1 -1
- package/dist/context-api.js.map +1 -1
- package/dist/data-binding.js +8 -8
- package/dist/data-binding.js.map +2 -2
- package/dist/html-imports.js +1 -1
- package/dist/html-imports.js.map +2 -2
- package/dist/main.js +22 -24
- package/dist/main.js.map +3 -3
- package/dist/main.lite.js +20 -22
- package/dist/main.lite.js.map +3 -3
- package/dist/namespaced-html.js +1 -1
- package/dist/namespaced-html.js.map +3 -3
- package/dist/scoped-css.js +1 -3
- package/dist/scoped-css.js.map +3 -3
- package/dist/scoped-js.js +1 -1
- package/dist/scoped-js.js.map +3 -3
- package/package.json +2 -2
- package/src/bindings-api/DOMBindingsContext.js +1 -1
- package/src/bindings-api/index.js +21 -21
- package/src/data-binding/index.js +4 -19
- package/src/html-imports/HTMLImportsContext.js +1 -3
- package/src/html-imports/index.js +7 -1
- package/src/index.js +3 -3
- package/src/namespaced-html/DOMNamingContext.js +54 -0
- package/src/namespaced-html/index.js +287 -60
- package/src/scoped-css/index.js +114 -16
- package/src/scoped-js/index.js +48 -25
- package/src/util.js +38 -0
- package/test/scoped-css.test.js +2 -2
- package/src/scoped-js/Hash.js +0 -26
package/src/scoped-js/index.js
CHANGED
|
@@ -3,34 +3,63 @@
|
|
|
3
3
|
* @imports
|
|
4
4
|
*/
|
|
5
5
|
import { resolveParams } from '@webqit/quantum-js/params';
|
|
6
|
-
import { _init } from '../util.js';
|
|
7
|
-
import Hash from './Hash.js';
|
|
6
|
+
import { _init, _toHash, _fromHash } from '../util.js';
|
|
8
7
|
|
|
9
8
|
/**
|
|
10
9
|
* @init
|
|
11
10
|
*
|
|
12
11
|
* @param Object $config
|
|
13
12
|
*/
|
|
14
|
-
export default function init(
|
|
13
|
+
export default function init({ advanced = {}, ...$config }) {
|
|
15
14
|
const { config, window } = _init.call( this, 'scoped-js', $config, {
|
|
16
15
|
script: { retention: 'retain', mimeType: '' },
|
|
17
|
-
|
|
16
|
+
api: { scripts: 'scripts' },
|
|
17
|
+
advanced: resolveParams(advanced),
|
|
18
18
|
} );
|
|
19
|
-
|
|
20
|
-
const qualifier = mm ? `[type=${ window.CSS.escape( mm ) }]` : '';
|
|
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
21
|
return selector.concat( `script${ qualifier }[scoped],script${ qualifier }[quantum]` );
|
|
22
22
|
}, [] ).join( ',' );
|
|
23
23
|
window.webqit.oohtml.Script = {
|
|
24
24
|
compileCache: [ new Map, new Map, ],
|
|
25
25
|
execute: execute.bind( window, config ),
|
|
26
26
|
};
|
|
27
|
+
exposeAPIs.call( window, config );
|
|
27
28
|
realtime.call( window, config );
|
|
28
29
|
}
|
|
29
30
|
|
|
31
|
+
/**
|
|
32
|
+
* Exposes Bindings with native APIs.
|
|
33
|
+
*
|
|
34
|
+
* @param Object config
|
|
35
|
+
*
|
|
36
|
+
* @return Void
|
|
37
|
+
*/
|
|
38
|
+
function exposeAPIs( config ) {
|
|
39
|
+
const window = this, scriptsMap = new Map;
|
|
40
|
+
if ( config.api.scripts in window.Element.prototype ) { throw new Error( `The "Element" class already has a "${ config.api.scripts }" property!` ); }
|
|
41
|
+
Object.defineProperty( window.HTMLElement.prototype, config.api.scripts, { get: function() {
|
|
42
|
+
if ( !scriptsMap.has( this ) ) { scriptsMap.set( this, [] ); }
|
|
43
|
+
return scriptsMap.get( this );
|
|
44
|
+
}, } );
|
|
45
|
+
Object.defineProperties( window.HTMLScriptElement.prototype, {
|
|
46
|
+
scoped: {
|
|
47
|
+
configurable: true,
|
|
48
|
+
get() { return this.hasAttribute( 'scoped' ); },
|
|
49
|
+
set( value ) { this.toggleAttribute( 'scoped', value ); },
|
|
50
|
+
},
|
|
51
|
+
quantum: {
|
|
52
|
+
configurable: true,
|
|
53
|
+
get() { return this.hasAttribute( 'quantum' ); },
|
|
54
|
+
set( value ) { this.toggleAttribute( 'quantum', value ); },
|
|
55
|
+
},
|
|
56
|
+
} );
|
|
57
|
+
}
|
|
58
|
+
|
|
30
59
|
// Script runner
|
|
31
60
|
async function execute( config, execHash ) {
|
|
32
61
|
const window = this, { realdom } = window.webqit;
|
|
33
|
-
const exec =
|
|
62
|
+
const exec = _fromHash( execHash );
|
|
34
63
|
if ( !exec ) throw new Error( `Argument must be a valid exec hash.` );
|
|
35
64
|
const { script, compiledScript, thisContext } = exec;
|
|
36
65
|
// Honour retention flag
|
|
@@ -46,7 +75,7 @@ async function execute( config, execHash ) {
|
|
|
46
75
|
if ( script.quantum ) { Object.defineProperty( script, 'state', { value: state } ); }
|
|
47
76
|
realdom.realtime( window.document ).observe( script, () => {
|
|
48
77
|
if ( script.quantum ) { state.dispose(); }
|
|
49
|
-
if ( script.scoped ) { thisContext.scripts.splice( thisContext.scripts.indexOf( script, 1 ) ); }
|
|
78
|
+
if ( script.scoped ) { thisContext[ config.api.scripts ].splice( thisContext[ config.api.scripts ].indexOf( script, 1 ) ); }
|
|
50
79
|
}, { subtree: true, timing: 'sync', generation: 'exits' } );
|
|
51
80
|
}
|
|
52
81
|
|
|
@@ -58,26 +87,23 @@ async function execute( config, execHash ) {
|
|
|
58
87
|
* @return Void
|
|
59
88
|
*/
|
|
60
89
|
function realtime( config ) {
|
|
61
|
-
|
|
90
|
+
const window = this, { webqit: { oohtml, realdom, QuantumScript, QuantumAsyncScript, QuantumModule } } = window;
|
|
62
91
|
if ( !window.HTMLScriptElement.supports ) { window.HTMLScriptElement.supports = () => false; }
|
|
63
|
-
const potentialManualTypes = [ 'module' ].concat( config.script.mimeType || [] );
|
|
64
|
-
|
|
92
|
+
const potentialManualTypes = [ 'module' ].concat( config.script.mimeType || [] ), handled = new WeakSet;
|
|
93
|
+
realdom.realtime( window.document ).subtree/*instead of observe(); reason: jsdom timing*/( config.scriptSelector, record => {
|
|
65
94
|
record.entrants.forEach( script => {
|
|
66
|
-
if (
|
|
67
|
-
|
|
68
|
-
Object.defineProperty( script, 'quantum', { value: script.hasAttribute( 'quantum' ) } );
|
|
69
|
-
if ( 'scoped' in script ) return handled( script );
|
|
70
|
-
Object.defineProperty( script, 'scoped', { value: script.hasAttribute( 'scoped' ) } );
|
|
95
|
+
if ( handled.has( script ) ) return;
|
|
96
|
+
handled.add( script );
|
|
71
97
|
// Do compilation
|
|
72
98
|
const textContent = ( script._ = script.textContent.trim() ) && script._.startsWith( '/*@oohtml*/if(false){' ) && script._.endsWith( '}/*@oohtml*/' ) ? script._.slice( 21, -12 ) : script.textContent;
|
|
73
|
-
const sourceHash =
|
|
99
|
+
const sourceHash = _toHash( textContent );
|
|
74
100
|
const compileCache = oohtml.Script.compileCache[ script.quantum ? 0 : 1 ];
|
|
75
101
|
let compiledScript;
|
|
76
102
|
if ( !( compiledScript = compileCache.get( sourceHash ) ) ) {
|
|
77
103
|
const { parserParams, compilerParams, runtimeParams } = config.advanced;
|
|
78
|
-
compiledScript = new ( script.type === 'module' ? QuantumModule : (
|
|
104
|
+
compiledScript = new ( script.type === 'module' ? QuantumModule : (QuantumScript || QuantumAsyncScript) )( textContent, {
|
|
79
105
|
exportNamespace: `#${ script.id }`,
|
|
80
|
-
fileName
|
|
106
|
+
fileName: `${ window.document.url?.split( '#' )?.[ 0 ] || '' }#${ script.id }`,
|
|
81
107
|
parserParams,
|
|
82
108
|
compilerParams: { ...compilerParams, startStatic: !script.quantum },
|
|
83
109
|
runtimeParams,
|
|
@@ -86,16 +112,13 @@ function realtime( config ) {
|
|
|
86
112
|
}
|
|
87
113
|
// Run now!!!
|
|
88
114
|
const thisContext = script.scoped ? script.parentNode || record.target : ( script.type === 'module' ? undefined : window );
|
|
89
|
-
if ( script.scoped ) {
|
|
90
|
-
|
|
91
|
-
thisContext.scripts.push( script );
|
|
92
|
-
}
|
|
93
|
-
const execHash = Hash.toHash( { script, compiledScript, thisContext } );
|
|
115
|
+
if ( script.scoped ) { thisContext[ config.api.scripts ].push( script ); }
|
|
116
|
+
const execHash = _toHash( { script, compiledScript, thisContext } );
|
|
94
117
|
const manualHandling = record.type === 'query' || ( potentialManualTypes.includes( script.type ) && !window.HTMLScriptElement.supports( script.type ) );
|
|
95
118
|
if ( manualHandling ) { oohtml.Script.execute( execHash ); } else {
|
|
96
119
|
script.textContent = `webqit.oohtml.Script.execute( '${ execHash }' );`;
|
|
97
120
|
}
|
|
98
121
|
} );
|
|
99
|
-
|
|
122
|
+
}, { live: true, timing: 'intercept', generation: 'entrants', eventDetails: true } );
|
|
100
123
|
// ---
|
|
101
124
|
}
|
package/src/util.js
CHANGED
|
@@ -53,4 +53,42 @@ export function _compare( a, b, depth = 1, objectSizing = false ) {
|
|
|
53
53
|
return ( b = b.slice( 0 ).sort() ) && a.slice( 0 ).sort().every( ( valueA, i ) => valueA === b[ i ] );
|
|
54
54
|
}
|
|
55
55
|
return a === b;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
export function _splitOuter( str, delim ) {
|
|
59
|
+
return [ ...str ].reduce( ( [ quote, depth, splits ], x ) => {
|
|
60
|
+
if ( !quote && depth === 0 && ( Array.isArray( delim ) ? delim : [ delim ] ).includes( x ) ) {
|
|
61
|
+
return [ quote, depth, [ '' ].concat( splits ) ];
|
|
62
|
+
}
|
|
63
|
+
if ( !quote && [ '(', '[', '{' ].includes( x ) && !splits[ 0 ].endsWith( '\\' ) ) depth++;
|
|
64
|
+
if ( !quote && [ ')', ']', '}' ].includes( x ) && !splits[ 0 ].endsWith( '\\' ) ) depth--;
|
|
65
|
+
if ( [ '"', "'", '`' ].includes( x ) && !splits[ 0 ].endsWith( '\\' ) ) {
|
|
66
|
+
quote = quote === x ? null : ( quote || x );
|
|
67
|
+
}
|
|
68
|
+
splits[ 0 ] += x;
|
|
69
|
+
return [ quote, depth, splits ]
|
|
70
|
+
}, [ null, 0, [ '' ] ] )[ 2 ].reverse();
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
// Unique ID generator
|
|
74
|
+
export const _uniqId = () => ( 0 | Math.random() * 9e6 ).toString( 36 );
|
|
75
|
+
|
|
76
|
+
// Hash of anything generator
|
|
77
|
+
const hashTable = new Map;
|
|
78
|
+
export function _toHash( val ) {
|
|
79
|
+
let hash;
|
|
80
|
+
if ( !( hash = hashTable.get( val ) ) ) {
|
|
81
|
+
hash = _uniqId();
|
|
82
|
+
hashTable.set( val, hash );
|
|
83
|
+
}
|
|
84
|
+
return hash;
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
// Value of any hash
|
|
88
|
+
export function _fromHash( hash ) {
|
|
89
|
+
let val;
|
|
90
|
+
hashTable.forEach( ( _hash, _val ) => {
|
|
91
|
+
if ( _hash === hash ) val = _val;
|
|
92
|
+
} );
|
|
93
|
+
return val;
|
|
56
94
|
}
|
package/test/scoped-css.test.js
CHANGED
|
@@ -10,7 +10,7 @@ describe(`Test: Scoped CSS`, function() {
|
|
|
10
10
|
describe(`Styles`, function() {
|
|
11
11
|
|
|
12
12
|
it(`Should do basic rewrite`, async function() {
|
|
13
|
-
const head = '
|
|
13
|
+
const head = '', body = `
|
|
14
14
|
<div>
|
|
15
15
|
<h1>Hello World!</h1>
|
|
16
16
|
<style scoped>
|
|
@@ -24,7 +24,7 @@ describe(`Test: Scoped CSS`, function() {
|
|
|
24
24
|
await delay( 160 ); // Takes time to dynamically load Reflex compiler
|
|
25
25
|
const styleElement = window.document.querySelector( 'style' );
|
|
26
26
|
|
|
27
|
-
expect( styleElement.textContent.substring( 0, 13 ) ).to.eq( '@scope
|
|
27
|
+
//expect( styleElement.textContent.substring( 0, 13 ) ).to.eq( '@scope (' );
|
|
28
28
|
});
|
|
29
29
|
|
|
30
30
|
});
|
package/src/scoped-js/Hash.js
DELETED
|
@@ -1,26 +0,0 @@
|
|
|
1
|
-
|
|
2
|
-
export default class Hash {
|
|
3
|
-
|
|
4
|
-
// Unique ID generator
|
|
5
|
-
static hashTable = new Map;
|
|
6
|
-
static uniqId = () => (0|Math.random()*9e6).toString(36);
|
|
7
|
-
|
|
8
|
-
// Hash of anything generator
|
|
9
|
-
static toHash( val ) {
|
|
10
|
-
let hash;
|
|
11
|
-
if ( !( hash = this.hashTable.get( val ) ) ) {
|
|
12
|
-
hash = this.uniqId();
|
|
13
|
-
this.hashTable.set( val, hash );
|
|
14
|
-
}
|
|
15
|
-
return hash;
|
|
16
|
-
}
|
|
17
|
-
|
|
18
|
-
// Value of any hash
|
|
19
|
-
static fromHash( hash ) {
|
|
20
|
-
let val;
|
|
21
|
-
this.hashTable.forEach( ( _hash, _val ) => {
|
|
22
|
-
if ( _hash === hash ) val = _val;
|
|
23
|
-
} );
|
|
24
|
-
return val;
|
|
25
|
-
}
|
|
26
|
-
}
|