@webqit/oohtml 1.10.2 → 2.0.0

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 (53) hide show
  1. package/.gitignore +3 -3
  2. package/LICENSE +21 -0
  3. package/README.md +399 -396
  4. package/dist/context-api.js +2 -0
  5. package/dist/context-api.js.map +7 -0
  6. package/dist/html-imports.js +1 -2
  7. package/dist/html-imports.js.map +3 -3
  8. package/dist/html-modules.js +1 -2
  9. package/dist/html-modules.js.map +3 -3
  10. package/dist/main.js +26 -14
  11. package/dist/main.js.map +3 -3
  12. package/dist/namespaced-html.js +1 -2
  13. package/dist/namespaced-html.js.map +3 -3
  14. package/dist/scoped-js.js +27 -0
  15. package/dist/scoped-js.js.map +7 -0
  16. package/dist/state-api.js +1 -2
  17. package/dist/state-api.js.map +3 -3
  18. package/package.json +76 -76
  19. package/src/context-api/HTMLContext.js +158 -0
  20. package/src/context-api/HTMLContextManager.js +77 -0
  21. package/src/context-api/_ContextRequestEvent.js +26 -0
  22. package/src/context-api/index.js +53 -0
  23. package/src/{namespaced-html/browser-entry.js → context-api/targets.browser.js} +9 -9
  24. package/src/html-imports/_HTMLImportElement.js +216 -0
  25. package/src/html-imports/index.js +92 -557
  26. package/src/{browser-entry.js → html-imports/targets.browser.js} +10 -10
  27. package/src/html-modules/HTMLExportsManager.js +191 -0
  28. package/src/html-modules/_HTMLImportsContext.js +114 -0
  29. package/src/html-modules/index.js +133 -384
  30. package/src/{html-imports/browser-entry.js → html-modules/targets.browser.js} +9 -9
  31. package/src/index.js +34 -39
  32. package/src/namespaced-html/index.js +130 -144
  33. package/src/namespaced-html/targets.browser.js +10 -0
  34. package/src/scoped-js/index.js +382 -0
  35. package/src/scoped-js/targets.browser.js +10 -0
  36. package/src/state-api/index.js +55 -142
  37. package/src/state-api/targets.browser.js +10 -0
  38. package/src/{html-modules/browser-entry.js → targets.browser.js} +10 -10
  39. package/src/util.js +20 -180
  40. package/test/imports.test.js +194 -0
  41. package/test/index.js +119 -0
  42. package/test/modules.test.js +198 -0
  43. package/test/namespaced-html.test.js +50 -0
  44. package/test/scoped-js.js +57 -0
  45. package/test/state-api.test.js +34 -0
  46. package/test/test.html +69 -0
  47. package/dist/subscript.js +0 -15
  48. package/dist/subscript.js.map +0 -7
  49. package/src/state-api/browser-entry.js +0 -10
  50. package/src/subscript/Element.js +0 -103
  51. package/src/subscript/browser-entry.js +0 -10
  52. package/src/subscript/index.js +0 -70
  53. package/test/all.test.js +0 -0
@@ -0,0 +1,198 @@
1
+
2
+ /**
3
+ * @imports
4
+ */
5
+ import { expect } from 'chai';
6
+ import Observer from '@webqit/observer';
7
+ import { delay, createDocument, mockRemoteFetch, printDocument, _ } from './index.js';
8
+ const getQueryPath = str => str.split( '/' ).join( '/modules/' ).split( '/' );
9
+
10
+ describe(`HTML Modules`, function() {
11
+
12
+ describe( `APIs...`, function() {
13
+
14
+ it ( `The document object and <template> elements should expose a "modules" property...`, async function() {
15
+
16
+ const head = `
17
+ <template exportid="temp0">
18
+ <p>Hello world Export</p>
19
+ <p>Hellort</p>
20
+ </template>`;
21
+ const body = `
22
+ <template exportid="temp1" scoped>
23
+ <p>Hello world Export</p>
24
+ <p>Hellort</p>
25
+ </template>`;
26
+ const { document } = createDocument( head, body );
27
+ await delay( 200 );
28
+ // -------
29
+ expect( document ).to.have.property( 'modules' );
30
+ expect( document.modules[ 'temp0' ] ).to.have.property( 'modules' );
31
+ expect( document.modules[ 'temp0' ].exportid ).to.eq( 'temp0' );
32
+ // -------
33
+ expect( document.body ).to.have.property( 'modules' );
34
+ expect( document.body.modules[ 'temp1' ] ).to.have.property( 'modules' );
35
+ expect( document.body.modules[ 'temp1' ].exportid ).to.eq( 'temp1' );
36
+ } );
37
+
38
+ it ( `The document object and <template> elements should expose a "modules" property...`, async function() {
39
+
40
+ const body = '', head = `
41
+ <template exportid="temp0">
42
+ <p>Hello world Export</p>
43
+ <p>Hellort</p>
44
+ <template exportid="temp1"></template>
45
+ <template exportid="temp2" inherits="temp1 temp3">
46
+ <p>Hello world Export</p>
47
+ <p>Hellort</p>
48
+ </template>
49
+ </template>`;
50
+ const { document } = createDocument( head, body );
51
+ await delay( 200 );
52
+ // -------
53
+ const temp0 = Observer.deep( document.modules, getQueryPath( 'temp0' ), Observer.get );
54
+ expect( temp0 ).to.have.property( 'modules' );
55
+ expect( temp0.modules[ '#default' ] ).to.have.length( 2 );
56
+ const temp2 = Observer.deep( document.modules, getQueryPath( 'temp0/temp2' ), Observer.get );
57
+ expect( temp2 ).to.have.property( 'modules' );
58
+ // -------
59
+ const temp1Inherited = Observer.deep( document.modules, getQueryPath( 'temp0/temp2/temp1' ), Observer.get );
60
+ expect( temp1Inherited ).to.have.property( 'modules' );
61
+ // -------
62
+ const temp3Observed = [];
63
+ Observer.deep( document.modules, getQueryPath( 'temp0/temp2/temp3' ), Observer.observe, record => {
64
+ temp3Observed.push( record.value );
65
+ } );
66
+ // -------
67
+ const temp3 = document.createElement( 'template' );
68
+ temp3.setAttribute( 'exportid', 'temp3' );
69
+ temp0.content.appendChild( temp3 );
70
+ // -------
71
+ expect( temp3Observed ).to.be.an( 'array' ).with.length( 1 );
72
+ expect( temp3Observed[ 0 ] ).to.have.property( 'modules' );
73
+ // -------
74
+ const temp3Inherited = Observer.deep( document.modules, getQueryPath( 'temp0/temp2/temp3' ), Observer.get );
75
+ expect( temp3Inherited ).to.have.property( 'modules' );
76
+ // -------
77
+ } );
78
+
79
+ } );
80
+
81
+ describe( `Remote...`, function() {
82
+ //return;
83
+ this.timeout( 10000 );
84
+
85
+ it( `Add remote lazy module, with a nested remote lazy module, then resolve.`, async function() {
86
+
87
+ const head = ``, body = ``;
88
+ const window = createDocument( head, body, window => {
89
+ // Define remote responses
90
+ const temp0 = `
91
+ <template exportid="temp1" src="/temp1.html" loading="lazy"></template>`;
92
+ const temp1 = `
93
+ <template exportid="temp2" src="/temp2.html"></template>`;
94
+ const temp2 = `
95
+ <template exportid="temp3"></template>
96
+ <p>Hello world Export</p>
97
+ <p>Hellort</p>`;
98
+ const timeout = 1000;
99
+ mockRemoteFetch( window, { '/temp0.html': temp0, '/temp1.html': temp1, '/temp2.html': temp2 }, timeout );
100
+ } ), document = window.document;
101
+ // -------
102
+ // Add a remote module
103
+ const templateEl = document.createElement( 'template' );
104
+ templateEl.setAttribute( 'exportid', 'temp0' );
105
+ templateEl.setAttribute( 'loading', 'lazy' );
106
+ templateEl.setAttribute( 'src', '/temp0.html' );
107
+ document.head.appendChild( templateEl );
108
+ // -------
109
+ // Add the import element to with a view to waiting for the remote module
110
+ const temp0 = Observer.deep( document.modules, getQueryPath( 'temp0' ), Observer.get );
111
+ expect( temp0 ).to.have.property( 'modules' );
112
+ await delay( 2100 );
113
+ // temp1 shouldn't have been automatically loaded still
114
+ const hasTemp1 = Observer.deep( document.modules, getQueryPath( 'temp0/temp1' ), Observer.has );
115
+ expect( hasTemp1 ).to.be.false;
116
+ // Try access temp1 to trigger loading and await
117
+ const _temp1 = await Observer.deep( document.modules, getQueryPath( 'temp0/temp1' ), Observer.get );
118
+ expect( _temp1 ).to.have.property( 'modules' );
119
+ // -------
120
+ // Receive updates
121
+ const temp3Observed = [];
122
+ Observer.deep( document.modules, getQueryPath( 'temp0/temp1/temp2/temp3' ), Observer.observe, ( record, lifecycle ) => {
123
+ temp3Observed.push( record.value );
124
+ } );
125
+ await delay( 2100 );
126
+ // -------
127
+ // temp2 should be loaded by now
128
+ expect( temp3Observed ).to.be.an( 'array' ).with.length( 1 );
129
+ expect( temp3Observed[ 0 ] ).to.have.property( 'modules' );
130
+ expect( temp3Observed[ 0 ].getAttribute( 'exportid' ) ).to.eq( 'temp3' );
131
+ } );
132
+ } );
133
+
134
+ describe( `Context...`, function() {
135
+ //return;
136
+ this.timeout( 10000 );
137
+
138
+ it( `Use the context API to fire a scoped-request that is imitially resolved from the document and then from a scoped context.`, async function() {
139
+
140
+ const head = `
141
+ <template exportid="temp0">
142
+ <template exportid="temp-head1">
143
+ <p>Hello world Export</p>
144
+ <p>Hellort</p>
145
+ </template>
146
+ </template>`;
147
+ const body = `
148
+ <div></div>`;
149
+ const window = createDocument( head, body ), document = window.document;
150
+ // -------
151
+ const addScopedModules = () => {
152
+ const templateEl = document.createElement( 'template' );
153
+ templateEl.setAttribute( 'exportid', 'temp0' );
154
+ templateEl.toggleAttribute( 'scoped', true );
155
+ const scoped = document.body.appendChild( templateEl );
156
+ document.body.setAttribute( 'importscontext', '/' );
157
+ return scoped;
158
+ };
159
+ // -------
160
+ const contextRequest = ( el, params, callback ) => {
161
+ const request = { type: 'HTMLModules', live: true, ...params };
162
+ const event = new document.context.ContextRequestEvent( request, callback, {
163
+ bubbles: true,
164
+ } );
165
+ return el.dispatchEvent( event );
166
+ };
167
+ // -------
168
+ await 'For some reason, the <template> element in the head needs to show up in the document modulesObj';
169
+ const modulesObjs = [], div = document.querySelector( 'div' );
170
+ // -------
171
+ contextRequest( div, { detail: '/temp0', diff: false }, response => {
172
+ modulesObjs.push( response );
173
+ } );
174
+ expect( modulesObjs ).to.have.length( 1 );
175
+ expect( modulesObjs[ 0 ] ).to.have.property( 'scoped', false );
176
+ // -------
177
+ const scoped = addScopedModules();
178
+ expect( modulesObjs ).to.have.length( 3 );
179
+ expect( modulesObjs[ 1 ] ).to.have.property( 'scoped', true );
180
+ expect( modulesObjs[ 2 ] ).to.have.property( 'scoped', true );
181
+ // -------
182
+ scoped.remove();
183
+ expect( modulesObjs ).to.have.length( 4 );
184
+ expect( modulesObjs[ 3 ] ).to.have.property( 'scoped', false );
185
+ // -------
186
+ document.body.appendChild( scoped );
187
+ expect( modulesObjs ).to.have.length( 5 );
188
+ expect( modulesObjs[ 4 ] ).to.have.property( 'scoped', true );
189
+ // -------
190
+ const unscoped = document.modules.temp0;
191
+ unscoped.remove();
192
+ document.head.appendChild( unscoped );
193
+ document.body.remove();
194
+ expect( modulesObjs ).to.have.length( 5 );
195
+ } );
196
+ } );
197
+
198
+ } );
@@ -0,0 +1,50 @@
1
+
2
+ /**
3
+ * @imports
4
+ */
5
+ import { expect } from 'chai';
6
+ import { createDocument } from './index.js';
7
+ import Observer from '@webqit/observer';
8
+
9
+ describe(`Namespaced HTML`, function() {
10
+
11
+ describe( `Basic...`, function() {
12
+
13
+ const head = `
14
+ <meta name="oohtml" content="attr.id=data-id" />`;
15
+ const body = `
16
+ <div data-id="main" namespace>
17
+ <div data-id="child"></div>
18
+ </div>`;
19
+ const { document } = createDocument( head, body );
20
+
21
+ it ( `The document object and elements should expose a "namespace" property each...`, async function() {
22
+ expect( document ).to.have.property( 'namespace' );
23
+ expect( document.namespace.main ).to.have.property( 'namespace' ).that.have.property( 'child' );
24
+ } );
25
+
26
+ it ( `Namespace objects should be observable...`, async function() {
27
+ let idReceived = null;
28
+ Observer.observe( document.namespace, records => {
29
+ idReceived = records[ 0 ].key;
30
+ } );
31
+ const item = document.createElement( 'div' );
32
+ item.setAttribute( 'data-id', 'some-id' );
33
+ document.body.appendChild( item );
34
+ expect( idReceived ).to.eq( 'some-id' );
35
+ } );
36
+
37
+ it ( `Namespace attributes should be applicable dynamically...`, async function() {
38
+ expect( Object.keys( document.namespace ).length ).to.eq( 2 );
39
+ document.body.toggleAttribute( 'namespace', true );
40
+ expect( Object.keys( document.namespace ).length ).to.eq( 0 );
41
+ expect( Object.keys( document.body.namespace ).length ).to.eq( 2 );
42
+ document.body.toggleAttribute( 'namespace', false );
43
+ expect( Object.keys( document.namespace ).length ).to.eq( 2 );
44
+ expect( Object.keys( document.body.namespace ).length ).to.eq( 0 );
45
+ } );
46
+
47
+ } );
48
+
49
+ } );
50
+
@@ -0,0 +1,57 @@
1
+
2
+ /**
3
+ * @imports
4
+ */
5
+ import { expect } from 'chai';
6
+ import { delay, createDocumentForScopedJS, Observer } from './index.js';
7
+
8
+ describe(`Test: Scoped JS`, function() {
9
+
10
+ describe(`Scripts`, function() {
11
+
12
+ it(`Should do basic observe`, async function() {
13
+ const head = '', body = `
14
+ <h1>Hello World!</h1>
15
+ <script>
16
+ let ul = document.createElement( 'ul' );
17
+ let li = document.createElement( 'li' );
18
+ ul.appendChild(li);
19
+ document.body.appendChild(ul);
20
+ </script>
21
+ <div><p>Hello World!</p></div>`;
22
+
23
+ const window = createDocumentForScopedJS( head, body, ( window, dom ) => {
24
+ // Observer is bound before document is parsed.
25
+ // Elements are going to show up as they are being parsed.
26
+ dom.realtime( window.document ).observe( 'h1,p,li', record => {
27
+ window.testRecords.push( record.entrants[ 0 ] );
28
+ }, { subtree: true } );
29
+ }, { runScripts: 'dangerously' } );
30
+
31
+ await delay( 60 );
32
+ expect( window.testRecords ).to.have.length( 3 );
33
+ });
34
+
35
+
36
+ });
37
+
38
+ describe(`Scripts`, function() {
39
+
40
+ it(`Should do basic observe`, async function() {
41
+ const head = '', body = `
42
+ <h1>Hello World!</h1>
43
+ <script scoped contract>
44
+ testRecords.push( this );
45
+ </script>`;
46
+
47
+ const window = createDocumentForScopedJS( head, body );
48
+
49
+ await delay( 60 );
50
+ expect( window.testRecords ).to.have.length( 1 );
51
+ expect( window.testRecords[ 0 ] ).to.eql( window.document.body );
52
+ //console.log('::::::::::::', window.document.documentElement.outerHTML);
53
+ });
54
+
55
+ });
56
+
57
+ });
@@ -0,0 +1,34 @@
1
+
2
+ /**
3
+ * @imports
4
+ */
5
+ import { expect } from 'chai';
6
+ import { createDocument } from './index.js';
7
+ import Observer from '@webqit/observer';
8
+
9
+ describe(`State API`, function() {
10
+
11
+ describe( `Basic...`, function() {
12
+
13
+ const head = ``;
14
+ const body = ``;
15
+ const { document } = createDocument( head, body );
16
+
17
+ it ( `The document object and elements should expose a "state" property each...`, async function() {
18
+ expect( document ).to.have.property( 'state' );
19
+ expect( document.body ).to.have.property( 'state' );
20
+ } );
21
+
22
+ it ( `State objects should be observable...`, async function() {
23
+ let idReceived = null;
24
+ Observer.observe( document.state, records => {
25
+ idReceived = records[ 0 ].key;
26
+ } );
27
+ document.state.someKey = 'someValue';
28
+ expect( idReceived ).to.eq( 'someKey' );
29
+ } );
30
+
31
+ } );
32
+
33
+ } );
34
+
package/test/test.html ADDED
@@ -0,0 +1,69 @@
1
+ <!DOCTYPE html>
2
+ <html>
3
+ <head>
4
+ <meta name="subscript-compiler-url" content="http://127.0.0.1:5500/subscript/dist/compiler.js" />
5
+ <script src="/oohtml/dist/main.js"></script>
6
+ <script>
7
+ window.extVar = 'External variable initial value.';
8
+ </script>
9
+ <template exportid="temp0">
10
+ <input exportid="input" />
11
+ <template exportid="temp1">
12
+ <textarea exportid="input"></textarea>
13
+ <template exportid="temp2">
14
+ <select exportid="input"></select>
15
+ </template>
16
+ <template exportid="temp2b" inherits="#input"></template>
17
+ <template exportid="temp2c">
18
+ <textarea exportid="input"></textarea>
19
+ </template>
20
+ </template>
21
+ </template>
22
+ </head>
23
+ <body>
24
+
25
+ <div importscontext="temp0/temp1">
26
+ <textarea exportid="input"></textarea>
27
+ <!--<import module="#input"></import>-->
28
+ </div>
29
+
30
+ <div id="diiiiv">
31
+ DIV
32
+ <script scoped contract>
33
+ console.log( 'Execution context: ' + this.tagName );
34
+ console.log( extVar );
35
+ this.addEventListener( 'remove', e => {
36
+ console.log('removing...');
37
+ } );
38
+ setTimeout( () => {
39
+ this.remove();
40
+ }, 10000 );
41
+ </script>
42
+ </div>
43
+
44
+ <div id="diiiiv2">
45
+ DIV
46
+ <script scoped contract>
47
+ console.log( 'Execution context: ' + this.tagName );
48
+ console.log( extVar );
49
+ this.addEventListener( 'beforeremove', e => {
50
+ console.log('removing...');
51
+ } );
52
+ setTimeout( () => {
53
+ this.remove();
54
+ }, 10000 );
55
+ </script>
56
+ </div>
57
+
58
+ <script>
59
+ const diiiiv = document.querySelector( '#diiiiv' );
60
+ setTimeout( () => {
61
+ extVar = 'External variable updated value!';
62
+ diiiiv.scripts.forEach( script => {
63
+ script.rerender( [ 'extVar' ] );
64
+ } );
65
+ }, 5000 );
66
+ </script>
67
+
68
+ </body>
69
+ </html>