@webqit/oohtml 4.1.10 → 4.1.12

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": "4.1.10",
17
+ "version": "4.1.12",
18
18
  "license": "MIT",
19
19
  "repository": {
20
20
  "type": "git",
@@ -40,7 +40,7 @@
40
40
  },
41
41
  "dependencies": {
42
42
  "@webqit/quantum-js": "^4.5.8",
43
- "@webqit/realdom": "^2.1.24",
43
+ "@webqit/realdom": "^2.1.25",
44
44
  "@webqit/util": "^0.8.11"
45
45
  },
46
46
  "devDependencies": {
@@ -84,6 +84,8 @@ export default class DOMContexts {
84
84
  args[ args.indexOf( options ) ] = { ...options, signal: responseInstance.signal };
85
85
  }
86
86
  const event = new ( _DOMContextRequestEvent() )( ...args );
87
+ // Initally
88
+ event.meta.target = this[ '#' ].host;
87
89
 
88
90
  const rootNode = this[ '#' ].host.getRootNode();
89
91
  const temp = event => {
@@ -45,7 +45,7 @@ function realtime( config ) {
45
45
  realdom.realtime( window.document ).query( config.attrSelector, record => {
46
46
  cleanup.call( this, ...record.exits );
47
47
  mountInlineBindings.call( window, config, ...record.entrants );
48
- }, { live: true, subtree: 'cross-roots', timing: 'sync', staticSensitivity: true } );
48
+ }, { live: true, subtree: 'cross-roots', timing: 'sync', eventDetails: true, staticSensitivity: true } );
49
49
  }
50
50
 
51
51
  function createDynamicScope( config, root ) {
@@ -90,14 +90,17 @@ export default class HTMLImportsContext extends DOMContext {
90
90
  // Any existing this.refdSourceController? Abort!
91
91
  this.refdSourceController?.disconnect();
92
92
  const realdom = this.host.ownerDocument.defaultView.webqit.realdom;
93
+ let prevRef;
93
94
  this.refdSourceController = realdom.realtime( this.host ).attr( $config.attr.importscontext, ( record, { signal } ) => {
95
+ if (record.value === prevRef) return;
96
+ prevRef = record.value;
94
97
  // No importscontext attr set. But we're still watching
95
98
  if ( !record.value ) {
96
99
  this.contextModules = undefined;
97
100
  return update();
98
101
  }
99
102
  // This superModules contextrequest is automatically aborted by the injected signal below
100
- const request = { ...this.constructor.createRequest( record.value.trim() ), live: true, signal };
103
+ const request = { ...this.constructor.createRequest( record.value.trim() ), live: true, signal, diff: true };
101
104
  this.host.parentNode[ this.configs.CONTEXT_API.api.contexts ].request( request, response => {
102
105
  this.contextModules = !( response && Object.getPrototypeOf( response ) ) ? response : getDefs( response );
103
106
  update();
@@ -70,38 +70,36 @@ export default class HTMLModule {
70
70
  expose( entries, isConnected ) {
71
71
  const { window } = env, { webqit: { Observer } } = window;
72
72
  let dirty, allFragments = this.defs[ '#' ] || [];
73
- Observer.batch( this.defs, () => {
74
- entries.forEach( entry => {
75
- if ( entry.nodeType !== 1 ) return;
76
- const isTemplate = entry.matches( this.config.templateSelector );
77
- const defId = ( entry.getAttribute( isTemplate ? this.config.attr.def : this.config.attr.fragmentdef ) || '' ).trim();
78
- if ( isConnected ) {
79
- if ( isTemplate && defId ) {
80
- new HTMLModule( entry, this.host, this.level + 1 );
81
- } else {
82
- allFragments.push( entry );
83
- dirty = true;
84
- if ( typeof requestIdleCallback === 'function' ) {
85
- requestIdleCallback( () => {
86
- this.config.idleCompilers?.forEach( callback => callback.call( this.window, entry ) );
87
- } );
88
- }
89
- }
90
- if ( defId ) {
91
- this.validateDefId( defId );
92
- Observer.set( this.defs, ( !isTemplate && '#' || '' ) + defId, entry );
93
- }
73
+ entries.forEach( entry => {
74
+ if ( entry.nodeType !== 1 ) return;
75
+ const isTemplate = entry.matches( this.config.templateSelector );
76
+ const defId = ( entry.getAttribute( isTemplate ? this.config.attr.def : this.config.attr.fragmentdef ) || '' ).trim();
77
+ if ( isConnected ) {
78
+ if ( isTemplate && defId ) {
79
+ new HTMLModule( entry, this.host, this.level + 1 );
94
80
  } else {
95
- if ( isTemplate && defId ) { HTMLModule.instance( entry ).dispose(); }
96
- else {
97
- allFragments = allFragments.filter( x => x !== entry );
98
- dirty = true;
81
+ allFragments.push( entry );
82
+ dirty = true;
83
+ if ( typeof requestIdleCallback === 'function' ) {
84
+ requestIdleCallback( () => {
85
+ this.config.idleCompilers?.forEach( callback => callback.call( this.window, entry ) );
86
+ } );
99
87
  }
100
- if ( defId ) Observer.deleteProperty( this.defs, ( !isTemplate && '#' || '' ) + defId );
101
88
  }
102
- } );
103
- if ( dirty ) Observer.set( this.defs, '#', allFragments );
89
+ if ( defId ) {
90
+ this.validateDefId( defId );
91
+ Observer.set( this.defs, ( !isTemplate && '#' || '' ) + defId, entry );
92
+ }
93
+ } else {
94
+ if ( isTemplate && defId ) { HTMLModule.instance( entry ).dispose(); }
95
+ else {
96
+ allFragments = allFragments.filter( x => x !== entry );
97
+ dirty = true;
98
+ }
99
+ if ( defId ) Observer.deleteProperty( this.defs, ( !isTemplate && '#' || '' ) + defId );
100
+ }
104
101
  } );
102
+ if ( dirty ) Observer.set( this.defs, '#', allFragments );
105
103
  }
106
104
 
107
105
  /**
@@ -49,51 +49,61 @@ export default function() {
49
49
  return anchorNode;
50
50
  };
51
51
 
52
- priv.importRequest = ( callback, signal = null ) => {
53
- const request = { ...HTMLImportsContext.createRequest( priv.moduleRef?.includes( '#' ) ? priv.moduleRef : `${ priv.moduleRef }#`/* for live children */ ), live: signal && true, signal };
54
- ( this.el.isConnected ? this.el.parentNode : priv.anchorNode.parentNode )[ configs.CONTEXT_API.api.contexts ].request( request, response => {
55
- callback( ( response instanceof window.HTMLTemplateElement ? [ ...response.content.children ] : (
56
- Array.isArray( response ) ? response : response && [ response ]
57
- ) ) || [] );
58
- } );
52
+ priv.live = callback => {
53
+ if ( priv.liveImportsRealtime ) throw new Error(`Import element already in live mode.`);
54
+ const parentNode = this.el.isConnected ? this.el.parentNode : priv.anchorNode.parentNode;
55
+ priv.liveImportsRealtime = realdom.realtime( this.el ).attr( configs.HTML_IMPORTS.attr.ref, ( record, { signal } ) => {
56
+ priv.moduleRef = record.value;
57
+ const moduleRef = priv.moduleRef.includes( '#' ) ? priv.moduleRef : `${ priv.moduleRef }#`/* for live children */;
58
+ const request = { ...HTMLImportsContext.createRequest( moduleRef ), live: signal && true, signal, diff: !moduleRef.endsWith('#') };
59
+ parentNode[ configs.CONTEXT_API.api.contexts ].request( request, response => {
60
+ callback( ( response instanceof window.HTMLTemplateElement ? [ ...response.content.children ] : (
61
+ Array.isArray( response ) ? response : response && [ response ]
62
+ ) ) || [] );
63
+ } );
64
+ }, { live: true, timing: 'sync', lifecycleSignals: true } );
65
+ priv.autoDestroyRealtime = realdom.realtime( window.document ).track( parentNode, () => {
66
+ priv.die();
67
+ }, { subtree: 'cross-roots', timing: 'sync', generation: 'exits' } );
68
+ };
69
+
70
+ priv.die = () => {
71
+ priv.autoDestroyRealtime?.disconnect();
72
+ priv.liveImportsRealtime?.disconnect();
73
+ priv.liveImportsRealtime = null;
59
74
  };
60
75
 
61
76
  priv.hydrate = ( anchorNode, slottedElements ) => {
62
- // ----------------
63
- priv.moduleRef = ( this.el.getAttribute( configs.HTML_IMPORTS.attr.ref ) || '' ).trim();
64
77
  anchorNode.replaceWith( priv.setAnchorNode( this.createAnchorNode() ) );
65
- priv.autoRestore( () => {
66
- slottedElements.forEach( slottedElement => {
67
- priv.slottedElements.add( slottedElement );
68
- _( slottedElement ).set( 'slot@imports', this.el );
69
- } );
70
- } );
71
- // ----------------
72
- priv.hydrationImportRequest = new AbortController;
73
- priv.importRequest( fragments => {
74
- if ( priv.originalsRemapped ) { return this.fill( fragments ); }
78
+ priv.live( fragments => {
79
+ // The default action
80
+ if ( priv.originalsRemapped ) return this.fill( fragments );
81
+ // Initial remap action
75
82
  const identifiersMap = fragments.map( ( fragment, i ) => ( { el: fragment, fragmentDef: fragment.getAttribute( configs.HTML_IMPORTS.attr.fragmentdef ) || '', tagName: fragment.tagName, i } ) );
76
- let i = -1;
77
- slottedElements.forEach( slottedElement => {
83
+ slottedElements.forEach( ( slottedElement, i ) => {
78
84
  const tagName = slottedElement.tagName, fragmentDef = slottedElement.getAttribute( configs.HTML_IMPORTS.attr.fragmentdef ) || '';
79
85
  const originalsMatch = ( i ++, identifiersMap.find( fragmentIdentifiers => fragmentIdentifiers.tagName === tagName && fragmentIdentifiers.fragmentDef === fragmentDef && fragmentIdentifiers.i === i ) );
80
- if ( !originalsMatch ) return; // Or should we throw integrity error?
81
- _( slottedElement ).set( 'original@imports', originalsMatch.el );
86
+ if ( originalsMatch ) _( slottedElement ).set( 'original@imports', originalsMatch.el ); // Or should we throw integrity error here?
87
+ _( slottedElement ).set( 'slot@imports', this.el );
88
+ priv.slottedElements.add( slottedElement );
82
89
  } );
83
90
  priv.originalsRemapped = true;
84
- }, priv.hydrationImportRequest.signal );
91
+ });
85
92
  };
86
93
 
87
94
  priv.autoRestore = ( callback = null ) => {
88
95
  priv.autoRestoreRealtime?.disconnect();
89
96
  if ( callback ) callback();
90
97
  const restore = () => {
91
- priv.anchorNode?.replaceWith( this.el );
92
- priv.anchorNode = null;
98
+ if (this.el.isConnected) return;
93
99
  this.el.setAttribute( 'data-nodecount', 0 );
100
+ this.el.slottingAction = true;
101
+ priv.anchorNode.replaceWith( this.el );
102
+ this.el.slottingAction = false;
103
+ priv.setAnchorNode( null );
94
104
  };
95
105
  if ( !priv.slottedElements.size ) return restore();
96
- const autoRestoreRealtime = realdom.realtime( window.document ).observe( [ ...priv.slottedElements ], record => {
106
+ const autoRestoreRealtime = realdom.realtime( priv.anchorNode.parentNode ).observe( [ ...priv.slottedElements ], record => {
97
107
  record.exits.forEach( outgoingNode => {
98
108
  _( outgoingNode ).delete( 'slot@imports' );
99
109
  priv.slottedElements.delete( outgoingNode );
@@ -109,26 +119,13 @@ export default function() {
109
119
  };
110
120
 
111
121
  priv.connectedCallback = () => {
112
- // In case this is DOM node relocation or induced reinsertion into the DOM
113
- if ( priv.slottedElements.size ) throw new Error( `Illegal reinsertion into the DOM; import slot is not empty!` );
114
- // Totally initialize this instance?
115
- if ( priv.moduleRefRealtime ) return;
116
- priv.moduleRefRealtime = realdom.realtime( this.el ).attr( configs.HTML_IMPORTS.attr.ref, ( record, { signal } ) => {
117
- priv.moduleRef = record.value;
118
- // Below, we ignore first restore from hydration
119
- priv.importRequest( fragments => !priv.hydrationImportRequest && this.fill( fragments ), signal );
120
- }, { live: true, timing: 'sync', lifecycleSignals: true } );
121
- // Must come after
122
- priv.hydrationImportRequest?.abort();
123
- priv.hydrationImportRequest = null;
122
+ if ( this.el.slottingAction ) return;
123
+ priv.live( fragments => this.fill( fragments ) );
124
124
  };
125
125
 
126
126
  priv.disconnectedCallback = () => {
127
- priv.hydrationImportRequest?.abort();
128
- priv.hydrationImportRequest = null;
129
- if ( priv.anchorNode?.isConnected ) return;
130
- priv.moduleRefRealtime?.disconnect();
131
- priv.moduleRefRealtime = null;
127
+ if ( this.el.slottingAction ) return;
128
+ priv.die();
132
129
  };
133
130
  }
134
131
 
@@ -153,7 +150,11 @@ export default function() {
153
150
  *
154
151
  * @return void
155
152
  */
156
- fill( slottableElements ) {
153
+ fill( slottableElements, r ) {
154
+ if (!this.el.isConnected && (!this[ '#' ].anchorNode || !this[ '#' ].anchorNode.isConnected)) {
155
+ // LiveImports must be responding to an event that just removed the subtree from DOM
156
+ return;
157
+ }
157
158
  if ( Array.isArray( slottableElements ) ) { slottableElements = new Set( slottableElements ) }
158
159
  // This state must be set before the diffing below and the serialization done at createAnchorNode()
159
160
  this.el.setAttribute( 'data-nodecount', slottableElements.size );
@@ -172,10 +173,11 @@ export default function() {
172
173
  } );
173
174
  // Make sure anchor node is what's in place...
174
175
  // not the import element itslef - but all only when we have slottableElements.size
175
- if ( slottableElements.size ) {
176
- const currentAnchorNode = this[ '#' ].anchorNode;
177
- const anchorNode = this[ '#' ].setAnchorNode( this.createAnchorNode() );
178
- ( this.el.isConnected ? this.el : currentAnchorNode ).replaceWith( anchorNode );
176
+ if ( slottableElements.size && this.el.isConnected ) {
177
+ const newAnchorNode = this[ '#' ].setAnchorNode( this.createAnchorNode() );
178
+ this.el.slottingAction = true;
179
+ this.el.replaceWith( newAnchorNode );
180
+ this.el.slottingAction = false;
179
181
  }
180
182
  // Insert slottables now
181
183
  slottableElements.forEach( slottableElement => {
@@ -14,26 +14,26 @@ import { _, _init } from '../util.js';
14
14
  *
15
15
  * @return Void
16
16
  */
17
- export default function init( $config = {} ) {
18
- const { config, window } = _init.call( this, 'html-imports', $config, {
17
+ export default function init($config = {}) {
18
+ const { config, window } = _init.call(this, 'html-imports', $config, {
19
19
  elements: { import: 'import', },
20
20
  attr: { def: 'def', extends: 'extends', inherits: 'inherits', ref: 'ref', importscontext: 'importscontext', },
21
21
  api: { def: 'def', defs: 'defs', import: 'import' },
22
- } );
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)`;
27
- const anchorNodeMatch = ( start, end ) => {
28
- const starting = `starts-with(., "${ start }")`;
29
- const ending = `substring(., string-length(.) - string-length("${ end }") + 1) = "${ end }"`;
30
- return `${ starting } and ${ ending }`;
22
+ });
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)`;
27
+ const anchorNodeMatch = (start, end) => {
28
+ const starting = `starts-with(., "${start}")`;
29
+ const ending = `substring(., string-length(.) - string-length("${end}") + 1) = "${end}"`;
30
+ return `${starting} and ${ending}`;
31
31
  }
32
- config.anchorNodeSelector = `comment()[${ anchorNodeMatch( `<${ config.elements.import }`, `</${ config.elements.import }>` ) }]`;
32
+ config.anchorNodeSelector = `comment()[${anchorNodeMatch(`<${config.elements.import}`, `</${config.elements.import}>`)}]`;
33
33
  window.webqit.HTMLImportsContext = HTMLImportsContext;
34
34
  window.webqit.HTMLImportElement = _HTMLImportElement();
35
- exposeAPIs.call( window, config );
36
- realtime.call( window, config );
35
+ exposeAPIs.call(window, config);
36
+ realtime.call(window, config);
37
37
  }
38
38
 
39
39
  /**
@@ -44,12 +44,12 @@ export default function init( $config = {} ) {
44
44
  *
45
45
  * @return Object
46
46
  */
47
- export function getDefs( node, autoCreate = true ) {
48
- if ( !_( node ).has( 'defs' ) && autoCreate ) {
49
- const defs = Object.create( null );
50
- _( node ).set( 'defs', defs );
51
- }
52
- return _( node ).get( 'defs' );
47
+ export function getDefs(node, autoCreate = true) {
48
+ if (!_(node).has('defs') && autoCreate) {
49
+ const defs = Object.create(null);
50
+ _(node).set('defs', defs);
51
+ }
52
+ return _(node).get('defs');
53
53
  }
54
54
 
55
55
  /**
@@ -59,44 +59,50 @@ export function getDefs( node, autoCreate = true ) {
59
59
  *
60
60
  * @return Void
61
61
  */
62
- function exposeAPIs( config ) {
62
+ function exposeAPIs(config) {
63
63
  const window = this, { webqit: { oohtml: { configs } } } = window;
64
64
  // The "def" & "defs" properties
65
- if ( config.api.def in window.HTMLTemplateElement.prototype ) { throw new Error( `The "HTMLTemplateElement" prototype already has a "${ config.api.def }" API!` ); }
66
- if ( config.api.defs in window.HTMLTemplateElement.prototype ) { throw new Error( `The "HTMLTemplateElement" prototype already has a "${ config.api.defs }" API!` ); }
65
+ if (config.api.def in window.HTMLTemplateElement.prototype) { throw new Error(`The "HTMLTemplateElement" prototype already has a "${config.api.def}" API!`); }
66
+ if (config.api.defs in window.HTMLTemplateElement.prototype) { throw new Error(`The "HTMLTemplateElement" prototype already has a "${config.api.defs}" API!`); }
67
67
  // No-conflict assertions
68
- Object.defineProperty( window.HTMLTemplateElement.prototype, config.api.def, { get: function() {
69
- return this.getAttribute( config.attr.def );
70
- } } );
71
- Object.defineProperty( window.HTMLTemplateElement.prototype, config.api.defs, { get: function() {
72
- return getDefs( this );
73
- } } );
68
+ Object.defineProperty(window.HTMLTemplateElement.prototype, config.api.def, {
69
+ get: function () {
70
+ return this.getAttribute(config.attr.def);
71
+ }
72
+ });
73
+ Object.defineProperty(window.HTMLTemplateElement.prototype, config.api.defs, {
74
+ get: function () {
75
+ return getDefs(this);
76
+ }
77
+ });
74
78
  // The "scoped" property
75
- Object.defineProperty( window.HTMLTemplateElement.prototype, 'scoped', {
79
+ Object.defineProperty(window.HTMLTemplateElement.prototype, 'scoped', {
76
80
  configurable: true,
77
- get() { return this.hasAttribute( 'scoped' ); },
78
- set( value ) { this.toggleAttribute( 'scoped', value ); },
79
- } );
81
+ get() { return this.hasAttribute('scoped'); },
82
+ set(value) { this.toggleAttribute('scoped', value); },
83
+ });
80
84
  // The Import API
81
- [ window.Document.prototype, window.Element.prototype, window.ShadowRoot.prototype ].forEach( prototype => {
85
+ [window.Document.prototype, window.Element.prototype, window.ShadowRoot.prototype].forEach(prototype => {
82
86
  // No-conflict assertions
83
- const type = prototype === window.Document.prototype ? 'Document' : ( prototype === window.ShadowRoot.prototype ? 'ShadowRoot' : 'Element' );
84
- if ( config.api.import in prototype ) { throw new Error( `The ${ type } prototype already has a "${ config.api.import }" API!` ); }
87
+ const type = prototype === window.Document.prototype ? 'Document' : (prototype === window.ShadowRoot.prototype ? 'ShadowRoot' : 'Element');
88
+ if (config.api.import in prototype) { throw new Error(`The ${type} prototype already has a "${config.api.import}" API!`); }
85
89
  // Definitions
86
- Object.defineProperty( prototype, config.api.import, { value: function( ref, live = false, callback = null ) {
87
- return importRequest( this, ...arguments );
88
- } });
89
- } );
90
- function importRequest( context, ref, live = false, callback = null ) {
90
+ Object.defineProperty(prototype, config.api.import, {
91
+ value: function (ref, live = false, callback = null) {
92
+ return importRequest(this, ...arguments);
93
+ }
94
+ });
95
+ });
96
+ function importRequest(context, ref, live = false, callback = null) {
91
97
  let options = {};
92
- if ( typeof live === 'function' ) {
98
+ if (typeof live === 'function') {
93
99
  callback = live;
94
100
  live = false;
95
- } else if ( typeof live === 'object' && live ) {
101
+ } else if (typeof live === 'object' && live) {
96
102
  options = { ...live, ...options };
97
103
  } else { options = { live }; }
98
- const request = { ...HTMLImportsContext.createRequest( ref ), ...options };
99
- return context[ configs.CONTEXT_API.api.contexts ].request( request, callback );
104
+ const request = { ...HTMLImportsContext.createRequest(ref), ...options };
105
+ return context[configs.CONTEXT_API.api.contexts].request(request, callback);
100
106
  }
101
107
  }
102
108
 
@@ -108,83 +114,83 @@ function exposeAPIs( config ) {
108
114
  *
109
115
  * @return Void
110
116
  */
111
- function realtime( config ) {
117
+ function realtime(config) {
112
118
  const window = this, { webqit: { Observer, realdom, oohtml: { configs }, HTMLImportElement, HTMLImportsContext } } = window;
113
-
119
+
114
120
  // ------------
115
121
  // MODULES
116
122
  // ------------
117
123
  const attachImportsContext = host => {
118
- const contextsApi = host[ configs.CONTEXT_API.api.contexts ];
119
- if ( !contextsApi.find( HTMLImportsContext.kind ) ) {
120
- contextsApi.attach( new HTMLImportsContext );
124
+ const contextsApi = host[configs.CONTEXT_API.api.contexts];
125
+ if (!contextsApi.find(HTMLImportsContext.kind)) {
126
+ contextsApi.attach(new HTMLImportsContext);
121
127
  }
122
128
  };
123
129
  const detachImportsContext = host => {
124
- const contextsApi = host[ configs.CONTEXT_API.api.contexts ];
125
- const ctx = contextsApi.find( HTMLImportsContext.kind );
126
- if ( ctx && ( /* disconnect? */!host.isConnected || /* not inheriting && no localModules? */(
127
- !host.matches?.( config.importsContextSelector ) && !Object.keys( ctx.localModules ).length
128
- ) ) ) {
129
- contextsApi.detach( ctx );
130
+ const contextsApi = host[configs.CONTEXT_API.api.contexts];
131
+ const ctx = contextsApi.find(HTMLImportsContext.kind);
132
+ if (ctx && ( /* disconnect? */!host.isConnected || /* not inheriting && no localModules? */(
133
+ !host.matches?.(config.importsContextSelector) && !Object.keys(ctx.localModules).length
134
+ ))) {
135
+ contextsApi.detach(ctx);
130
136
  }
131
137
  };
132
138
  // ------------
133
- realdom.realtime( window.document ).query( [ config.templateSelector, config.importsContextSelector ], record => {
134
- record.entrants.forEach( entry => {
135
- if ( entry.matches( config.templateSelector ) ) {
136
- const htmlModule = HTMLModule.instance( entry );
139
+ realdom.realtime(window.document).query([config.templateSelector, config.importsContextSelector], record => {
140
+ record.entrants.forEach(entry => {
141
+ if (entry.matches(config.templateSelector)) {
142
+ const htmlModule = HTMLModule.instance(entry);
137
143
  htmlModule.ownerContext = entry.scoped ? entry.parentNode : entry.getRootNode();
138
- const ownerContextModulesObj = getDefs( htmlModule.ownerContext );
139
- if ( htmlModule.defId ) { Observer.set( ownerContextModulesObj, htmlModule.defId, entry ); }
144
+ const ownerContextModulesObj = getDefs(htmlModule.ownerContext);
145
+ if (htmlModule.defId) { Observer.set(ownerContextModulesObj, htmlModule.defId, entry); }
140
146
  // The ownerContext's defs - ownerContextModulesObj - has to be populated
141
147
  // Before attaching a context instance to it, to give the just created context something to use for
142
148
  // fullfiling reclaimed requests.
143
- attachImportsContext( htmlModule.ownerContext );
149
+ attachImportsContext(htmlModule.ownerContext);
144
150
  } else {
145
- attachImportsContext( entry );
151
+ attachImportsContext(entry);
146
152
  }
147
- } );
148
- record.exits.forEach( entry => {
149
- if ( entry.matches( config.templateSelector ) ) {
150
- const htmlModule = HTMLModule.instance( entry );
151
- const ownerContextModulesObj = getDefs( htmlModule.ownerContext );
152
- if ( htmlModule.defId && htmlModule.ownerContext.isConnected ) { Observer.deleteProperty( ownerContextModulesObj, htmlModule.defId ); }
153
- detachImportsContext( htmlModule.ownerContext );
153
+ });
154
+ record.exits.forEach(entry => {
155
+ if (entry.matches(config.templateSelector)) {
156
+ const htmlModule = HTMLModule.instance(entry);
157
+ const ownerContextModulesObj = getDefs(htmlModule.ownerContext);
158
+ if (htmlModule.defId && htmlModule.ownerContext.isConnected) { Observer.deleteProperty(ownerContextModulesObj, htmlModule.defId); }
159
+ detachImportsContext(htmlModule.ownerContext);
154
160
  } else {
155
- detachImportsContext( entry );
161
+ detachImportsContext(entry);
156
162
  }
157
- } );
158
- }, { live: true, subtree: 'cross-roots', timing: 'sync', staticSensitivity: true, eventDetails: true } );
159
-
163
+ });
164
+ }, { live: true, subtree: 'cross-roots', timing: 'sync', staticSensitivity: true, eventDetails: true });
165
+
160
166
  // ------------
161
167
  // IMPORTS
162
168
  // ------------
163
- realdom.realtime( window.document ).query( config.elements.import, record => {
164
- record.entrants.forEach( node => handleRealtime( node, true, record ) );
165
- record.exits.forEach( node => handleRealtime( node, false, record ) );
166
- }, { live: true, subtree: 'cross-roots', timing: 'sync' } );
167
- function handleRealtime( entry, connectedState ) {
168
- const elInstance = HTMLImportElement.instance( entry );
169
- if ( connectedState ) { elInstance[ '#' ].connectedCallback(); }
170
- else { elInstance[ '#' ].disconnectedCallback(); }
169
+ realdom.realtime(window.document).query(config.elements.import, record => {
170
+ record.entrants.forEach(node => handleRealtime(node, true, record));
171
+ record.exits.forEach(node => handleRealtime(node, false, record));
172
+ }, { live: true, subtree: 'cross-roots', timing: 'sync' });
173
+ function handleRealtime(entry, connectedState) {
174
+ const elInstance = HTMLImportElement.instance(entry);
175
+ if (connectedState) { elInstance['#'].connectedCallback(); }
176
+ else { elInstance['#'].disconnectedCallback(); }
171
177
  }
172
178
  // Hydration
173
- if ( window.webqit.env === 'server' ) return;
174
- realdom.realtime( window.document ).query( `(${ config.anchorNodeSelector })`, record => {
175
- record.entrants.forEach( anchorNode => {
176
- if ( _( anchorNode ).get( 'isAnchorNode' ) ) return; // Doubling up on the early return above! Ignoring every just created anchorNode
177
- const reviver = window.document.createElement( 'div' );
179
+ if (window.webqit.env === 'server') return;
180
+ realdom.realtime(window.document).query(`(${config.anchorNodeSelector})`, record => {
181
+ record.entrants.forEach(anchorNode => {
182
+ if (_(anchorNode).get('isAnchorNode')) return; // Doubling up on the early return above! Ignoring every just created anchorNode
183
+ const reviver = window.document.createElement('div');
178
184
  reviver.innerHTML = anchorNode.nodeValue;
179
185
  reviver.innerHTML = reviver.firstChild.textContent;
180
186
  const importEl = reviver.firstChild;
181
- let nodecount = parseInt( importEl.getAttribute( 'data-nodecount' ) );
187
+ let nodecount = parseInt(importEl.getAttribute('data-nodecount'));
182
188
  const slottedElements = new Set;
183
189
  let slottedElement = anchorNode;
184
- while ( ( slottedElement = slottedElement.previousElementSibling ) && slottedElement.matches( config.slottedElementsSelector ) && nodecount -- ) {
185
- slottedElements.add( slottedElement );
190
+ while ((slottedElement = slottedElement.previousElementSibling) && slottedElement.matches(config.slottedElementsSelector) && nodecount--) {
191
+ slottedElements.add(slottedElement);
186
192
  }
187
- HTMLImportElement.instance( importEl )[ '#' ].hydrate( anchorNode, slottedElements );
188
- } );
189
- }, { live: true, subtree: 'cross-roots', timing: 'sync' } );
193
+ HTMLImportElement.instance(importEl)['#'].hydrate(anchorNode, slottedElements);
194
+ });
195
+ }, { live: true, subtree: 'cross-roots', timing: 'sync' });
190
196
  }
@@ -15,7 +15,7 @@ describe(`HTML Imports`, function() {
15
15
  <p>Hellort</p>
16
16
  </template>`;
17
17
  const body = `
18
- <import ref="temp0"></import>`;
18
+ <import ref="temp0#"></import>`;
19
19
  const { document } = createDocument( head, body );
20
20
 
21
21
  it ( `The document object and <template> elements should expose an "import" property`, async function() {
@@ -31,6 +31,7 @@ describe(`HTML Imports`, function() {
31
31
  const templateEl = document.querySelector( 'template' );
32
32
  let added = document.createElement( 'div' );
33
33
  templateEl.content.appendChild( added );
34
+ console.log('\n\n\n\n', document.body.outerHTML);
34
35
  expect( document.body.children ).to.have.length( 3 );
35
36
  } );
36
37
  } );