@webqit/oohtml 3.1.7 → 3.1.9

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.
@@ -12,7 +12,7 @@ import { _, _init } from '../util.js';
12
12
  */
13
13
  export default function init( $config = {} ) {
14
14
  const { config, window } = _init.call( this, 'bindings-api', $config, {
15
- context: { attr: { bindingsreflection: 'bindings' }, },
15
+ attr: { bindingsreflection: 'bindings' },
16
16
  api: { bind: 'bind', bindings: 'bindings', },
17
17
  } );
18
18
  window.webqit.DOMBindingsContext = DOMBindingsContext;
@@ -34,11 +34,11 @@ function getBindings( config, node ) {
34
34
  // Reflection
35
35
  const props = Object.keys( bindingsObj );
36
36
  const targetNode = node === window.document ? window.document.documentElement : node;
37
- const bindingsReflection = config.context.attr.bindingsreflection;
37
+ const bindingsReflection = config.attr.bindingsreflection;
38
38
  if ( props.length && bindingsReflection ) {
39
- targetNode.setAttribute( config.context.attr.bindingsreflection, props.join( ' ') );
39
+ targetNode.setAttribute( config.attr.bindingsreflection, props.join( ' ') );
40
40
  } else if ( bindingsReflection ) {
41
- targetNode.toggleAttribute( config.context.attr.bindingsreflection, false );
41
+ targetNode.toggleAttribute( config.attr.bindingsreflection, false );
42
42
  }
43
43
  // Re: DOMBindingsContext
44
44
  const contextsApi = node[ ctxConfig.api.contexts ];
@@ -101,7 +101,7 @@ export default class DOMContext {
101
101
  host.addEventListener( 'contextrequest', this );
102
102
  host.addEventListener( 'contextclaim', this );
103
103
  const { value: claims } = DOMContexts.instance( host ).request( 'contextclaim', { kind: this.constructor.kind, detail: this } );
104
- claims.forEach( subscriptionEvent => {
104
+ claims?.forEach( subscriptionEvent => {
105
105
  this.subscriptions.add( subscriptionEvent );
106
106
  this.subscribed( subscriptionEvent );
107
107
  this.handle( subscriptionEvent );
@@ -12,11 +12,9 @@ import { _, _init } from '../util.js';
12
12
  * @return Void
13
13
  */
14
14
  export default function init( $config = {} ) {
15
- const { config, window } = _init.call( this, 'html-bindings', $config, {
15
+ const { config, window } = _init.call( this, 'data-binding', $config, {
16
16
  attr: { expr: 'expr', itemIndex: 'data-key' },
17
17
  tokens: { nodeType: 'processing-instruction', tagStart: '?{', tagEnd: '}?', stateStart: '; [=', stateEnd: ']' },
18
- staticsensitivity: true,
19
- isomorphic: true,
20
18
  } );
21
19
  ( { CONTEXT_API: config.CONTEXT_API, BINDINGS_API: config.BINDINGS_API, HTML_IMPORTS: config.HTML_IMPORTS } = window.webqit.oohtml.configs );
22
20
  config.attrSelector = `[${ window.CSS.escape( config.attr.expr ) }]`;
@@ -46,13 +44,19 @@ function realtime( config ) {
46
44
  realdom.realtime( window.document ).subtree( config.attrSelector, record => {
47
45
  cleanup.call( this, ...record.exits );
48
46
  mountInlineBindings.call( this, config, ...record.entrants );
49
- }, { live: true, timing: 'sync', staticSensitivity: config.staticsensitivity } );
47
+ }, { live: true, timing: 'sync', staticSensitivity: true } );
50
48
  }
51
49
 
52
50
  function createDynamicScope( config, root ) {
53
- const { webqit: { Observer, DOMBindingsContext } } = this;
51
+ const { webqit: { realdom, Observer, DOMBindingsContext } } = this;
54
52
  if ( _( root ).has( 'data-binding' ) ) return _( root ).get( 'data-binding' );
55
53
  const scope = Object.create( null ), abortController = new AbortController;
54
+ scope[ '$exec__' ] = ( target, prop, ...args ) => {
55
+ realdom.schedule( 'write', () => target[ prop ]( ...args ) );
56
+ };
57
+ scope[ '$assign__' ] = ( target, prop, val ) => {
58
+ realdom.schedule( 'write', () => (target[ prop ] = val) );
59
+ };
56
60
  Observer.intercept( scope, {
57
61
  get: ( e, recieved, next ) => {
58
62
  if ( !( e.key in scope ) ) {
@@ -130,10 +134,10 @@ const discreteParseCache = new Map;
130
134
  function compileDiscreteBindings( config, str ) {
131
135
  if ( discreteParseCache.has( str ) ) return discreteParseCache.get( str );
132
136
  let source = `let content = ((${ str }) ?? '') + '';`;
133
- source += `this.nodeValue = content;`;
134
- source += `if ( this.$oohtml_internal_databinding_anchorNode ) { this.$oohtml_internal_databinding_anchorNode.nodeValue = "${ config.tokens.tagStart }${ escDouble( str ) }${ config.tokens.stateStart }" + content.length + "${ config.tokens.stateEnd } ${ config.tokens.tagEnd }"; }`;
135
- const { webqit: { QuantumAsyncScript } } = this;
136
- const compiled = new QuantumAsyncScript( source );
137
+ source += `$assign__(this, 'nodeValue', content);`;
138
+ source += `if ( this.$oohtml_internal_databinding_anchorNode ) { $assign__(this.$oohtml_internal_databinding_anchorNode, 'nodeValue', "${ config.tokens.tagStart }${ escDouble( str ) }${ config.tokens.stateStart }" + content.length + "${ config.tokens.stateEnd } ${ config.tokens.tagEnd }"); }`;
139
+ const { webqit: { QuantumModule } } = this;
140
+ const compiled = new QuantumModule( source );
137
141
  discreteParseCache.set( str, compiled );
138
142
  return compiled;
139
143
  }
@@ -157,19 +161,19 @@ function compileInlineBindings( config, str ) {
157
161
  const directive = left[ 0 ], param = left.slice( 1 ).trim();
158
162
  const arg = `(${ right })`, $arg = `(${ arg } ?? '')`;
159
163
  if ( directive === '&' ) {
160
- if ( param.startsWith( '--' ) ) return `this.style.setProperty("${ escDouble( param ) }", ${ $arg });`;
161
- return `this.style["${ escDouble( param ) }"] = ${ $arg };`;
164
+ if ( param.startsWith( '--' ) ) return `$exec__(this.style, 'setProperty', "${ escDouble( param ) }", ${ $arg });`;
165
+ return `$assign__(this.style, "${ escDouble( param ) }", ${ $arg });`;
162
166
  }
163
- if ( directive === '%' ) return `this.classList.toggle("${ escDouble( param ) }", !!${ arg });`;
167
+ if ( directive === '%' ) return `$exec__(this.classList, 'toggle', "${ escDouble( param ) }", !!${ arg });`;
164
168
  if ( directive === '~' ) {
165
- if ( param.startsWith( '?' ) ) return `this.toggleAttribute("${ escDouble( param.substring( 1 ).trim() ) }", !!${ arg });`;
166
- return `this.setAttribute("${ escDouble( param ) }", ${ $arg });`;
169
+ if ( param.startsWith( '?' ) ) return `$exec__(this, 'toggleAttribute', "${ escDouble( param.substring( 1 ).trim() ) }", !!${ arg });`;
170
+ return `$exec__(this, 'setAttribute', "${ escDouble( param ) }", ${ $arg });`;
167
171
  }
168
172
  if ( directive === '@' ) {
169
173
  if ( validation[ param ] ) throw new Error( `Duplicate binding: ${ left }.` );
170
174
  validation[ param ] = true;
171
- if ( param === 'text' ) return `this.textContent = ${ $arg };`;
172
- if ( param === 'html' ) return `this.setHTML(${ $arg });`;
175
+ if ( param === 'text' ) return `$assign__(this, 'textContent', ${ $arg });`;
176
+ if ( param === 'html' ) return `$exec__(this, 'setHTML', ${ $arg });`;
173
177
  if ( param === 'items' ) {
174
178
  const [ iterationSpec, importSpec ] = splitOuter( right, '/' );
175
179
  if ( !importSpec ) throw new Error( `Invalid ${ directive }items spec: ${ str }; no import specifier.` );
@@ -182,7 +186,7 @@ function compileInlineBindings( config, str ) {
182
186
  const indices = kind === 'in' ? production[ 2 ] : ( production[ 1 ] || '$index__' );
183
187
  return `
184
188
  let $iteratee__ = ${ iteratee };
185
- let $import__ = this.${ config.HTML_IMPORTS.context.api.import }( ${ importSpec.trim() }, true );
189
+ let $import__ = this.${ config.HTML_IMPORTS.api.import }( ${ importSpec.trim() }, true );
186
190
  this.$oohtml_internal_databinding_signals?.push( $import__ );
187
191
 
188
192
  if ( $import__.value && $iteratee__ ) {
@@ -200,13 +204,14 @@ function compileInlineBindings( config, str ) {
200
204
  let $itemNode__ = $existing__.get( $key___ );
201
205
  if ( $itemNode__ ) {
202
206
  $existing__.delete( $key___ );
207
+ $exec__($itemNode__, '${ config.BINDINGS_API.api.bind }', $itemBinding__ );
203
208
  } else {
204
209
  $itemNode__ = ( Array.isArray( $import__.value ) ? $import__.value[ 0 ] : ( $import__.value instanceof window.HTMLTemplateElement ? $import__.value.content.firstElementChild : $import__.value ) ).cloneNode( true );
205
210
  $itemNode__.setAttribute( "${ config.attr.itemIndex }", $key___ );
206
- this.appendChild( $itemNode__ );
211
+ $exec__($itemNode__, '${ config.BINDINGS_API.api.bind }', $itemBinding__ );
212
+ $exec__(this, 'appendChild', $itemNode__ );
207
213
  }
208
214
 
209
- $itemNode__.${ config.BINDINGS_API.api.bind }( $itemBinding__ );
210
215
  if ( ${ kind === 'in' ? `!( ${ production[ 0 ] } in $iteratee__ )` : `typeof ${ production[ 0 ] } === 'undefined'` } ) { $itemNode__.remove(); }
211
216
  }
212
217
  $existing__.forEach( x => x.remove() );
@@ -216,8 +221,8 @@ function compileInlineBindings( config, str ) {
216
221
  }
217
222
  if ( str.trim() ) throw new Error( `Invalid binding: ${ str }.` );
218
223
  } ).join( `\n` );
219
- const { webqit: { QuantumAsyncScript } } = this;
220
- const compiled = new QuantumAsyncScript( source );
224
+ const { webqit: { QuantumModule } } = this;
225
+ const compiled = new QuantumModule( source );
221
226
  inlineParseCache.set( str, compiled );
222
227
  return compiled;
223
228
  }
@@ -46,7 +46,7 @@ export default class HTMLImportsContext extends DOMContext {
46
46
  if ( ( event.detail || '' ).trim() === '/' ) return event.respondWith( this.localModules );
47
47
  const $config = this.configs.HTML_IMPORTS;
48
48
  let path = ( event.detail || '' ).split( /\/|(?<=\w)(?=#)/g ).map( x => x.trim() ).filter( x => x );
49
- if ( path.length ) { path = path.join( `/${ $config.template.api.exports }/` )?.split( '/' ) || []; }
49
+ if ( path.length ) { path = path.join( `/${ $config.api.defs }/` )?.split( '/' ) || []; }
50
50
  // No detail?
51
51
  if ( !path.length ) return event.respondWith();
52
52
 
@@ -89,11 +89,11 @@ export default class HTMLImportsContext extends DOMContext {
89
89
  };
90
90
  // ----------------
91
91
  const $config = this.configs.HTML_IMPORTS;
92
- if ( !this.host.matches || !$config.context.attr.importscontext ) return;
92
+ if ( !this.host.matches || !$config.attr.importscontext ) return;
93
93
  // Any existing this.refdSourceController? Abort!
94
94
  this.refdSourceController?.disconnect();
95
95
  const realdom = this.host.ownerDocument.defaultView.webqit.realdom;
96
- this.refdSourceController = realdom.realtime( this.host ).attr( $config.context.attr.importscontext, ( record, { signal } ) => {
96
+ this.refdSourceController = realdom.realtime( this.host ).attr( $config.attr.importscontext, ( record, { signal } ) => {
97
97
  // No importscontext attr set. But we're still watching
98
98
  if ( !record.value ) {
99
99
  this.contextModules = undefined;
@@ -12,7 +12,7 @@ export default class HTMLModule {
12
12
  * @instance
13
13
  */
14
14
  static instance( host ) {
15
- return _( host ).get( 'exportsmanager::instance' ) || new this( host );
15
+ return _( host ).get( 'defsmanager::instance' ) || new this( host );
16
16
  }
17
17
 
18
18
  /**
@@ -20,14 +20,14 @@ export default class HTMLModule {
20
20
  */
21
21
  constructor( host, parent = null, level = 0 ) {
22
22
  const { window } = env, { webqit: { realdom, oohtml: { configs } } } = window;
23
- _( host ).get( `exportsmanager::instance` )?.dispose();
24
- _( host ).set( `exportsmanager::instance`, this );
23
+ _( host ).get( `defsmanager::instance` )?.dispose();
24
+ _( host ).set( `defsmanager::instance`, this );
25
25
  this.host = host;
26
26
  this.config = configs.HTML_IMPORTS;
27
27
  this.parent = parent;
28
28
  this.level = level;
29
- this.exports = getExports( this.host );
30
- this.defId = ( this.host.getAttribute( this.config.template?.attr.moduledef ) || '' ).trim();
29
+ this.defs = getExports( this.host );
30
+ this.defId = ( this.host.getAttribute( this.config.attr.def ) || '' ).trim();
31
31
  this.validateDefId( this.defId );
32
32
  // ----------
33
33
  this.realtimeA = realdom.realtime( this.host.content ).children( record => {
@@ -60,7 +60,7 @@ export default class HTMLModule {
60
60
  }
61
61
 
62
62
  /**
63
- * Maps module contents as exports.
63
+ * Maps module contents as defs.
64
64
  *
65
65
  * @param Array entries
66
66
  * @param Bool isConnected
@@ -69,12 +69,12 @@ export default class HTMLModule {
69
69
  */
70
70
  export( entries, isConnected ) {
71
71
  const { window } = env, { webqit: { Observer } } = window;
72
- let dirty, allFragments = this.exports[ '#' ] || [];
73
- Observer.batch( this.exports, () => {
72
+ let dirty, allFragments = this.defs[ '#' ] || [];
73
+ Observer.batch( this.defs, () => {
74
74
  entries.forEach( entry => {
75
75
  if ( entry.nodeType !== 1 ) return;
76
76
  const isTemplate = entry.matches( this.config.templateSelector );
77
- const defId = ( entry.getAttribute( isTemplate ? this.config.template.attr.moduledef : this.config.template.attr.fragmentdef ) || '' ).trim();
77
+ const defId = ( entry.getAttribute( isTemplate ? this.config.attr.def : this.config.attr.fragmentdef ) || '' ).trim();
78
78
  if ( isConnected ) {
79
79
  if ( isTemplate && defId ) { new HTMLModule( entry, this.host, this.level + 1 ); }
80
80
  else {
@@ -83,7 +83,7 @@ export default class HTMLModule {
83
83
  }
84
84
  if ( defId ) {
85
85
  this.validateDefId( defId );
86
- Observer.set( this.exports, ( !isTemplate && '#' || '' ) + defId, entry );
86
+ Observer.set( this.defs, ( !isTemplate && '#' || '' ) + defId, entry );
87
87
  }
88
88
  } else {
89
89
  if ( isTemplate && defId ) { HTMLModule.instance( entry ).dispose(); }
@@ -91,10 +91,10 @@ export default class HTMLModule {
91
91
  allFragments = allFragments.filter( x => x !== entry );
92
92
  dirty = true;
93
93
  }
94
- if ( defId ) Observer.deleteProperty( this.exports, ( !isTemplate && '#' || '' ) + defId );
94
+ if ( defId ) Observer.deleteProperty( this.defs, ( !isTemplate && '#' || '' ) + defId );
95
95
  }
96
96
  } );
97
- if ( dirty ) Observer.set( this.exports, '#', allFragments );
97
+ if ( dirty ) Observer.set( this.defs, '#', allFragments );
98
98
  } );
99
99
  }
100
100
 
@@ -114,7 +114,7 @@ export default class HTMLModule {
114
114
  $loadingPromise = promise.then( () => interception.remove() ); // Set
115
115
  };
116
116
  const loading = ( record2.value || '' ).trim();
117
- const interception = Observer.intercept( this.exports, 'get', async ( descriptor, recieved, next ) => {
117
+ const interception = Observer.intercept( this.defs, 'get', async ( descriptor, recieved, next ) => {
118
118
  if ( loading === 'lazy' ) { loadingPromise( this.load( src, true ) ); }
119
119
  await loadingPromise();
120
120
  return next();
@@ -162,22 +162,22 @@ export default class HTMLModule {
162
162
  evalInheritance( ) {
163
163
  if ( !this.parent ) return [];
164
164
  const { window: { webqit: { Observer } } } = env;
165
- let extendedId = ( this.host.getAttribute( this.config.template.attr.extends ) || '' ).trim();
166
- let inheritedIds = ( this.host.getAttribute( this.config.template.attr.inherits ) || '' ).trim();
165
+ let extendedId = ( this.host.getAttribute( this.config.attr.extends ) || '' ).trim();
166
+ let inheritedIds = ( this.host.getAttribute( this.config.attr.inherits ) || '' ).trim();
167
167
  const handleInherited = records => {
168
168
  records.forEach( record => {
169
- if ( Observer.get( this.exports, record.key ) !== record.oldValue ) return;
169
+ if ( Observer.get( this.defs, record.key ) !== record.oldValue ) return;
170
170
  if ( [ 'get'/*initial get*/, 'set', 'def' ].includes( record.type ) ) {
171
- Observer[ record.type.replace( 'get', 'set' ) ]( this.exports, record.key, record.value );
171
+ Observer[ record.type.replace( 'get', 'set' ) ]( this.defs, record.key, record.value );
172
172
  } else if ( record.type === 'delete' ) {
173
- Observer.deleteProperty( this.exports, record.key );
173
+ Observer.deleteProperty( this.defs, record.key );
174
174
  }
175
175
  } );
176
176
  };
177
177
  const realtimes = [];
178
178
  const parentExportsObj = getExports( this.parent );
179
179
  if ( extendedId ) {
180
- realtimes.push( Observer.reduce( parentExportsObj, [ extendedId, this.config.template.api.exports, Infinity ], Observer.get, handleInherited, { live: true } ) );
180
+ realtimes.push( Observer.reduce( parentExportsObj, [ extendedId, this.config.api.defs, Infinity ], Observer.get, handleInherited, { live: true } ) );
181
181
  }
182
182
  if ( ( inheritedIds = inheritedIds.split( ' ' ).map( id => id.trim() ).filter( x => x ) ).length ) {
183
183
  realtimes.push( Observer.get( parentExportsObj, inheritedIds, handleInherited, { live: true } ) );
@@ -194,7 +194,7 @@ export default class HTMLModule {
194
194
  this.realtimeA.disconnect();
195
195
  this.realtimeB.disconnect();
196
196
  this.realtimeC.forEach( r => ( r instanceof Promise ? r.then( r => r.abort() ) : r.abort() ) );
197
- Object.entries( this.exports ).forEach( ( [ key, entry ] ) => {
197
+ Object.entries( this.defs ).forEach( ( [ key, entry ] ) => {
198
198
  if ( key.startsWith( '#' ) ) return;
199
199
  HTMLModule.instance( entry ).dispose();
200
200
  } );
@@ -13,9 +13,9 @@ import { _, env } from '../util.js';
13
13
  * @return HTMLImportElement
14
14
  */
15
15
  export default function() {
16
- const { window } = env, { webqit } = window, { Observer, realdom, oohtml: { configs } } = webqit;
16
+ const { window } = env, { webqit } = window, { realdom, oohtml: { configs } } = webqit;
17
17
  if ( webqit.HTMLImportElement ) return webqit.HTMLImportElement;
18
- const BaseElement = configs.HTML_IMPORTS.import.tagName.includes( '-' ) ? window.HTMLElement : class {};
18
+ const BaseElement = configs.HTML_IMPORTS.elements.import.includes( '-' ) ? window.HTMLElement : class {};
19
19
  class HTMLImportElement extends BaseElement {
20
20
 
21
21
  /**
@@ -26,7 +26,7 @@ export default function() {
26
26
  * @returns
27
27
  */
28
28
  static instance( node ) {
29
- if ( configs.HTML_IMPORTS.import.tagName.includes( '-' ) && ( node instanceof this ) ) return node;
29
+ if ( configs.HTML_IMPORTS.elements.import.includes( '-' ) && ( node instanceof this ) ) return node;
30
30
  return _( node ).get( 'import::instance' ) || new this( node );
31
31
  }
32
32
 
@@ -60,7 +60,7 @@ export default function() {
60
60
 
61
61
  priv.hydrate = ( anchorNode, slottedElements ) => {
62
62
  // ----------------
63
- priv.moduleRef = ( this.el.getAttribute( configs.HTML_IMPORTS.import.attr.moduleref ) || '' ).trim();
63
+ priv.moduleRef = ( this.el.getAttribute( configs.HTML_IMPORTS.attr.ref ) || '' ).trim();
64
64
  anchorNode.replaceWith( priv.setAnchorNode( this.createAnchorNode() ) );
65
65
  priv.autoRestore( () => {
66
66
  slottedElements.forEach( slottedElement => {
@@ -72,10 +72,10 @@ export default function() {
72
72
  priv.hydrationImportRequest = new AbortController;
73
73
  priv.importRequest( fragments => {
74
74
  if ( priv.originalsRemapped ) { return this.fill( fragments ); }
75
- const identifiersMap = fragments.map( ( fragment, i ) => ( { el: fragment, fragmentDef: fragment.getAttribute( configs.HTML_IMPORTS.template.attr.fragmentdef ) || '', tagName: fragment.tagName, i } ) );
75
+ const identifiersMap = fragments.map( ( fragment, i ) => ( { el: fragment, fragmentDef: fragment.getAttribute( configs.HTML_IMPORTS.attr.fragmentdef ) || '', tagName: fragment.tagName, i } ) );
76
76
  let i = -1;
77
77
  slottedElements.forEach( slottedElement => {
78
- const tagName = slottedElement.tagName, fragmentDef = slottedElement.getAttribute( configs.HTML_IMPORTS.template.attr.fragmentdef ) || '';
78
+ const tagName = slottedElement.tagName, fragmentDef = slottedElement.getAttribute( configs.HTML_IMPORTS.attr.fragmentdef ) || '';
79
79
  const originalsMatch = ( i ++, identifiersMap.find( fragmentIdentifiers => fragmentIdentifiers.tagName === tagName && fragmentIdentifiers.fragmentDef === fragmentDef && fragmentIdentifiers.i === i ) );
80
80
  if ( !originalsMatch ) return; // Or should we throw integrity error?
81
81
  _( slottedElement ).set( 'original@imports', originalsMatch.el );
@@ -113,7 +113,7 @@ export default function() {
113
113
  if ( priv.slottedElements.size ) throw new Error( `Illegal reinsertion into the DOM; import slot is not empty!` );
114
114
  // Totally initialize this instance?
115
115
  if ( priv.moduleRefRealtime ) return;
116
- priv.moduleRefRealtime = realdom.realtime( this.el ).attr( configs.HTML_IMPORTS.import.attr.moduleref, ( record, { signal } ) => {
116
+ priv.moduleRefRealtime = realdom.realtime( this.el ).attr( configs.HTML_IMPORTS.attr.ref, ( record, { signal } ) => {
117
117
  priv.moduleRef = record.value;
118
118
  // Below, we ignore first restore from hydration
119
119
  priv.importRequest( fragments => !priv.hydrationImportRequest && this.fill( fragments ), signal );
@@ -182,8 +182,8 @@ export default function() {
182
182
  // Clone each slottable element and give it a reference to its original
183
183
  const slottableElementClone = slottableElement.cloneNode( true );
184
184
  // The folllowing references must be set before adding to DODM
185
- if ( !slottableElementClone.hasAttribute( configs.HTML_IMPORTS.template.attr.fragmentdef ) ) {
186
- slottableElementClone.toggleAttribute( configs.HTML_IMPORTS.template.attr.fragmentdef, true );
185
+ if ( !slottableElementClone.hasAttribute( configs.HTML_IMPORTS.attr.fragmentdef ) ) {
186
+ slottableElementClone.toggleAttribute( configs.HTML_IMPORTS.attr.fragmentdef, true );
187
187
  }
188
188
  _( slottableElementClone ).set( 'original@imports', slottableElement );
189
189
  _( slottableElementClone ).set( 'slot@imports', this.el );
@@ -221,7 +221,7 @@ export default function() {
221
221
  */
222
222
  get slottedElements() { return this[ '#' ].slottedElements; }
223
223
  }
224
- if ( configs.HTML_IMPORTS.import.tagName.includes( '-' ) ) { customElements.define( configs.HTML_IMPORTS.import.tagName, HTMLImportElement ); }
224
+ if ( configs.HTML_IMPORTS.elements.import.includes( '-' ) ) { customElements.define( configs.HTML_IMPORTS.elements.import, HTMLImportElement ); }
225
225
  webqit.HTMLImportElement = HTMLImportElement;
226
226
  return HTMLImportElement;
227
227
  }
@@ -15,22 +15,21 @@ import { _, _init } from '../util.js';
15
15
  * @return Void
16
16
  */
17
17
  export default function init( $config = {} ) {
18
- const { config, realdom, window } = _init.call( this, 'html-imports', $config, {
19
- template: { attr: { moduledef: 'def', fragmentdef: 'def', extends: 'extends', inherits: 'inherits' }, api: { exports: 'exports', moduledef: 'def' }, },
20
- context: { attr: { importscontext: 'importscontext', }, api: { import: 'import' }, },
21
- import: { tagName: 'import', attr: { moduleref: 'ref' }, },
22
- staticsensitivity: true,
23
- isomorphic: true,
18
+ const { config, window } = _init.call( this, 'html-imports', $config, {
19
+ elements: { import: 'import', },
20
+ attr: { def: 'def', extends: 'extends', inherits: 'inherits', ref: 'ref', importscontext: 'importscontext', },
21
+ api: { def: 'def', defs: 'defs', import: 'import' },
24
22
  } );
25
- config.templateSelector = `template[${ window.CSS.escape( config.template.attr.moduledef ) }]`;
26
- config.importsContextSelector = `[${ window.CSS.escape( config.context.attr.importscontext ) }]`;
27
- config.slottedElementsSelector = `[${ window.CSS.escape( config.template.attr.fragmentdef ) }]:not(template)`;
23
+ if ( !config.attr.fragmentdef ) { config.attr.fragmentdef = config.attr.def; }
24
+ config.templateSelector = `template[${ window.CSS.escape( config.attr.def ) }]`;
25
+ config.importsContextSelector = `[${ window.CSS.escape( config.attr.importscontext ) }]`;
26
+ config.slottedElementsSelector = `[${ window.CSS.escape( config.attr.fragmentdef ) }]:not(template)`;
28
27
  const anchorNodeMatch = ( start, end ) => {
29
28
  const starting = `starts-with(., "${ start }")`;
30
29
  const ending = `substring(., string-length(.) - string-length("${ end }") + 1) = "${ end }"`;
31
30
  return `${ starting } and ${ ending }`;
32
31
  }
33
- config.anchorNodeSelector = `comment()[${ anchorNodeMatch( `&lt;${ config.import.tagName }`, `&lt;/${ config.import.tagName }&gt;` ) }]`;
32
+ config.anchorNodeSelector = `comment()[${ anchorNodeMatch( `&lt;${ config.elements.import }`, `&lt;/${ config.elements.import }&gt;` ) }]`;
34
33
  window.webqit.HTMLImportsContext = HTMLImportsContext;
35
34
  window.webqit.HTMLImportElement = _HTMLImportElement();
36
35
  exposeAPIs.call( window, config );
@@ -38,7 +37,7 @@ export default function init( $config = {} ) {
38
37
  }
39
38
 
40
39
  /**
41
- * Returns the "exports" object associated with the given node.
40
+ * Returns the "defs" object associated with the given node.
42
41
  *
43
42
  * @param Element node
44
43
  * @param Bool autoCreate
@@ -46,11 +45,11 @@ export default function init( $config = {} ) {
46
45
  * @return Object
47
46
  */
48
47
  export function getExports( node, autoCreate = true ) {
49
- if ( !_( node ).has( 'exports' ) && autoCreate ) {
50
- const exports = Object.create( null );
51
- _( node ).set( 'exports', exports );
48
+ if ( !_( node ).has( 'defs' ) && autoCreate ) {
49
+ const defs = Object.create( null );
50
+ _( node ).set( 'defs', defs );
52
51
  }
53
- return _( node ).get( 'exports' );
52
+ return _( node ).get( 'defs' );
54
53
  }
55
54
 
56
55
  /**
@@ -63,21 +62,21 @@ export function getExports( node, autoCreate = true ) {
63
62
  function exposeAPIs( config ) {
64
63
  const window = this, { webqit: { oohtml: { configs } } } = window;
65
64
  // Assertions
66
- if ( config.template.api.exports in window.HTMLTemplateElement.prototype ) { throw new Error( `The "HTMLTemplateElement" class already has a "${ config.template.api.exports }" property!` ); }
67
- if ( config.template.api.moduledef in window.HTMLTemplateElement.prototype ) { throw new Error( `The "HTMLTemplateElement" class already has a "${ config.template.api.moduledef }" property!` ); }
68
- if ( config.context.api.import in window.document ) { throw new Error( `document already has a "${ config.context.api.import }" property!` ); }
69
- if ( config.context.api.import in window.HTMLElement.prototype ) { throw new Error( `The "HTMLElement" class already has a "${ config.context.api.import }" property!` ); }
65
+ if ( config.api.defs in window.HTMLTemplateElement.prototype ) { throw new Error( `The "HTMLTemplateElement" class already has a "${ config.api.defs }" property!` ); }
66
+ if ( config.api.def in window.HTMLTemplateElement.prototype ) { throw new Error( `The "HTMLTemplateElement" class already has a "${ config.api.def }" property!` ); }
67
+ if ( config.api.import in window.document ) { throw new Error( `document already has a "${ config.api.import }" property!` ); }
68
+ if ( config.api.import in window.HTMLElement.prototype ) { throw new Error( `The "HTMLElement" class already has a "${ config.api.import }" property!` ); }
70
69
  // Definitions
71
- Object.defineProperty( window.HTMLTemplateElement.prototype, config.template.api.exports, { get: function() {
70
+ Object.defineProperty( window.HTMLTemplateElement.prototype, config.api.defs, { get: function() {
72
71
  return getExports( this );
73
72
  } } );
74
- Object.defineProperty( window.HTMLTemplateElement.prototype, config.template.api.moduledef, { get: function() {
75
- return this.getAttribute( config.template.attr.moduledef );
73
+ Object.defineProperty( window.HTMLTemplateElement.prototype, config.api.def, { get: function() {
74
+ return this.getAttribute( config.attr.def );
76
75
  } } );
77
- Object.defineProperty( window.document, config.context.api.import, { value: function( ref, live = false, callback = null ) {
76
+ Object.defineProperty( window.document, config.api.import, { value: function( ref, live = false, callback = null ) {
78
77
  return importRequest( window.document, ...arguments );
79
78
  } } );
80
- Object.defineProperty( window.HTMLElement.prototype, config.context.api.import, { value: function( ref, live = false, callback = null ) {
79
+ Object.defineProperty( window.HTMLElement.prototype, config.api.import, { value: function( ref, live = false, callback = null ) {
81
80
  return importRequest( this, ...arguments );
82
81
  } } );
83
82
  function importRequest( context, ref, live = false, callback = null ) {
@@ -130,7 +129,7 @@ function realtime( config ) {
130
129
  htmlModule.ownerContext = entry.scoped ? record.target : window.document;
131
130
  const ownerContextModulesObj = getExports( htmlModule.ownerContext );
132
131
  if ( htmlModule.defId ) { Observer.set( ownerContextModulesObj, htmlModule.defId, entry ); }
133
- // The ownerContext's exports - ownerContextModulesObj - has to be populated
132
+ // The ownerContext's defs - ownerContextModulesObj - has to be populated
134
133
  // Before attaching a context instance to it, to give the just created context something to use for
135
134
  // fullfiling reclaimed requests.
136
135
  attachImportsContext( htmlModule.ownerContext );
@@ -148,11 +147,11 @@ function realtime( config ) {
148
147
  detachImportsContext( entry );
149
148
  }
150
149
  } );
151
- }, { live: true, timing: 'sync', staticSensitivity: config.staticsensitivity } );
150
+ }, { live: true, timing: 'sync', staticSensitivity: true } );
152
151
  // ------------
153
152
  // IMPORTS
154
153
  // ------------
155
- realdom.realtime( window.document ).subtree/*instead of observe(); reason: jsdom timing*/( config.import.tagName, record => {
154
+ realdom.realtime( window.document ).subtree/*instead of observe(); reason: jsdom timing*/( config.elements.import, record => {
156
155
  record.entrants.forEach( node => handleRealtime( node, true, record ) );
157
156
  record.exits.forEach( node => handleRealtime( node, false, record ) );
158
157
  }, { live: true, timing: 'sync' } );
@@ -11,14 +11,12 @@ import { _, _init } from '../util.js';
11
11
  */
12
12
  export default function init( $config = {} ) {
13
13
  const { config, window } = _init.call( this, 'namespaced-html', $config, {
14
- id: { attr: 'id' },
15
- namespace: { attr: 'namespace', api: 'namespace', },
14
+ attr: { namespace: 'namespace', id: 'id', },
15
+ api: { namespace: 'namespace', eagermode: true, },
16
16
  target: { attr: ':target', event: ':target', scrolling: true },
17
- staticsensitivity: true,
18
- eagermode: true,
19
17
  } );
20
- config.idSelector = `[${ window.CSS.escape( config.id.attr ) }]`;
21
- config.namespaceSelector = `[${ window.CSS.escape( config.namespace.attr ) }]`;
18
+ config.idSelector = `[${ window.CSS.escape( config.attr.id ) }]`;
19
+ config.namespaceSelector = `[${ window.CSS.escape( config.attr.namespace ) }]`;
22
20
  exposeAPIs.call( window, config );
23
21
  realtime.call( window, config );
24
22
  }
@@ -35,8 +33,8 @@ function getNamespaceObject( node, config ) {
35
33
  if ( !_( node ).has( 'namespace' ) ) {
36
34
  const namespaceObj = Object.create( null );
37
35
  Observer.intercept( namespaceObj, 'get', ( event, receiver, next ) => {
38
- if ( Observer.has( namespaceObj, event.key ) || !config.eagermode ) return next();
39
- const selector = `[${ window.CSS.escape( config.id.attr ) }="${ event.key }"]`;
36
+ if ( Observer.has( namespaceObj, event.key ) || !config.api.eagermode ) return next();
37
+ const selector = `[${ window.CSS.escape( config.attr.id ) }="${ event.key }"]`;
40
38
  const resultNode = Array.from( node.querySelectorAll( selector ) ).filter( idNode => {
41
39
  const ownerRoot = idNode.parentNode.closest( config.namespaceSelector );
42
40
  if ( node === window.document ) {
@@ -63,13 +61,13 @@ function getNamespaceObject( node, config ) {
63
61
  function exposeAPIs( config ) {
64
62
  const window = this, { webqit: { Observer } } = window;
65
63
  // Assertions
66
- if ( config.namespace.api in window.document ) { throw new Error( `document already has a "${ config.namespace.api }" property!` ); }
67
- if ( config.namespace.api in window.Element.prototype ) { throw new Error( `The "Element" class already has a "${ config.namespace.api }" property!` ); }
64
+ if ( config.api.namespace in window.document ) { throw new Error( `document already has a "${ config.api.namespace }" property!` ); }
65
+ if ( config.api.namespace in window.Element.prototype ) { throw new Error( `The "Element" class already has a "${ config.api.namespace }" property!` ); }
68
66
  // Definitions
69
- Object.defineProperty( window.document, config.namespace.api, { get: function() {
67
+ Object.defineProperty( window.document, config.api.namespace, { get: function() {
70
68
  return Observer.proxy( getNamespaceObject.call( window, window.document, config ) );
71
69
  } });
72
- Object.defineProperty( window.Element.prototype, config.namespace.api, { get: function() {
70
+ Object.defineProperty( window.Element.prototype, config.api.namespace, { get: function() {
73
71
  return Observer.proxy( getNamespaceObject.call( window, this, config ) );
74
72
  } } );
75
73
  }
@@ -85,7 +83,7 @@ function realtime( config ) {
85
83
  const window = this, { webqit: { Observer, realdom } } = window;
86
84
  // ----------------
87
85
  const handle = ( target, entry, incoming ) => {
88
- const identifier = entry.getAttribute( config.id.attr );
86
+ const identifier = entry.getAttribute( config.attr.id );
89
87
  const ownerRoot = target.closest( config.namespaceSelector ) || _( entry ).get( 'ownerNamespace' ) || window.document;
90
88
  const namespaceObj = getNamespaceObject.call( window, ownerRoot, config );
91
89
  if ( incoming ) {
@@ -101,10 +99,10 @@ function realtime( config ) {
101
99
  realdom.realtime( window.document ).subtree/*instead of observe(); reason: jsdom timing*/( config.idSelector, record => {
102
100
  record.entrants.forEach( entry => handle( record.target, entry, true ) );
103
101
  record.exits.forEach( entry => handle( record.target, entry, false ) );
104
- }, { live: true, timing: 'sync', staticSensitivity: config.staticsensitivity } );
102
+ }, { live: true, timing: 'sync', staticSensitivity: true } );
105
103
  // ----------------
106
- if ( config.staticsensitivity ) {
107
- realdom.realtime( window.document, 'attr' ).observe( config.namespace.attr, record => {
104
+ if ( true/*config.staticsensitivity*/ ) {
105
+ realdom.realtime( window.document, 'attr' ).observe( config.attr.namespace, record => {
108
106
  const ownerRoot = record.target.parentNode?.closest( config.namespaceSelector ) || _( record.target ).get( 'ownerNamespace' ) || window.document;
109
107
  const ownerRootNamespaceObj = getNamespaceObject.call( window, ownerRoot, config );
110
108
  const namespaceObj = getNamespaceObject.call( window, record.target, config );
@@ -126,7 +124,7 @@ function realtime( config ) {
126
124
  let prevTarget;
127
125
  const activateTarget = () => {
128
126
  const path = window.location.hash?.substring( 1 ).split( '/' ).map( s => s.trim() ).filter( s => s ) || [];
129
- const currTarget = path.reduce( ( prev, segment ) => prev && prev[ config.namespace.api ][ segment ], window.document );
127
+ const currTarget = path.reduce( ( prev, segment ) => prev && prev[ config.api.namespace ][ segment ], window.document );
130
128
  if ( prevTarget && config.target.attr ) { prevTarget.toggleAttribute( config.target.attr, false ); }
131
129
  if ( currTarget && currTarget !== window.document ) {
132
130
  if ( config.target.attr ) { currTarget.toggleAttribute( config.target.attr, true ); }
package/src/util.js CHANGED
@@ -5,6 +5,7 @@
5
5
  import realdomInit from '@webqit/realdom';
6
6
  import { _internals } from '@webqit/util/js/index.js';
7
7
  import { _merge } from '@webqit/util/obj/index.js';
8
+ import { _toTitle } from '@webqit/util/str/index.js';
8
9
 
9
10
  export const _ = ( ...args ) => _internals( 'oohtml', ...args );
10
11
 
@@ -12,14 +13,31 @@ export const env = {};
12
13
 
13
14
  export function _init( name, $config, $defaults ) {
14
15
  const window = this, realdom = realdomInit.call( window );
16
+ env.window = window;
17
+ if ( !window.webqitConfig ) {
18
+ window.webqitConfig = realdom.meta( 'webqit' ).json();
19
+ }
15
20
  window.webqit || ( window.webqit = {} );
16
21
  window.webqit.oohtml || ( window.webqit.oohtml = {} );
17
22
  window.webqit.oohtml.configs || ( window.webqit.oohtml.configs = {} );
18
- const configKey = name.toUpperCase().replace( '-', '_' );
19
- window.webqit.oohtml.configs[ configKey ] || ( window.webqit.oohtml.configs[ configKey ] = {} );
20
- env.window = window;
21
23
  // ---------------------
22
- _merge( 2, window.webqit.oohtml.configs[ configKey ], $defaults, $config, realdom.meta( name ).json() );
24
+ const configKey = name.toUpperCase().replace( '-', '_' );
25
+ if ( !window.webqit.oohtml.configs[ configKey ] ) {
26
+ window.webqit.oohtml.configs[ configKey ] = {};
27
+ const config = window.webqit.oohtml.configs[ configKey ];
28
+ _merge( 2, config, $defaults, $config, realdom.meta( name ).json() );
29
+ if ( window.webqitConfig.prefix ) {
30
+ Object.keys( config ).forEach( main => {
31
+ Object.keys( config[ main ] ).forEach( key => {
32
+ if ( main === 'api' && typeof config[ main ][ key ] === 'string' ) {
33
+ config[ main ][ key ] = `${ window.webqitConfig.prefix }${ _toTitle( config[ main ][ key ] ) }`
34
+ } else if ( [ 'attr', 'elements' ].includes( main ) && config[ main ][ key ]?.startsWith( 'data-' ) === false ) {
35
+ config[ main ][ key ] = `${ window.webqitConfig.prefix }-${ config[ main ][ key ] }`
36
+ }
37
+ } );
38
+ } );
39
+ }
40
+ }
23
41
  // ---------------------
24
42
  return { config: window.webqit.oohtml.configs[ configKey ], realdom, window };
25
43
  }