@webqit/oohtml 4.1.5 → 4.1.8
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/dist/data-binding.js +11 -6
- package/dist/data-binding.js.map +3 -3
- package/dist/html-imports.js +1 -1
- package/dist/html-imports.js.map +2 -2
- package/dist/main.js +22 -17
- package/dist/main.js.map +3 -3
- package/dist/main.lite.js +19 -14
- package/dist/main.lite.js.map +3 -3
- package/dist/scoped-js.js +1 -1
- package/dist/scoped-js.js.map +2 -2
- package/package.json +1 -1
- package/src/data-binding/index.js +56 -21
- package/src/html-imports/HTMLModule.js +12 -6
- package/src/init.js +5 -5
- package/src/scoped-js/index.js +32 -18
package/package.json
CHANGED
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
/**
|
|
3
3
|
* @imports
|
|
4
4
|
*/
|
|
5
|
+
import { xpathQuery } from '@webqit/realdom/src/realtime/Util.js';
|
|
5
6
|
import { _, _init, _splitOuter } from '../util.js';
|
|
6
7
|
|
|
7
8
|
/**
|
|
@@ -38,12 +39,12 @@ function realtime( config ) {
|
|
|
38
39
|
const window = this, { webqit: { realdom } } = window;
|
|
39
40
|
// ----------------
|
|
40
41
|
realdom.realtime( window.document ).query( `(${ config.discreteBindingsSelector })`, record => {
|
|
41
|
-
cleanup.call( this, ...record.exits );
|
|
42
|
-
mountDiscreteBindings.call(
|
|
42
|
+
cleanup.call( this, ...record.exits );
|
|
43
|
+
mountDiscreteBindings.call( window, config, ...record.entrants );
|
|
43
44
|
}, { live: true, subtree: 'cross-roots', timing: 'sync' } );
|
|
44
45
|
realdom.realtime( window.document ).query( config.attrSelector, record => {
|
|
45
|
-
cleanup.call( this, ...record.exits );
|
|
46
|
-
mountInlineBindings.call(
|
|
46
|
+
cleanup.call( this, ...record.exits );
|
|
47
|
+
mountInlineBindings.call( window, config, ...record.entrants );
|
|
47
48
|
}, { live: true, subtree: 'cross-roots', timing: 'sync', staticSensitivity: true } );
|
|
48
49
|
}
|
|
49
50
|
|
|
@@ -52,10 +53,18 @@ function createDynamicScope( config, root ) {
|
|
|
52
53
|
if ( _( root ).has( 'data-binding' ) ) return _( root ).get( 'data-binding' );
|
|
53
54
|
const scope = Object.create( null ), abortController = new AbortController;
|
|
54
55
|
scope[ '$exec__' ] = ( target, prop, ...args ) => {
|
|
55
|
-
|
|
56
|
+
const exec = () => {
|
|
57
|
+
try { target[ prop ]( ...args ); }
|
|
58
|
+
catch( e ) { console.error( `${ e.message } at ${ e.cause }` ); }
|
|
59
|
+
};
|
|
60
|
+
realdom.schedule( 'write', exec );
|
|
56
61
|
};
|
|
57
62
|
scope[ '$assign__' ] = ( target, prop, val ) => {
|
|
58
|
-
|
|
63
|
+
const exec = () => {
|
|
64
|
+
try { target[ prop ] = val; }
|
|
65
|
+
catch( e ) { console.error( `${ e.message } at ${ e.cause }` ); }
|
|
66
|
+
};
|
|
67
|
+
realdom.schedule( 'write', exec );
|
|
59
68
|
};
|
|
60
69
|
Observer.intercept( scope, {
|
|
61
70
|
get: ( e, recieved, next ) => {
|
|
@@ -89,21 +98,21 @@ function cleanup( ...entries ) {
|
|
|
89
98
|
}
|
|
90
99
|
}
|
|
91
100
|
|
|
101
|
+
function patternMatch( config, str ) {
|
|
102
|
+
const tagStart = config.tokens.tagStart.split( '' ).map( x => `\\${ x }` ).join( '' );
|
|
103
|
+
const tagEnd = config.tokens.tagEnd.split( '' ).map( x => `\\${ x }` ).join( '' );
|
|
104
|
+
const stateStart = config.tokens.stateStart.split( '' ).map( x => x === ' ' ? `(?:\\s+)?` : `\\${ x }` ).join( '' );
|
|
105
|
+
const stateEnd = config.tokens.stateEnd.split( '' ).map( x => `\\${ x }` ).join( '' );
|
|
106
|
+
const pattern = `^${ tagStart }(.*?)(?:${ stateStart }(\\d+)${ stateEnd }(?:\\s+)?)?${ tagEnd }$`;
|
|
107
|
+
const [ /*raw*/, expr, span ] = str.match( new RegExp( pattern ) );
|
|
108
|
+
return { raw: str, expr, span: parseInt( span ?? 0 ) };
|
|
109
|
+
}
|
|
110
|
+
|
|
92
111
|
async function mountDiscreteBindings( config, ...entries ) {
|
|
93
112
|
const window = this;
|
|
94
|
-
const patternMatch = str => {
|
|
95
|
-
const tagStart = config.tokens.tagStart.split( '' ).map( x => `\\${ x }` ).join( '' );
|
|
96
|
-
const tagEnd = config.tokens.tagEnd.split( '' ).map( x => `\\${ x }` ).join( '' );
|
|
97
|
-
const stateStart = config.tokens.stateStart.split( '' ).map( x => x === ' ' ? `(?:\\s+)?` : `\\${ x }` ).join( '' );
|
|
98
|
-
const stateEnd = config.tokens.stateEnd.split( '' ).map( x => `\\${ x }` ).join( '' );
|
|
99
|
-
const pattern = `^${ tagStart }(.*?)(?:${ stateStart }(\\d+)${ stateEnd }(?:\\s+)?)?${ tagEnd }$`;
|
|
100
|
-
const [ /*raw*/, expr, span ] = str.match( new RegExp( pattern ) );
|
|
101
|
-
return { raw: str, expr, span: parseInt( span ?? 0 ) };
|
|
102
|
-
};
|
|
103
|
-
|
|
104
113
|
const instances = entries.reduce( ( instances, node ) => {
|
|
105
114
|
if ( node.isBound ) return instances;
|
|
106
|
-
const template = patternMatch( node.nodeValue );
|
|
115
|
+
const template = patternMatch( config, node.nodeValue );
|
|
107
116
|
let textNode = node;
|
|
108
117
|
if ( template.span ) {
|
|
109
118
|
textNode = node.nextSibling;
|
|
@@ -123,10 +132,14 @@ async function mountDiscreteBindings( config, ...entries ) {
|
|
|
123
132
|
}, [] );
|
|
124
133
|
|
|
125
134
|
for ( const { textNode, template, anchorNode } of instances ) {
|
|
126
|
-
const compiled = compileDiscreteBindings( config, template.expr );
|
|
135
|
+
const compiled = compileDiscreteBindings.call( window, config, template.expr );
|
|
127
136
|
const { scope, bindings } = createDynamicScope.call( this, config, textNode.parentNode );
|
|
128
137
|
Object.defineProperty( textNode, '$oohtml_internal_databinding_anchorNode', { value: anchorNode, configurable: true } );
|
|
129
|
-
|
|
138
|
+
try {
|
|
139
|
+
bindings.set( textNode, { state: await ( await compiled.bind( textNode, scope ) ).execute(), } );
|
|
140
|
+
} catch( e ) {
|
|
141
|
+
console.log(e);
|
|
142
|
+
}
|
|
130
143
|
}
|
|
131
144
|
}
|
|
132
145
|
|
|
@@ -144,11 +157,15 @@ function compileDiscreteBindings( config, str ) {
|
|
|
144
157
|
|
|
145
158
|
async function mountInlineBindings( config, ...entries ) {
|
|
146
159
|
for ( const node of entries ) {
|
|
147
|
-
const compiled = compileInlineBindings( config, node.getAttribute( config.attr.render ) );
|
|
160
|
+
const compiled = compileInlineBindings.call( this, config, node.getAttribute( config.attr.render ) );
|
|
148
161
|
const { scope, bindings } = createDynamicScope.call( this, config, node );
|
|
149
162
|
const signals = [];
|
|
150
163
|
Object.defineProperty( node, '$oohtml_internal_databinding_signals', { value: signals, configurable: true } );
|
|
151
|
-
|
|
164
|
+
try {
|
|
165
|
+
bindings.set( node, { signals, state: await ( await compiled.bind( node, scope ) ).execute(), } );
|
|
166
|
+
} catch( e ) {
|
|
167
|
+
console.log(e);
|
|
168
|
+
}
|
|
152
169
|
}
|
|
153
170
|
}
|
|
154
171
|
|
|
@@ -218,6 +235,13 @@ function compileInlineBindings( config, str ) {
|
|
|
218
235
|
$existing__.clear();
|
|
219
236
|
}`;
|
|
220
237
|
}
|
|
238
|
+
// Treat other "@" directives as events
|
|
239
|
+
return `
|
|
240
|
+
const handler = () => ${ arg };
|
|
241
|
+
this.addEventListener( '${ param }', handler );
|
|
242
|
+
const abort = () => this.removeEventListener( '${ param }', handler );
|
|
243
|
+
this.$oohtml_internal_databinding_signals?.push( { abort } );
|
|
244
|
+
`;
|
|
221
245
|
}
|
|
222
246
|
if ( str.trim() ) throw new Error( `Invalid binding: ${ str }.` );
|
|
223
247
|
} ).join( `\n` );
|
|
@@ -228,3 +252,14 @@ function compileInlineBindings( config, str ) {
|
|
|
228
252
|
}
|
|
229
253
|
|
|
230
254
|
const escDouble = str => str.replace(/"/g, '\\"');
|
|
255
|
+
|
|
256
|
+
export function idleCompiler( node ) {
|
|
257
|
+
const window = this, { webqit: { oohtml: { configs: { DATA_BINDING: config } } } } = window;
|
|
258
|
+
xpathQuery( window, node, `(${ config.discreteBindingsSelector })` ).forEach( node => {
|
|
259
|
+
const template = patternMatch( config, node.nodeValue );
|
|
260
|
+
compileDiscreteBindings.call( window, config, template.expr );
|
|
261
|
+
} );
|
|
262
|
+
( node?.matches( config.attrSelector ) ? [ node ] : [] ).concat([ ...( node?.querySelectorAll( config.attrSelector ) || [] ) ]).forEach( node => {
|
|
263
|
+
compileInlineBindings.call( window, config, node.getAttribute( config.attr.render ) );
|
|
264
|
+
} );
|
|
265
|
+
}
|
|
@@ -2,7 +2,6 @@
|
|
|
2
2
|
/**
|
|
3
3
|
* @imports
|
|
4
4
|
*/
|
|
5
|
-
import { _isNumeric } from '@webqit/util/js/index.js';
|
|
6
5
|
import { getDefs } from './index.js';
|
|
7
6
|
import { _, env } from '../util.js';
|
|
8
7
|
|
|
@@ -22,6 +21,7 @@ export default class HTMLModule {
|
|
|
22
21
|
const { window } = env, { webqit: { realdom, oohtml: { configs } } } = window;
|
|
23
22
|
_( host ).get( `defsmanager::instance` )?.dispose();
|
|
24
23
|
_( host ).set( `defsmanager::instance`, this );
|
|
24
|
+
this.window = window;
|
|
25
25
|
this.host = host;
|
|
26
26
|
this.config = configs.HTML_IMPORTS;
|
|
27
27
|
this.parent = parent;
|
|
@@ -31,8 +31,8 @@ export default class HTMLModule {
|
|
|
31
31
|
this.validateDefId( this.defId );
|
|
32
32
|
// ----------
|
|
33
33
|
this.realtimeA = realdom.realtime( this.host.content ).children( record => {
|
|
34
|
-
this.
|
|
35
|
-
this.
|
|
34
|
+
this.expose( record.entrants, true );
|
|
35
|
+
this.expose( record.exits, false );
|
|
36
36
|
}, { live: true, timing: 'sync' } );
|
|
37
37
|
// ----------
|
|
38
38
|
this.realtimeB = realdom.realtime( this.host ).attr( [ 'src', 'loading' ], ( ...args ) => this.evaluateLoading( ...args ), {
|
|
@@ -67,7 +67,7 @@ export default class HTMLModule {
|
|
|
67
67
|
*
|
|
68
68
|
* @returns Void
|
|
69
69
|
*/
|
|
70
|
-
|
|
70
|
+
expose( entries, isConnected ) {
|
|
71
71
|
const { window } = env, { webqit: { Observer } } = window;
|
|
72
72
|
let dirty, allFragments = this.defs[ '#' ] || [];
|
|
73
73
|
Observer.batch( this.defs, () => {
|
|
@@ -76,10 +76,16 @@ export default class HTMLModule {
|
|
|
76
76
|
const isTemplate = entry.matches( this.config.templateSelector );
|
|
77
77
|
const defId = ( entry.getAttribute( isTemplate ? this.config.attr.def : this.config.attr.fragmentdef ) || '' ).trim();
|
|
78
78
|
if ( isConnected ) {
|
|
79
|
-
if ( isTemplate && defId ) {
|
|
80
|
-
|
|
79
|
+
if ( isTemplate && defId ) {
|
|
80
|
+
new HTMLModule( entry, this.host, this.level + 1 );
|
|
81
|
+
} else {
|
|
81
82
|
allFragments.push( entry );
|
|
82
83
|
dirty = true;
|
|
84
|
+
if ( typeof requestIdleCallback === 'function' ) {
|
|
85
|
+
requestIdleCallback( () => {
|
|
86
|
+
this.config.idleCompilers?.forEach( callback => callback.call( this.window, entry ) );
|
|
87
|
+
} );
|
|
88
|
+
}
|
|
83
89
|
}
|
|
84
90
|
if ( defId ) {
|
|
85
91
|
this.validateDefId( defId );
|
package/src/init.js
CHANGED
|
@@ -3,12 +3,12 @@
|
|
|
3
3
|
* @imports
|
|
4
4
|
*/
|
|
5
5
|
import NamespacedHTML from './namespaced-html/index.js';
|
|
6
|
-
import
|
|
7
|
-
import
|
|
8
|
-
import ContextAPI from './context-api/index.js';
|
|
6
|
+
import ScopedJS, { idleCompiler as idleCompiler1 } from './scoped-js/index.js';
|
|
7
|
+
import DataBinding, { idleCompiler as idleCompiler2 } from './data-binding/index.js';
|
|
9
8
|
import BindingsAPI from './bindings-api/index.js';
|
|
10
9
|
import HTMLImports from './html-imports/index.js';
|
|
11
|
-
import
|
|
10
|
+
import ContextAPI from './context-api/index.js';
|
|
11
|
+
import ScopedCSS from './scoped-css/index.js';
|
|
12
12
|
|
|
13
13
|
/**
|
|
14
14
|
* @init
|
|
@@ -20,7 +20,7 @@ export default function init( QuantumJS, configs = {} ) {
|
|
|
20
20
|
ContextAPI.call( this, ( configs.CONTEXT_API || {} ) );
|
|
21
21
|
BindingsAPI.call( this, ( configs.BINDINGS_API || {} ) ); // Depends on ContextAPI
|
|
22
22
|
NamespacedHTML.call( this, ( configs.NAMESPACED_HTML || {} ) ); // Depends on ContextAPI
|
|
23
|
-
HTMLImports.call( this, ( configs.HTML_IMPORTS || {} ) ); // Depends on ContextAPI
|
|
23
|
+
HTMLImports.call( this, { ...( configs.HTML_IMPORTS || {} ), idleCompilers: [ idleCompiler1, idleCompiler2 ] } ); // Depends on ContextAPI
|
|
24
24
|
DataBinding.call( this, ( configs.DATA_BINDING || {} ) ); // Depends on ContextAPI, BindingsAPI, HTMLImports
|
|
25
25
|
ScopedCSS.call( this, ( configs.SCOPED_CSS || {} ) ); // Depends on NamespacedHTML
|
|
26
26
|
ScopedJS.call( this, ( configs.SCOPED_JS || {} ) );
|
package/src/scoped-js/index.js
CHANGED
|
@@ -91,30 +91,16 @@ async function execute( config, execHash ) {
|
|
|
91
91
|
* @return Void
|
|
92
92
|
*/
|
|
93
93
|
function realtime( config ) {
|
|
94
|
-
const window = this, { webqit: { oohtml, realdom
|
|
94
|
+
const window = this, { webqit: { oohtml, realdom } } = window;
|
|
95
95
|
if ( !window.HTMLScriptElement.supports ) { window.HTMLScriptElement.supports = type => [ 'text/javascript', 'application/javascript' ].includes( type ); }
|
|
96
96
|
const handled = new WeakSet;
|
|
97
97
|
realdom.realtime( window.document ).query( config.scriptSelector, record => {
|
|
98
98
|
record.entrants.forEach( script => {
|
|
99
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;
|
|
102
|
-
handled.add( script );
|
|
103
100
|
// Do compilation
|
|
104
|
-
const
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
if ( !( compiledScript = compileCache.get( sourceHash ) ) ) {
|
|
108
|
-
const { parserParams, compilerParams, runtimeParams } = config.advanced;
|
|
109
|
-
compiledScript = new ( script.type === 'module' ? QuantumModule : ( QuantumScript || AsyncQuantumScript ) )( textContent, {
|
|
110
|
-
exportNamespace: `#${ script.id }`,
|
|
111
|
-
fileName: `${ window.document.url?.split( '#' )?.[ 0 ] || '' }#${ script.id }`,
|
|
112
|
-
parserParams: { ...parserParams, quantumMode: script.quantum },
|
|
113
|
-
compilerParams,
|
|
114
|
-
runtimeParams,
|
|
115
|
-
} );
|
|
116
|
-
compileCache.set( sourceHash, compiledScript );
|
|
117
|
-
}
|
|
101
|
+
const compiledScript = compileScript.call( window, config, script );
|
|
102
|
+
if ( !compiledScript ) return;
|
|
103
|
+
handled.add( script );
|
|
118
104
|
// Run now!!!
|
|
119
105
|
const thisContext = script.scoped ? script.parentNode || record.target : ( script.type === 'module' ? undefined : window );
|
|
120
106
|
if ( script.scoped ) { thisContext[ config.api.scripts ].push( script ); }
|
|
@@ -126,4 +112,32 @@ function realtime( config ) {
|
|
|
126
112
|
} );
|
|
127
113
|
}, { live: true, subtree: 'cross-roots', timing: 'intercept', generation: 'entrants', eventDetails: true } );
|
|
128
114
|
// ---
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
function compileScript( config, script ) {
|
|
118
|
+
const window = this, { webqit: { oohtml, QuantumScript, AsyncQuantumScript, QuantumModule } } = window;
|
|
119
|
+
const textContent = ( script._ = script.textContent.trim() ) && script._.startsWith( '/*@oohtml*/if(false){' ) && script._.endsWith( '}/*@oohtml*/' ) ? script._.slice( 21, -12 ) : script.textContent;
|
|
120
|
+
if ( !script.scoped && !script.quantum && !textContent.includes( 'quantum' ) ) return;
|
|
121
|
+
const sourceHash = _toHash( textContent );
|
|
122
|
+
const compileCache = oohtml.Script.compileCache[ script.quantum ? 0 : 1 ];
|
|
123
|
+
let compiledScript;
|
|
124
|
+
if ( !( compiledScript = compileCache.get( sourceHash ) ) ) {
|
|
125
|
+
const { parserParams, compilerParams, runtimeParams } = config.advanced;
|
|
126
|
+
compiledScript = new ( script.type === 'module' ? QuantumModule : ( QuantumScript || AsyncQuantumScript ) )( textContent, {
|
|
127
|
+
exportNamespace: `#${ script.id }`,
|
|
128
|
+
fileName: `${ window.document.url?.split( '#' )?.[ 0 ] || '' }#${ script.id }`,
|
|
129
|
+
parserParams: { ...parserParams, quantumMode: script.quantum },
|
|
130
|
+
compilerParams,
|
|
131
|
+
runtimeParams,
|
|
132
|
+
} );
|
|
133
|
+
compileCache.set( sourceHash, compiledScript );
|
|
134
|
+
}
|
|
135
|
+
return compiledScript;
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
export function idleCompiler( node ) {
|
|
139
|
+
const window = this, { webqit: { oohtml: { configs: { SCOPED_JS: config } } } } = window;
|
|
140
|
+
[ ...( node?.querySelectorAll( config.scriptSelector ) || [] ) ].forEach( script => {
|
|
141
|
+
compileScript.call( window, config, script );
|
|
142
|
+
} );
|
|
129
143
|
}
|