@webqit/oohtml 2.0.2 → 2.1.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -14,7 +14,7 @@
14
14
  "wicg-proposal"
15
15
  ],
16
16
  "homepage": "https://webqit.io/tooling/oohtml",
17
- "version": "2.0.2",
17
+ "version": "2.1.1",
18
18
  "license": "MIT",
19
19
  "repository": {
20
20
  "type": "git",
@@ -107,13 +107,13 @@ export default class HTMLContext {
107
107
  * @handleEvent()
108
108
  */
109
109
  handleEvent( event ) {
110
- if ( this.disposed || ( event.target === this.host && !event.request?.selfScoped )
110
+ if ( this.disposed || ( event.target === this.host && event.request?.superContextOnly )
111
111
  || !event.request || typeof event.callback !== 'function' || !this.constructor.matchRequest( this.id, event.request ) ) return;
112
112
  event.stopPropagation();
113
113
  if ( event.type === 'contextclaim' ) {
114
114
  const claims = new Set;
115
115
  this.subscriptions.forEach( subscriptionEvent => {
116
- if ( !event.target.contains( subscriptionEvent.request.selfScoped ? subscriptionEvent.target : subscriptionEvent.target.parentNode )
116
+ if ( !event.target.contains( subscriptionEvent.request.superContextOnly ? subscriptionEvent.target.parentNode : subscriptionEvent.target )
117
117
  || !this.constructor.matchRequest( event.request/*provider ID*/, subscriptionEvent.request/*request ID*/ ) ) return;
118
118
  this.subscriptions.delete( subscriptionEvent );
119
119
  claims.add( subscriptionEvent );
@@ -133,7 +133,7 @@ export default class HTMLContext {
133
133
  this.disposed = false;
134
134
  host.addEventListener( 'contextrequest', this );
135
135
  host.addEventListener( 'contextclaim', this );
136
- HTMLContextManager.instance( host ).ask( this.id, claims => claims.forEach( subscriptionEvent => {
136
+ HTMLContextManager.instance( host ).ask( { ...this.id, superContextOnly: true }, claims => claims.forEach( subscriptionEvent => {
137
137
  this.subscribe( subscriptionEvent );
138
138
  this.handle( subscriptionEvent );
139
139
  } ), { type: 'contextclaim' } );
@@ -53,7 +53,7 @@ export default function( params ) {
53
53
 
54
54
  priv.importRequest = ( callback, signal = null ) => {
55
55
  const detail = priv.moduleRef && !priv.moduleRef.includes( '#' ) ? `${ priv.moduleRef }#default` : priv.moduleRef;
56
- const request = _HTMLImportsContext.createRequest( { detail, live: signal && true, signal, selfScoped: true } );
56
+ const request = _HTMLImportsContext.createRequest( { detail, live: signal && true, signal } );
57
57
  HTMLContextManager.instance( this.el.isConnected ? this.el.parentNode : priv.anchorNode.parentNode ).ask( request, response => {
58
58
  callback( ( response instanceof Set ? new Set( response ) : response ) || [] );
59
59
  } );
@@ -73,9 +73,9 @@ export default function( params ) {
73
73
  priv.hydrationImportRequest = new AbortController;
74
74
  priv.importRequest( modules => {
75
75
  if ( priv.originalsRemapped ) { return this.fill( modules ); }
76
- const identifiersMap = [ ...modules ].map( module => ( { el: module, exportId: module.getAttribute( params.export.attr.exportid ) || 'default', tagName: module.tagName, } ) );
76
+ const identifiersMap = [ ...modules ].map( module => ( { el: module, exportId: module.getAttribute( params.export.attr.exportid ) || '#default', tagName: module.tagName, } ) );
77
77
  slottedElements.forEach( slottedElement => {
78
- const tagName = slottedElement.tagName, exportId = slottedElement.getAttribute( params.export.attr.exportid ) || 'default';
78
+ const tagName = slottedElement.tagName, exportId = slottedElement.getAttribute( params.export.attr.exportid ) || '#default';
79
79
  const originalsMatch = identifiersMap.filter( moduleIdentifiers => tagName === moduleIdentifiers.tagName && exportId === moduleIdentifiers.exportId );
80
80
  if ( originalsMatch.length !== 1 ) return;
81
81
  _( slottedElement ).set( 'original@imports', originalsMatch[ 0 ].el );
@@ -71,32 +71,32 @@ export default class HTMLExportsManager {
71
71
  const fragmentsExports = new Map;
72
72
  entries.forEach( entry => {
73
73
  if ( entry.nodeType !== 1 ) return;
74
- if ( entry.matches( this.params.templateSelector ) ) {
74
+ const exportId = ( entry.getAttribute( this.params.export.attr.exportid ) || '' ).trim() || '#default';
75
+ const isPackage = entry.matches( this.params.templateSelector );
76
+ if ( exportId.startsWith( '#' ) ) {
77
+ this.validateExportId( exportId.substring( 1 ) );
78
+ if ( !fragmentsExports.has( exportId ) ) { fragmentsExports.set( exportId, [] ); }
79
+ fragmentsExports.get( exportId ).push( entry );
80
+ } else {
75
81
  if ( isConnected ) {
76
- const moduleExport = new HTMLExportsManager( entry, this.params, this.host, this.level + 1 );
77
- if ( moduleExport.exportId ) { Observer.set( this.modules, moduleExport.exportId, entry ); }
82
+ if ( isPackage ) { new HTMLExportsManager( entry, this.params, this.host, this.level + 1 ); }
83
+ Observer.set( this.modules, exportId, entry );
78
84
  } else {
79
- const moduleExport = HTMLModulesGraph.instance( entry, this.params );
80
- if ( moduleExport.exportId ) { Observer.deleteProperty( this.modules, moduleExport.exportId ); }
81
- moduleExport.dispose();
85
+ if ( isPackage ) { HTMLModulesGraph.instance( entry, this.params ).dispose(); }
86
+ Observer.deleteProperty( this.modules, exportId );
82
87
  }
83
- } else {
84
- const exportId = ( entry.getAttribute( this.params.export.attr.exportid ) || '' ).trim() || 'default';
85
- this.validateExportId( exportId );
86
- if ( !fragmentsExports.has( exportId ) ) { fragmentsExports.set( exportId, [] ); }
87
- fragmentsExports.get( exportId ).push( entry );
88
88
  }
89
89
  } );
90
90
  // ----------------
91
91
  fragmentsExports.forEach( ( fragments, exportId ) => {
92
- let existingFragments = Observer.get( this.modules, `#${ exportId }` );
92
+ let existingFragments = Observer.get( this.modules, exportId );
93
93
  if ( isConnected ) {
94
94
  existingFragments = new Set( ( existingFragments ? [ ...existingFragments ] : [] ).concat( fragments ) );
95
95
  } else if ( existingFragments ) {
96
96
  fragments.forEach( el => existingFragments.delete( el ) );
97
97
  }
98
- if ( !isConnected && !existingFragments.size ) { Observer.deleteProperty( this.modules, `#${ exportId }` ); }
99
- else { Observer.set( this.modules, `#${ exportId }`, existingFragments ) }
98
+ if ( !isConnected && !existingFragments.size ) { Observer.deleteProperty( this.modules, exportId ); }
99
+ else { Observer.set( this.modules, exportId, existingFragments ) }
100
100
  } );
101
101
  }
102
102
 
@@ -158,20 +158,28 @@ export default class HTMLExportsManager {
158
158
  * @returns Void|AbortController
159
159
  */
160
160
  evalInheritance( ) {
161
- let inheritedIds;
162
- if ( this.parent && ( inheritedIds = ( this.host.getAttribute( this.params.template.attr.inherits ) || '' ).trim() )
163
- && ( inheritedIds = inheritedIds.split( ' ' ).map( id => id.trim() ) ).length ) {
164
- const parentExportsObj = getModulesObject( this.parent );
165
- return Observer.get( parentExportsObj, inheritedIds, records => {
166
- records.forEach( record => {
167
- if ( [ 'get'/*initial get*/, 'set', 'defineProperty' ].includes( record.type ) ) {
168
- Observer[ record.type.replace( 'get', 'set' ) ]( this.modules, record.key, record.value );
169
- } else if ( record.type === 'deleteProperty' ) {
170
- Observer.deleteProperty( this.modules, record.key );
171
- }
172
- } );
173
- }, { live: true } );
161
+ if ( !this.parent ) return [];
162
+ let extendedId = ( this.host.getAttribute( this.params.template.attr.extends ) || '' ).trim();
163
+ let inheritedIds = ( this.host.getAttribute( this.params.template.attr.inherits ) || '' ).trim();
164
+ const handleInherited = records => {
165
+ records.forEach( record => {
166
+ if ( Observer.get( this.modules, record.key ) !== record.oldValue ) return;
167
+ if ( [ 'get'/*initial get*/, 'set', 'defineProperty' ].includes( record.type ) ) {
168
+ Observer[ record.type.replace( 'get', 'set' ) ]( this.modules, record.key, record.value );
169
+ } else if ( record.type === 'deleteProperty' ) {
170
+ Observer.deleteProperty( this.modules, record.key );
171
+ }
172
+ } );
173
+ };
174
+ const realtimes = [];
175
+ const parentExportsObj = getModulesObject( this.parent );
176
+ if ( extendedId ) {
177
+ realtimes.push( Observer.deep( parentExportsObj, [ extendedId, this.params.template.api.modules, Infinity ], Observer.get, handleInherited, { live: true } ) );
178
+ }
179
+ if ( ( inheritedIds = inheritedIds.split( ' ' ).map( id => id.trim() ).filter( x => x ) ).length ) {
180
+ realtimes.push( Observer.get( parentExportsObj, inheritedIds, handleInherited, { live: true } ) );
174
181
  }
182
+ return realtimes;
175
183
  }
176
184
 
177
185
  /**
@@ -182,7 +190,7 @@ export default class HTMLExportsManager {
182
190
  dispose() {
183
191
  this.realtimeA.disconnect();
184
192
  this.realtimeB.disconnect();
185
- this.realtimeC?.abort();
193
+ this.realtimeC.forEach( r => r.abort() );
186
194
  Object.entries( this.modules ).forEach( ( [ key, entry ] ) => {
187
195
  if ( key.startsWith( '#' ) ) return;
188
196
  HTMLExportsManager.instance( entry ).dispose();
@@ -82,7 +82,7 @@ export default class _HTMLImportsContext extends HTMLContext {
82
82
  return update();
83
83
  }
84
84
  // This superModules contextrequest is automatically aborted by the injected signal below
85
- const request = this.constructor.createRequest( { detail: record.value.trim(), live: true, signal } );
85
+ const request = this.constructor.createRequest( { detail: record.value.trim(), live: true, signal, superContextOnly: true } );
86
86
  HTMLContextManager.instance( this.host ).ask( request, response => {
87
87
  this.altModules = !( response && Object.getPrototypeOf( response ) ) ? response : getModulesObject( response );
88
88
  update();
@@ -19,7 +19,7 @@ export default function init( $params = {} ) {
19
19
  const window = this, dom = wqDom.call( window );
20
20
  // -------
21
21
  const params = dom.meta( 'oohtml' ).copyWithDefaults( $params, {
22
- template: { attr: { exportid: 'exportid', inherits: 'inherits' }, api: { modules: 'modules', exportid: 'exportid' }, },
22
+ template: { attr: { exportid: 'exportid', extends: 'extends', inherits: 'inherits' }, api: { modules: 'modules', exportid: 'exportid' }, },
23
23
  context: { attr: { importscontext: 'importscontext', contextname: 'contextname' }, api: { modules: 'modules' }, },
24
24
  export: { attr: { exportid: 'exportid' }, },
25
25
  staticsensitivity: true,
@@ -49,7 +49,7 @@ export function getModulesObject( node, autoCreate = true ) {
49
49
  if ( !_( node ).has( 'modules' ) && autoCreate ) {
50
50
  const modulesObj = Object.create( null );
51
51
  Observer.intercept( modulesObj, 'set', ( event, receiver, next ) => {
52
- if ( !event.key.startsWith( '#' ) || event.value instanceof Set ) return next();
52
+ if ( !event.value || !event.key.startsWith( '#' ) || event.value instanceof Set ) return next();
53
53
  if ( !Array.isArray( event.value ) ) { event.value = [ event.value ]; }
54
54
  event.value = new Set( event.value );
55
55
  return next();
@@ -3,7 +3,7 @@
3
3
  * @imports
4
4
  */
5
5
  import { expect } from 'chai';
6
- import { delay, createDocument, mockRemoteFetch, printDocument, _ } from './index.js';
6
+ import { delay, createDocument, mockRemoteFetch, _ } from './index.js';
7
7
 
8
8
  describe(`HTML Imports`, function() {
9
9
 
@@ -41,15 +41,37 @@ describe(`HTML Imports`, function() {
41
41
 
42
42
  const head = `
43
43
  <template exportid="temp0">
44
+ <!-- ------- -->
44
45
  <p>Hello world Export</p>
45
46
  <p>Hellort</p>
46
- <input exportid="input" />
47
+ <input exportid="#input" />
47
48
  <template exportid="temp1">
48
- <textarea exportid="input"></textarea>
49
+ <textarea exportid="#input"></textarea>
49
50
  <template exportid="temp2">
50
- <select exportid="input"></select>
51
+ <select exportid="#input"></select>
51
52
  </template>
52
53
  </template>
54
+ <!-- ------- -->
55
+ <template exportid="_landing1">
56
+ <div exportid="#main.html">a</div>
57
+ <template exportid="_landing2">
58
+ <div exportid="#main.html">b</div>
59
+ <template exportid="_docs">
60
+ <div exportid="#main.html">c</div>
61
+ </template>
62
+ </template>
63
+ </template>
64
+ <!-- ------- -->
65
+ <template exportid="landing1" extends="_landing1">
66
+ <div exportid="#README.md">1</div>
67
+ <template exportid="landing2" extends="_landing2">
68
+ <div exportid="#README.md">2</div>
69
+ <template exportid="docs" extends="_docs">
70
+ <div exportid="#README.md">3</div>
71
+ </template>
72
+ </template>
73
+ </template>
74
+ <!-- ------- -->
53
75
  </template>`;
54
76
  const body = `
55
77
  <import module="temp0/uuu"></import>`;
@@ -86,6 +108,12 @@ describe(`HTML Imports`, function() {
86
108
  document.body.querySelector( 'input' ).remove();
87
109
  expect( document.body.firstElementChild.nodeName ).to.eq( 'IMPORT' );
88
110
  } );
111
+
112
+ /*
113
+ it ( ``, async function() {
114
+ console.log('"""""""""""""""""""""""""""""""""""""""""""""', document.modules.temp0.modules.landing1.modules.landing2.modules.docs.modules);
115
+ } );
116
+ */
89
117
 
90
118
  } );
91
119
 
@@ -131,17 +159,17 @@ describe(`HTML Imports`, function() {
131
159
 
132
160
  const head = `
133
161
  <template exportid="temp0">
134
- <input exportid="input" />
162
+ <input exportid="#input" />
135
163
  <template exportid="temp1">
136
- <textarea exportid="input"></textarea>
164
+ <textarea exportid="#input"></textarea>
137
165
  <template exportid="temp2">
138
- <select exportid="input"></select>
166
+ <select exportid="#input"></select>
139
167
  </template>
140
168
  </template>
141
169
  </template>`;
142
170
  const body = `
143
171
  <div importscontext="temp0/temp1">
144
- <textarea exportid="input"></textarea>
172
+ <textarea exportid="#input"></textarea>
145
173
  <!--<import module="#input"></import>-->
146
174
  </div>`;
147
175
  const { document } = createDocument( head, body );
@@ -163,17 +191,17 @@ describe(`HTML Imports`, function() {
163
191
 
164
192
  const head = `
165
193
  <template exportid="temp0">
166
- <input exportid="input" />
194
+ <input exportid="#input" />
167
195
  <template exportid="temp1">
168
- <textarea exportid="input"></textarea>
196
+ <textarea exportid="#input"></textarea>
169
197
  <template exportid="temp2">
170
- <select exportid="input"></select>
198
+ <select exportid="#input"></select>
171
199
  </template>
172
200
  </template>
173
201
  </template>`;
174
202
  const body = `
175
203
  <div importscontext="temp0/temp1">
176
- <textarea exportid="input"></textarea>
204
+ <textarea exportid="#input"></textarea>
177
205
  <!--<import module="#input"></import>-->
178
206
  </div>`;
179
207
  const { document } = createDocument( head, body );
package/test/test.html CHANGED
@@ -2,21 +2,21 @@
2
2
  <html>
3
3
  <head>
4
4
  <meta name="oohtml" content="script.retention=hidden" />
5
- <script src="https://unpkg.com/@webqit/oohtml/dist/main.js"></script>
5
+ <script src="/oohtml/dist/main.js"></script>
6
6
  <script>
7
7
  window.extVar = 'External variable initial value.';
8
8
  window.Observer = wq.Observer;
9
9
  </script>
10
10
  <template exportid="temp0">
11
- <input exportid="input" />
11
+ <input exportid="#input" />
12
12
  <template exportid="temp1">
13
- <textarea exportid="input"></textarea>
13
+ <textarea exportid="#input" placeholder="This is to be rendered"></textarea>
14
14
  <template exportid="temp2">
15
- <select exportid="input"></select>
15
+ <select exportid="#input"></select>
16
16
  </template>
17
17
  <template exportid="temp2b" inherits="#input"></template>
18
18
  <template exportid="temp2c">
19
- <textarea exportid="input"></textarea>
19
+ <textarea exportid="#input"></textarea>
20
20
  </template>
21
21
  </template>
22
22
  </template>
@@ -24,7 +24,7 @@
24
24
  <body>
25
25
 
26
26
  <div importscontext="temp0/temp1">
27
- <textarea exportid="input"></textarea>
27
+ <textarea exportid="#input" placeholder="This is server-rendered"></textarea>
28
28
  <!--<import module="#input"></import>-->
29
29
  </div>
30
30