@webqit/oohtml 3.0.1-9 → 3.1.2

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.
Files changed (50) hide show
  1. package/README.md +532 -229
  2. package/dist/bindings-api.js +1 -1
  3. package/dist/bindings-api.js.map +3 -3
  4. package/dist/context-api.js +1 -1
  5. package/dist/context-api.js.map +3 -3
  6. package/dist/data-binding.js +16 -36
  7. package/dist/data-binding.js.map +3 -3
  8. package/dist/html-imports.js +1 -1
  9. package/dist/html-imports.js.map +3 -3
  10. package/dist/main.js +31 -37
  11. package/dist/main.js.map +3 -3
  12. package/dist/main.lite.js +56 -0
  13. package/dist/main.lite.js.map +7 -0
  14. package/dist/namespaced-html.js +1 -1
  15. package/dist/namespaced-html.js.map +3 -3
  16. package/dist/scoped-css.js +3 -3
  17. package/dist/scoped-css.js.map +2 -2
  18. package/dist/scoped-js.js +1 -21
  19. package/dist/scoped-js.js.map +3 -3
  20. package/package.json +3 -5
  21. package/src/api.global.js +11 -0
  22. package/src/api.global.lite.js +11 -0
  23. package/src/bindings-api/DOMBindingsContext.js +51 -0
  24. package/src/bindings-api/index.js +30 -42
  25. package/src/context-api/DOMContext.js +128 -0
  26. package/src/context-api/DOMContextResponse.js +15 -0
  27. package/src/context-api/DOMContexts.js +89 -0
  28. package/src/context-api/DuplicateContextError.js +2 -0
  29. package/src/context-api/_DOMContextRequestEvent.js +49 -0
  30. package/src/context-api/index.js +20 -22
  31. package/src/data-binding/index.js +20 -26
  32. package/src/html-imports/{_HTMLImportsProvider.js → HTMLImportsContext.js} +42 -33
  33. package/src/html-imports/{_HTMLExportsManager.js → HTMLModule.js} +40 -38
  34. package/src/html-imports/_HTMLImportElement.js +17 -17
  35. package/src/html-imports/index.js +46 -49
  36. package/src/index.js +2 -7
  37. package/src/namespaced-html/index.js +3 -7
  38. package/src/scoped-css/index.js +1 -1
  39. package/src/scoped-js/index.js +2 -13
  40. package/src/util.js +8 -5
  41. package/test/imports.test.js +1 -3
  42. package/test/index.js +1 -1
  43. package/test/modules.test.js +35 -38
  44. package/src/bindings-api/_HTMLBindingsProvider.js +0 -51
  45. package/src/context-api/ContextReturnValue.js +0 -22
  46. package/src/context-api/HTMLContext.js +0 -85
  47. package/src/context-api/HTMLContextProvider.js +0 -175
  48. package/src/context-api/_ContextRequestEvent.js +0 -26
  49. package/src/html-imports/_HTMLImportElement copy.js +0 -217
  50. package/src/targets.browser.js +0 -10
@@ -1,85 +0,0 @@
1
-
2
- /**
3
- * @imports
4
- */
5
- import ContextReturnValue from './ContextReturnValue.js';
6
- import _ContextRequestEvent from './_ContextRequestEvent.js';
7
- import { _ } from '../util.js';
8
-
9
- export default class HTMLContext {
10
-
11
- /**
12
- * @instance
13
- */
14
- static instance( host ) {
15
- return _( host ).get( 'context::instance' ) || new this( host );;
16
- }
17
-
18
- /**
19
- * @constructor
20
- */
21
- constructor( host ) {
22
- _( host ).get( `context::instance` )?.dispose();
23
- _( host ).set( `context::instance`, this );
24
- const priv = { host, contexts: new Set };
25
- Object.defineProperty( this, '#', { get: () => priv } );
26
- const ContextRequestEvent = _ContextRequestEvent.call( host.ownerDocument?.defaultView || host.defaultView );
27
- Object.defineProperty( this, 'ContextRequestEvent', { get: () => ContextRequestEvent } );
28
- this[ Symbol.iterator ] = function*() {
29
- yield* priv.contexts;
30
- }
31
- }
32
-
33
- /**
34
- * @length()
35
- */
36
- get length() {
37
- this[ '#' ].contexts.size;
38
- }
39
-
40
- /**
41
- * @find()
42
- */
43
- findProvider( callback ) {
44
- return [ ...this[ '#' ].contexts ].find( callback );
45
- }
46
-
47
- /**
48
- * @attachProvider()
49
- */
50
- attachProvider( context ) {
51
- this[ '#' ].contexts.add( context );
52
- context.initialize( this[ '#' ].host );
53
- }
54
-
55
- /**
56
- * @detachProvider()
57
- */
58
- detachProvider( context ) {
59
- context.dispose( this[ '#' ].host );
60
- this[ '#' ].contexts.delete( context );
61
- }
62
-
63
- /**
64
- * @request()
65
- */
66
- request( request, callback = null, options = {} ) {
67
- if ( typeof callback === 'object' ) {
68
- options = callback;
69
- callback = null;
70
- }
71
- let contextReturnValue;
72
- if ( !callback ) {
73
- contextReturnValue = new ContextReturnValue( request, this[ '#' ].host );
74
- callback = contextReturnValue.callback.bind( contextReturnValue );
75
- }
76
- const returnValue = this[ '#' ].host.dispatchEvent( new this.ContextRequestEvent( request, callback, { bubbles: true, ...options } ) );
77
- return contextReturnValue ?? returnValue;
78
- }
79
-
80
- /**
81
- * @dispose()
82
- */
83
- dispose() {}
84
-
85
- }
@@ -1,175 +0,0 @@
1
-
2
- /**
3
- * @imports
4
- */
5
- import { _compare } from '../util.js';
6
- import HTMLContext from './HTMLContext.js';
7
-
8
- export default class HTMLContextProvider {
9
-
10
- /**
11
- * For reference purposes
12
- */
13
- static providers = new Map;
14
-
15
- /**
16
- * To be implemented by subclasses
17
- */
18
- static type;
19
-
20
- /**
21
- * @config
22
- */
23
- static get config() {
24
- return {};
25
- }
26
-
27
- /**
28
- * @attachTo
29
- */
30
- static attachTo( host, Id, multiple = false ) {
31
- this.providers.set( this.type, this );
32
- let provider, contextMgr = HTMLContext.instance( host );
33
- if ( !multiple && ( provider = contextMgr.findProvider( provider => this.matchId( provider.id, Id ) ) ) ) return provider;
34
- return contextMgr.attachProvider( new this( Id ) );
35
- }
36
-
37
- /**
38
- * @detachFrom
39
- */
40
- static detachFrom( host, Id, multipleOrFilter = false ) {
41
- let provider, contextMgr = HTMLContext.instance( host );
42
- for ( provider of contextMgr[ '#' ].contexts ) {
43
- if ( !this.matchId( provider.id, Id ) || ( typeof multipleOrFilter === 'function' && !multipleOrFilter( provider ) ) ) continue;
44
- contextMgr.detachProvider( provider );
45
- if ( typeof multiple !== 'function' && !multipleOrFilter ) return provider;
46
- }
47
- }
48
-
49
- /**
50
- * @createId
51
- */
52
- static createId( host, fields = {} ) {
53
- const id = { type: this.type, ...fields };
54
- if ( id.contextName ) return id;
55
- if ( host.getAttribute && !( id.contextName = ( host.getAttribute( this.config.context.attr.contextname ) || '' ).trim() ) ) {
56
- delete id.contextName;
57
- } else if ( !host.ownerDocument ) {
58
- id.contextName = 'root';
59
- }
60
- return id;
61
- }
62
-
63
- /**
64
- * @matchId
65
- */
66
- static matchId( a, b ) {
67
- return _compare( a, b, 1, true );
68
- }
69
-
70
- /**
71
- * @createRequest
72
- */
73
- static createRequest( fields = {} ) {
74
- return { type: this.type, ...fields };
75
- }
76
-
77
- /**
78
- * @matchesRequest
79
- */
80
- static matchRequest( id, request ) {
81
- return request.type === id.type && ( !request.contextName || request.contextName === id.contextName );
82
- }
83
-
84
- /**
85
- * @constructor
86
- */
87
- constructor( id ) {
88
- Object.defineProperty( this, 'id', { get: () => id } );
89
- Object.defineProperty( this, 'subscriptions', { value: new Set } );
90
- }
91
-
92
- /**
93
- * @length()
94
- */
95
- get length() {
96
- this.subscriptions.size;
97
- }
98
-
99
- /**
100
- * @handle()
101
- */
102
- handle( event ) {}
103
-
104
- /**
105
- * @subscribe()
106
- */
107
- subscribe( event ) {
108
- this.subscriptions.add( event );
109
- if ( !event.request.signal ) return;
110
- event.request.signal.addEventListener( 'abort', () => {
111
- this.unsubscribe( event );
112
- } );
113
- }
114
-
115
- /**
116
- * @unsubscribe()
117
- */
118
- unsubscribe( event ) {
119
- this.subscriptions.delete( event );
120
- event.request.controller?.abort();
121
- }
122
-
123
- /**
124
- * @handleEvent()
125
- */
126
- handleEvent( event ) {
127
- if ( this.disposed || ( event.target === this.host && event.request?.superContextOnly )
128
- || !( typeof event.request === 'object' && event.request ) || typeof event.respondWith !== 'function' || !this.constructor.matchRequest( this.id, event.request ) ) return;
129
- event.stopPropagation();
130
- if ( event.type === 'contextclaim' ) {
131
- const claims = new Set;
132
- this.subscriptions.forEach( subscriptionEvent => {
133
- if ( !event.target.contains( subscriptionEvent.request.superContextOnly ? subscriptionEvent.target.parentNode : subscriptionEvent.target )
134
- || !this.constructor.matchRequest( event.request/*provider ID*/, subscriptionEvent.request/*request ID*/ ) ) return;
135
- this.subscriptions.delete( subscriptionEvent );
136
- claims.add( subscriptionEvent );
137
- } );
138
- event.respondWith( claims );
139
- } else if ( event.type === 'contextrequest' ) {
140
- if ( event.request.live ) { this.subscribe( event ); }
141
- this.handle( event );
142
- }
143
- }
144
-
145
- /**
146
- * @initialize()
147
- */
148
- initialize( host ) {
149
- this.host = host;
150
- this.disposed = false;
151
- host.addEventListener( 'contextrequest', this );
152
- host.addEventListener( 'contextclaim', this );
153
- HTMLContext.instance( host ).request( { ...this.id, superContextOnly: true }, claims => claims.forEach( subscriptionEvent => {
154
- this.subscribe( subscriptionEvent );
155
- this.handle( subscriptionEvent );
156
- } ), { type: 'contextclaim' } );
157
- return this;
158
- }
159
-
160
- /**
161
- * @dispose()
162
- */
163
- dispose( host ) {
164
- this.disposed = true;
165
- host.removeEventListener( 'contextrequest', this );
166
- host.removeEventListener( 'contextclaim', this );
167
- this.subscriptions.forEach( subscriptionEvent => {
168
- this.unsubscribe( subscriptionEvent );
169
- const { target, request, callback, options } = subscriptionEvent;
170
- HTMLContext.instance( target ).request( request, callback, options );
171
- } );
172
- return this;
173
- }
174
-
175
- }
@@ -1,26 +0,0 @@
1
-
2
- export default function() {
3
- const window = this;
4
- return class ContextRequestEvent extends window.Event {
5
-
6
- /**
7
- * @constructor
8
- */
9
- constructor( request, callback, { type = 'contextrequest', ...options } = {} ) {
10
- super( type, options );
11
- Object.defineProperty( this, 'request', { get: () => request } );
12
- Object.defineProperty( this, 'callback', { get: () => callback } );
13
- }
14
-
15
- /**
16
- * @respondWith
17
- */
18
- respondWith( response, ...rest ) {
19
- if ( this.request.diff ) {
20
- if ( 'prevValue' in this && this.prevValue === response ) return;
21
- Object.defineProperty( this, 'prevValue', { value: response, configurable: true } );
22
- }
23
- return this.callback( response, ...rest );
24
- }
25
- };
26
- }
@@ -1,217 +0,0 @@
1
-
2
- /**
3
- * @imports
4
- */
5
- import _HTMLImportsContext from './_HTMLImportsProvider.js';
6
- import { _ } from '../util.js';
7
-
8
- /**
9
- * Creates the HTMLImportElement class.
10
- *
11
- * @param Object config
12
- *
13
- * @return HTMLImportElement
14
- */
15
- export default function( config ) {
16
- const window = this, { realdom } = window.webqit;
17
- const BaseElement = config.import.tagName.includes( '-' ) ? window.HTMLElement : class {};
18
- class HTMLImportElement extends BaseElement {
19
-
20
- /**
21
- * @instance
22
- *
23
- * @param HTMLElement node
24
- *
25
- * @returns
26
- */
27
- static instance( node ) {
28
- if ( config.import.tagName.includes( '-' ) && ( node instanceof this ) ) return node;
29
- return _( node ).get( 'import::instance' ) || new this( node );
30
- }
31
-
32
- /**
33
- * @constructor
34
- */
35
- constructor( ...args ) {
36
- super();
37
- // --------
38
- const el = args[ 0 ] || this;
39
- _( el ).set( 'import::instance', this );
40
- Object.defineProperty( this, 'el', { get: () => el, configurable: false } );
41
-
42
- const priv = {};
43
- Object.defineProperty( this, '#', { get: () => priv, configurable: false } );
44
- priv.slottedElements = new Set;
45
-
46
- priv.setAnchorNode = anchorNode => {
47
- priv.anchorNode = anchorNode;
48
- _( anchorNode ).set( 'anchoredNode@imports', this.el );
49
- };
50
-
51
- priv.importRequest = ( callback, signal = null ) => {
52
- const request = _HTMLImportsContext.createRequest( { detail: priv.moduleRef && !priv.moduleRef.includes( '#' ) ? priv.moduleRef + '#' : priv.moduleRef, live: signal && true, signal } );
53
- ( this.el.isConnected ? this.el.parentNode : priv.anchorNode.parentNode )[ config.CONTEXT_API.api.context ].request( request, response => {
54
- callback( ( response instanceof window.HTMLTemplateElement ? [ ...response.content.children ] : (
55
- Array.isArray( response ) ? response : response && [ response ]
56
- ) ) || [] );
57
- } );
58
- };
59
-
60
- priv.hydrate = ( anchorNode, slottedElements ) => {
61
- // ----------------
62
- priv.moduleRef = ( this.el.getAttribute( config.import.attr.moduleref ) || '' ).trim();
63
- priv.setAnchorNode( anchorNode );
64
- priv.autoRestore( () => {
65
- slottedElements.forEach( slottedElement => {
66
- priv.slottedElements.add( slottedElement );
67
- _( slottedElement ).set( 'slot@imports', this.el );
68
- } );
69
- } );
70
- // ----------------
71
- priv.hydrationImportRequest = new AbortController;
72
- priv.importRequest( fragments => {
73
- if ( priv.originalsRemapped ) { return this.fill( fragments ); }
74
- const identifiersMap = fragments.map( fragment => ( { el: fragment, fragmentDef: fragment.getAttribute( config.template.attr.fragmentdef ) || '', tagName: fragment.tagName, } ) );
75
- slottedElements.forEach( slottedElement => {
76
- const tagName = slottedElement.tagName, fragmentDef = slottedElement.getAttribute( config.template.attr.fragmentdef ) || '';
77
- const originalsMatch = identifiersMap.filter( fragmentIdentifiers => tagName === fragmentIdentifiers.tagName && fragmentDef === fragmentIdentifiers.fragmentDef );
78
- if ( originalsMatch.length !== 1 ) return;
79
- _( slottedElement ).set( 'original@imports', originalsMatch[ 0 ].el );
80
- } );
81
- priv.originalsRemapped = true;
82
- }, priv.hydrationImportRequest.signal );
83
- };
84
-
85
- priv.autoRestore = ( callback = null ) => {
86
- priv.autoRestoreRealtime?.disconnect();
87
- if ( callback ) callback();
88
- if ( !priv.slottedElements.size ) {
89
- priv.anchorNode.replaceWith( this.el );
90
- return;
91
- }
92
- const autoRestoreRealtime = realdom.realtime( window.document ).observe( [ ...priv.slottedElements ], record => {
93
- record.exits.forEach( outgoingNode => {
94
- _( outgoingNode ).delete( 'slot@imports' );
95
- priv.slottedElements.delete( outgoingNode );
96
- } );
97
- if ( !priv.slottedElements.size ) {
98
- autoRestoreRealtime.disconnect();
99
- // At this point, ignore if this is a removal involving the whole parent node
100
- if ( !record.target.isConnected ) return;
101
- priv.anchorNode.replaceWith( this.el );
102
- }
103
- }, { subtree: true, timing: 'sync', generation: 'exits' } );
104
- priv.autoRestoreRealtime = autoRestoreRealtime;
105
- };
106
-
107
- priv.connectedCallback = () => {
108
- // In case this is DOM node relocation or induced reinsertion into the DOM
109
- if ( priv.slottedElements.size ) throw new Error( `Illegal reinsertion into the DOM; import slot is not empty!` );
110
- // Totally initialize this instance?
111
- if ( !priv.anchorNode ) { priv.setAnchorNode( this.createAnchorNode() ); }
112
- if ( priv.moduleRefRealtime ) return;
113
- priv.moduleRefRealtime = realdom.realtime( this.el ).attr( config.import.attr.moduleref, ( record, { signal } ) => {
114
- priv.moduleRef = record.value;
115
- // Below, we ignore first restore from hydration
116
- priv.importRequest( fragments => !priv.hydrationImportRequest && this.fill( fragments ), signal );
117
- }, { live: true, timing: 'sync', lifecycleSignals: true } );
118
- // Must come after
119
- priv.hydrationImportRequest?.abort();
120
- priv.hydrationImportRequest = null;
121
- };
122
-
123
- priv.disconnectedCallback = () => {
124
- priv.hydrationImportRequest?.abort();
125
- priv.hydrationImportRequest = null;
126
- if ( priv.anchorNode.isConnected ) return;
127
- priv.moduleRefRealtime?.disconnect();
128
- priv.moduleRefRealtime = null;
129
- };
130
- }
131
-
132
- /**
133
- * Creates the slot's anchor node.
134
- *
135
- * @return Element
136
- */
137
- createAnchorNode() {
138
- if ( !config.isomorphic ) { return window.document.createTextNode( '' ) }
139
- return window.document.createComment( this.el.outerHTML );
140
- }
141
-
142
- /**
143
- * Fills the slot with slottableElements
144
- *
145
- * @param Iterable slottableElements
146
- *
147
- * @return void
148
- */
149
- fill( slottableElements ) {
150
- if ( Array.isArray( slottableElements ) ) { slottableElements = new Set( slottableElements ) }
151
- this[ '#' ].autoRestore( () => {
152
- this[ '#' ].slottedElements.forEach( slottedElement => {
153
- const slottedElementOriginal = _( slottedElement ).get( 'original@imports' );
154
- // If still available in source, simply leave unchanged
155
- // otherwise remove it from slot... to reflect this change
156
- if ( slottableElements.has( slottedElementOriginal ) ) {
157
- slottableElements.delete( slottedElementOriginal );
158
- } else {
159
- this[ '#' ].slottedElements.delete( slottedElement );
160
- // This removal will not be caught
161
- slottedElement.remove();
162
- }
163
- } );
164
- // Make sure anchor node is what's in place...
165
- // not the import element itslef - but all only when we have slottableElements.size
166
- if ( this.el.isConnected && slottableElements.size ) {
167
- this.el.replaceWith( this[ '#' ].anchorNode );
168
- }
169
- // Insert slottables now
170
- slottableElements.forEach( slottableElement => {
171
- // Clone each slottable element and give it a reference to its original
172
- const slottableElementClone = slottableElement.cloneNode( true );
173
- // The folllowing references must be set before adding to DODM
174
- if ( !slottableElementClone.hasAttribute( config.template.attr.fragmentdef ) ) {
175
- slottableElementClone.toggleAttribute( config.template.attr.fragmentdef, true );
176
- }
177
- _( slottableElementClone ).set( 'original@imports', slottableElement );
178
- _( slottableElementClone ).set( 'slot@imports', this.el );
179
- this[ '#' ].slottedElements.add( slottableElementClone );
180
- this[ '#' ].anchorNode.before( slottableElementClone );
181
- } );
182
- } );
183
- }
184
-
185
- /**
186
- * Empty slot.
187
- *
188
- * @return void
189
- */
190
- empty() { this[ '#' ].slottedElements.forEach( slottedElement => slottedElement.remove() ); }
191
-
192
- /**
193
- * Returns the slot's anchorNode.
194
- *
195
- * @return array
196
- */
197
- get anchorNode() { return this[ '#' ].anchorNode; }
198
-
199
- /**
200
- * Returns the slot's module reference, if any.
201
- *
202
- * @return string
203
- */
204
- get moduleRef() { return this[ '#' ].moduleRef; }
205
-
206
- /**
207
- * Returns the slot's slotted elements.
208
- *
209
- * @return array
210
- */
211
- get slottedElements() { return this[ '#' ].slottedElements; }
212
- }
213
- if ( config.import.tagName.includes( '-' ) ) {
214
- customElements.define( config.import.tagName, HTMLImportElement );
215
- }
216
- return HTMLImportElement;
217
- }
@@ -1,10 +0,0 @@
1
-
2
- /**
3
- * @imports
4
- */
5
- import init from './index.js';
6
-
7
- /**
8
- * @init
9
- */
10
- init.call( window );