@webqit/oohtml 1.10.3 → 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.
- package/.gitignore +3 -3
- package/LICENSE +20 -20
- package/README.md +399 -396
- package/dist/context-api.js +2 -0
- package/dist/context-api.js.map +7 -0
- package/dist/html-imports.js +1 -2
- package/dist/html-imports.js.map +3 -3
- package/dist/html-modules.js +1 -2
- package/dist/html-modules.js.map +3 -3
- package/dist/main.js +26 -14
- package/dist/main.js.map +3 -3
- package/dist/namespaced-html.js +1 -2
- package/dist/namespaced-html.js.map +3 -3
- package/dist/scoped-js.js +27 -0
- package/dist/scoped-js.js.map +7 -0
- package/dist/state-api.js +1 -2
- package/dist/state-api.js.map +3 -3
- package/package.json +76 -76
- package/src/context-api/HTMLContext.js +158 -0
- package/src/context-api/HTMLContextManager.js +77 -0
- package/src/context-api/_ContextRequestEvent.js +26 -0
- package/src/context-api/index.js +53 -0
- package/src/{namespaced-html/browser-entry.js → context-api/targets.browser.js} +9 -9
- package/src/html-imports/_HTMLImportElement.js +216 -0
- package/src/html-imports/index.js +92 -557
- package/src/{browser-entry.js → html-imports/targets.browser.js} +10 -10
- package/src/html-modules/HTMLExportsManager.js +191 -0
- package/src/html-modules/_HTMLImportsContext.js +114 -0
- package/src/html-modules/index.js +133 -384
- package/src/{html-imports/browser-entry.js → html-modules/targets.browser.js} +9 -9
- package/src/index.js +34 -39
- package/src/namespaced-html/index.js +130 -144
- package/src/namespaced-html/targets.browser.js +10 -0
- package/src/scoped-js/index.js +382 -0
- package/src/scoped-js/targets.browser.js +10 -0
- package/src/state-api/index.js +55 -142
- package/src/state-api/targets.browser.js +10 -0
- package/src/{html-modules/browser-entry.js → targets.browser.js} +10 -10
- package/src/util.js +20 -180
- package/test/imports.test.js +194 -0
- package/test/index.js +119 -0
- package/test/modules.test.js +198 -0
- package/test/namespaced-html.test.js +50 -0
- package/test/scoped-js.js +57 -0
- package/test/state-api.test.js +34 -0
- package/test/test.html +69 -0
- package/dist/subscript.js +0 -15
- package/dist/subscript.js.map +0 -7
- package/src/state-api/browser-entry.js +0 -10
- package/src/subscript/Element.js +0 -103
- package/src/subscript/browser-entry.js +0 -10
- package/src/subscript/index.js +0 -70
- package/test/all.test.js +0 -0
|
@@ -1,557 +1,92 @@
|
|
|
1
|
-
|
|
2
|
-
/**
|
|
3
|
-
* @imports
|
|
4
|
-
*/
|
|
5
|
-
import
|
|
6
|
-
import
|
|
7
|
-
import {
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
*
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
_internals(this.el, 'oohtml').set('compositionBlock', compositionBlock);
|
|
94
|
-
this._bindSlotted(slottedElements);
|
|
95
|
-
this._connectToCompositionBlock();
|
|
96
|
-
}
|
|
97
|
-
|
|
98
|
-
/**
|
|
99
|
-
* This triggers self-resolution
|
|
100
|
-
*
|
|
101
|
-
* @return void
|
|
102
|
-
*/
|
|
103
|
-
connectedCallback() {
|
|
104
|
-
if (!_internals(this.el, 'oohtml').has('anchorNode')) {
|
|
105
|
-
_internals(this.el, 'oohtml').set('anchorNode', _meta.get('isomorphic')
|
|
106
|
-
? document.createComment(this.el.outerHTML)
|
|
107
|
-
: document.createTextNode(''));
|
|
108
|
-
_internals(this.el, 'oohtml').set('compositionBlock', !this.el.hasAttribute(_meta.get('attr.moduleref'))
|
|
109
|
-
? this.el.parentNode.closest(modulerefSelector) : (
|
|
110
|
-
this.el.getAttribute(_meta.get('attr.moduleref')).trim().startsWith('~') ? this.el.parentNode.closest(exportgroupSelector) : null
|
|
111
|
-
));
|
|
112
|
-
this._connectToCompositionBlock();
|
|
113
|
-
}
|
|
114
|
-
WebQit.DOM.ready.call(WebQit, () => {
|
|
115
|
-
this.resolve('connected');
|
|
116
|
-
});
|
|
117
|
-
}
|
|
118
|
-
|
|
119
|
-
/**
|
|
120
|
-
* Connects the instance to the compositionBlock.
|
|
121
|
-
*/
|
|
122
|
-
_connectToCompositionBlock() {
|
|
123
|
-
if (this.compositionBlock) {
|
|
124
|
-
// Now after the update slot ID
|
|
125
|
-
_internals(this.compositionBlock, 'oohtml', 'imports').set(this.importID, this.el);
|
|
126
|
-
}
|
|
127
|
-
}
|
|
128
|
-
|
|
129
|
-
/**
|
|
130
|
-
* Bind a slotted element.
|
|
131
|
-
*
|
|
132
|
-
* @param array exports
|
|
133
|
-
*
|
|
134
|
-
* @return void
|
|
135
|
-
*/
|
|
136
|
-
_bindSlotted(exports) {
|
|
137
|
-
exports.forEach(_export => {
|
|
138
|
-
_export.importReference = this.el;
|
|
139
|
-
});
|
|
140
|
-
_internals(this.el, 'oohtml').set('slottedObserver', mutations.onRemoved(exports, (removed, state, isTransient, addedState, removedState) => {
|
|
141
|
-
if (removedState && removedState.size === exports.length) {
|
|
142
|
-
_internals(this.el, 'oohtml').get('slottedObserver').disconnect();
|
|
143
|
-
}
|
|
144
|
-
removed.forEach(remd => {
|
|
145
|
-
// Let's ensure this wasn't slotted againe
|
|
146
|
-
if (!remd.parentNode) {
|
|
147
|
-
_remove(this.slottedElements, remd);
|
|
148
|
-
}
|
|
149
|
-
// if the slotted hasnt been slotted somewhere
|
|
150
|
-
if (remd.importReference === this.el) {
|
|
151
|
-
delete remd.importReference;
|
|
152
|
-
}
|
|
153
|
-
});
|
|
154
|
-
// If this was the last of the s,ottable in the same family of IDs,
|
|
155
|
-
// we should restore the original slot
|
|
156
|
-
if (!this.slottedElements.length) {
|
|
157
|
-
// Must be assigned bu now
|
|
158
|
-
// for it to be removed in the first place
|
|
159
|
-
if (this.anchorNode.isConnected) {
|
|
160
|
-
this.anchorNode.replaceWith(this.el);
|
|
161
|
-
}
|
|
162
|
-
}
|
|
163
|
-
}, {maintainCallState: true, ignoreTransients: true}));
|
|
164
|
-
}
|
|
165
|
-
|
|
166
|
-
/**
|
|
167
|
-
* Resolves the slot
|
|
168
|
-
*/
|
|
169
|
-
resolve(reason = null) {
|
|
170
|
-
if (_any(importInertContexts, inertContext => this.el.closest(inertContext))) {
|
|
171
|
-
return;
|
|
172
|
-
}
|
|
173
|
-
var getExports = (contexts, moduleref, exportsearch) => {
|
|
174
|
-
var importId = this.importID,
|
|
175
|
-
modifiers = this.importModifiers,
|
|
176
|
-
[ searchA, searchB ] = (('search' in modifiers) || exportsearch !== null) ? ('search' in modifiers ? modifiers.search : exportsearch).split('-').filter(a => a).map(a => parseInt(a || 0)).concat([0, 1000]) : [0, 0];
|
|
177
|
-
const aggrExports = modules => modules.reduce((_exports, _module) => _exports.concat(_internals(_module, 'oohtml', 'exports').get(importId) || []), []);
|
|
178
|
-
return scopeQuery(contexts, moduleref, function(host, prop) {
|
|
179
|
-
var collection = _internals(host, 'oohtml', 'templates');
|
|
180
|
-
if (arguments.length === 1) return collection;
|
|
181
|
-
if (prop.startsWith(':')) return _internals(host, 'oohtml', 'exports').get(prop.substr(1));
|
|
182
|
-
return collection.get(prop);
|
|
183
|
-
}, function(_modules, level, isRewinding) {
|
|
184
|
-
var exportsAggr = aggrExports(_modules);
|
|
185
|
-
if (!exportsAggr.length && level > searchA && searchB) {
|
|
186
|
-
searchB --;
|
|
187
|
-
return -1;
|
|
188
|
-
}
|
|
189
|
-
return exportsAggr;
|
|
190
|
-
});
|
|
191
|
-
};
|
|
192
|
-
// -----------------
|
|
193
|
-
// Global import or scoped slot?
|
|
194
|
-
var templateSource, exports;
|
|
195
|
-
if (this.el.hasAttribute(_meta.get('attr.moduleref'))) {
|
|
196
|
-
// Did we previously had a compositionBlock?
|
|
197
|
-
// Let's remove ourself
|
|
198
|
-
if (this.compositionBlock && _internals(this.compositionBlock, 'oohtml', 'imports').get(this.importID) === this.el) {
|
|
199
|
-
_internals(this.compositionBlock, 'oohtml', 'imports').delete(this.importID);
|
|
200
|
-
}
|
|
201
|
-
templateSource = this.el;
|
|
202
|
-
} else {
|
|
203
|
-
if (!this.compositionBlock) {
|
|
204
|
-
console.warn('Scoped slots must be found within template contexts. [' + this.importID + ']', this.el);
|
|
205
|
-
return;
|
|
206
|
-
}
|
|
207
|
-
templateSource = this.compositionBlock;
|
|
208
|
-
}
|
|
209
|
-
var moduleref = templateSource.getAttribute(_meta.get('attr.moduleref')).trim();
|
|
210
|
-
var exportsearch = this.el.getAttribute(_meta.get('attr.exportsearch'));
|
|
211
|
-
if (templateSource && (exports = getExports([moduleref.startsWith('~') ? this.compositionBlock : document], moduleref, exportsearch)).length) {
|
|
212
|
-
if (_difference(exports, _internals(this.el, 'oohtml').get('originalSlottedElements') || []).length) {
|
|
213
|
-
_internals(this.el, 'oohtml').set('originalSlottedElements', exports);
|
|
214
|
-
this.fill(exports);
|
|
215
|
-
}
|
|
216
|
-
} else {
|
|
217
|
-
_internals(this.el, 'oohtml').set('originalSlottedElements', null);
|
|
218
|
-
this.empty();
|
|
219
|
-
}
|
|
220
|
-
}
|
|
221
|
-
|
|
222
|
-
/**
|
|
223
|
-
* Fill slot with exports.
|
|
224
|
-
*
|
|
225
|
-
* @param array|Element exports
|
|
226
|
-
*
|
|
227
|
-
* @return void
|
|
228
|
-
*/
|
|
229
|
-
fill(exports) {
|
|
230
|
-
exports = _arrFrom(exports, false/* castObject */).map(_export => _export.cloneNode(true));
|
|
231
|
-
// ---------------------
|
|
232
|
-
// Discard previous slotted elements
|
|
233
|
-
// But this intentional removal should not trigger slot restoration
|
|
234
|
-
this.empty(true/* silently */);
|
|
235
|
-
if (this.el.isConnected) {
|
|
236
|
-
this.el.replaceWith(this.anchorNode);
|
|
237
|
-
}
|
|
238
|
-
// ---------------------
|
|
239
|
-
// Slot-in the corresponding exports from template
|
|
240
|
-
exports.forEach(_export => {
|
|
241
|
-
// ---------------------
|
|
242
|
-
// Implement the slot?
|
|
243
|
-
_internals(_export, 'oohtml', 'templates').set('~', this.el);
|
|
244
|
-
// Inherit attributes from the slot element before replacement
|
|
245
|
-
mergeAttributes(_export, this.el);
|
|
246
|
-
// ---------------------
|
|
247
|
-
if (!_export.getAttribute(_meta.get('attr.exportgroup'))) {
|
|
248
|
-
_export.setAttribute(_meta.get('attr.exportgroup'), this.importID);
|
|
249
|
-
}
|
|
250
|
-
// Place slottable
|
|
251
|
-
this.anchorNode.before(_export);
|
|
252
|
-
});
|
|
253
|
-
this._bindSlotted(exports);
|
|
254
|
-
// ---------------------
|
|
255
|
-
// Updatate records
|
|
256
|
-
this.slottedElements.push(...exports);
|
|
257
|
-
}
|
|
258
|
-
|
|
259
|
-
/**
|
|
260
|
-
* Empty slot.
|
|
261
|
-
*
|
|
262
|
-
* @param bool sliently
|
|
263
|
-
*
|
|
264
|
-
* @return void
|
|
265
|
-
*/
|
|
266
|
-
empty(silently = false) {
|
|
267
|
-
if (this.slottedElements) {
|
|
268
|
-
var slottedElements = this.slottedElements;
|
|
269
|
-
if (silently && _internals(this.el, 'oohtml').has('slottedObserver')) {
|
|
270
|
-
_internals(this.el, 'oohtml').get('slottedObserver').disconnect();
|
|
271
|
-
slottedElements = this.slottedElements.splice(0);
|
|
272
|
-
}
|
|
273
|
-
slottedElements.forEach(slottedElement => slottedElement.remove());
|
|
274
|
-
}
|
|
275
|
-
}
|
|
276
|
-
|
|
277
|
-
/**
|
|
278
|
-
* Returns the slot's name.
|
|
279
|
-
*
|
|
280
|
-
* @return string
|
|
281
|
-
*/
|
|
282
|
-
get importID() {
|
|
283
|
-
return _internals(this.el, 'oohtml').get('importID');
|
|
284
|
-
}
|
|
285
|
-
|
|
286
|
-
/**
|
|
287
|
-
* Returns the slot's import Modifiers.
|
|
288
|
-
*
|
|
289
|
-
* @return string
|
|
290
|
-
*/
|
|
291
|
-
get importModifiers() {
|
|
292
|
-
return _internals(this.el, 'oohtml').get('importModifiers');
|
|
293
|
-
}
|
|
294
|
-
|
|
295
|
-
/**
|
|
296
|
-
* Returns the slot's anchorNode.
|
|
297
|
-
*
|
|
298
|
-
* @return array
|
|
299
|
-
*/
|
|
300
|
-
get anchorNode() {
|
|
301
|
-
return _internals(this.el, 'oohtml').get('anchorNode');
|
|
302
|
-
}
|
|
303
|
-
|
|
304
|
-
/**
|
|
305
|
-
* Returns the slot's compositionBlock, if any.
|
|
306
|
-
*
|
|
307
|
-
* @return array
|
|
308
|
-
*/
|
|
309
|
-
get compositionBlock() {
|
|
310
|
-
return _internals(this.el, 'oohtml').get('compositionBlock');
|
|
311
|
-
}
|
|
312
|
-
|
|
313
|
-
/**
|
|
314
|
-
* Returns the slot's slotted elements.
|
|
315
|
-
*
|
|
316
|
-
* @return array
|
|
317
|
-
*/
|
|
318
|
-
get slottedElements() {
|
|
319
|
-
if (!_internals(this.el, 'oohtml').has('slottedElements')) {
|
|
320
|
-
_internals(this.el, 'oohtml').set('slottedElements', []);
|
|
321
|
-
}
|
|
322
|
-
return _internals(this.el, 'oohtml').get('slottedElements');
|
|
323
|
-
}
|
|
324
|
-
|
|
325
|
-
/**
|
|
326
|
-
* Returns the slot's implementable exports
|
|
327
|
-
*
|
|
328
|
-
* @return array
|
|
329
|
-
*/
|
|
330
|
-
get exports() {
|
|
331
|
-
return _internals(this.el, 'oohtml').get('exports');
|
|
332
|
-
}
|
|
333
|
-
|
|
334
|
-
/**
|
|
335
|
-
* The attributes we want to observe.
|
|
336
|
-
*
|
|
337
|
-
* @return array
|
|
338
|
-
*/
|
|
339
|
-
static get observedAttributes() {
|
|
340
|
-
return [_meta.get('attr.importid')];
|
|
341
|
-
}
|
|
342
|
-
};
|
|
343
|
-
|
|
344
|
-
// ----------------------
|
|
345
|
-
// Capture import elements
|
|
346
|
-
// ----------------------
|
|
347
|
-
|
|
348
|
-
mutations.onPresent(_meta.get('element.import'), el => {
|
|
349
|
-
var importElInstance = Import.create(el);
|
|
350
|
-
importElInstance.connectedCallback();
|
|
351
|
-
});
|
|
352
|
-
/**
|
|
353
|
-
window.customElements.define(_meta.get('element.import'), Import);
|
|
354
|
-
*/
|
|
355
|
-
|
|
356
|
-
// ----------------------
|
|
357
|
-
// Progressive resolution
|
|
358
|
-
// ----------------------
|
|
359
|
-
|
|
360
|
-
const resolveSlots = (el, exportName, reason = null) => {
|
|
361
|
-
const shouldResolve = (importElInstance, importName) => {
|
|
362
|
-
return !exportName || importName === exportName || (
|
|
363
|
-
exportName === true && ((importElInstance.importModifiers && ('search' in importElInstance.importModifiers)) || importElInstance.el.getAttribute(_meta.get('attr.exportsearch')))
|
|
364
|
-
);
|
|
365
|
-
};
|
|
366
|
-
if (el.matches(_meta.get('element.import'))) {
|
|
367
|
-
var importElInstance = Import.create(el);
|
|
368
|
-
if (shouldResolve(importElInstance, importElInstance.importID)) {
|
|
369
|
-
importElInstance.resolve(reason);
|
|
370
|
-
}
|
|
371
|
-
} else {
|
|
372
|
-
_internals(el, 'oohtml', 'imports').forEach((importEl, name) => {
|
|
373
|
-
var importElInstance = Import.create(importEl);
|
|
374
|
-
if (shouldResolve(importElInstance, name)) {
|
|
375
|
-
importElInstance.resolve(`Resolution scope: ${reason}`);
|
|
376
|
-
}
|
|
377
|
-
});
|
|
378
|
-
}
|
|
379
|
-
};
|
|
380
|
-
|
|
381
|
-
mutations.onPresent(modulerefSelector, el => {
|
|
382
|
-
if (_any(importInertContexts, inertContext => el.closest(inertContext))) {
|
|
383
|
-
return;
|
|
384
|
-
}
|
|
385
|
-
// Imports resolve by themselves
|
|
386
|
-
// But...
|
|
387
|
-
// We resolve them again when reference to template changes
|
|
388
|
-
mutations.onAttrChange(el, mr => {
|
|
389
|
-
if (mr[0].target.getAttribute(mr[0].attributeName) !== mr[0].oldValue) {
|
|
390
|
-
resolveSlots(el, null, `Attr-Change: ${mr[0].attributeName}`);
|
|
391
|
-
}
|
|
392
|
-
}, [_meta.get('attr.moduleref'), _meta.get('attr.importid')]);
|
|
393
|
-
});
|
|
394
|
-
|
|
395
|
-
document.addEventListener('templatemutation', e => {
|
|
396
|
-
// Resolve slots when the referenced template changes
|
|
397
|
-
if (!e.detail.path) {
|
|
398
|
-
return;
|
|
399
|
-
}
|
|
400
|
-
_arrFrom(document.querySelectorAll('[' + window.CSS.escape(_meta.get('attr.moduleref')) + ']')).forEach(el => {
|
|
401
|
-
if (queryMatchPath(el.getAttribute(_meta.get('attr.moduleref')), e.detail.path)) {
|
|
402
|
-
resolveSlots(el, true/* resolve imports with search() */, `'templatemutation' event: ${e.detail.path}, search()`);
|
|
403
|
-
e.detail.addedExports.concat(e.detail.removedExports).forEach(exportGroup => {
|
|
404
|
-
resolveSlots(el, exportGroup.name, `'templatemutation' event: ${e.detail.path}, ${exportGroup.name}`);
|
|
405
|
-
});
|
|
406
|
-
}
|
|
407
|
-
});
|
|
408
|
-
});
|
|
409
|
-
|
|
410
|
-
// ----------------------
|
|
411
|
-
// Restore slots from snapshots
|
|
412
|
-
// ----------------------
|
|
413
|
-
|
|
414
|
-
const hydrateSlots = () => {
|
|
415
|
-
_arrFrom(document.querySelectorAll(exportgroupSelector)).forEach(_export => {
|
|
416
|
-
// Scan
|
|
417
|
-
if (_internals(_export.parentNode, 'oohtml').get('importsCan')) return;
|
|
418
|
-
// hydrateSlots() might be running AFTER certain <slots> have resolved
|
|
419
|
-
// and _export might be a just-resolved node
|
|
420
|
-
if (_export.importReference) return;
|
|
421
|
-
var slottedElements = [];
|
|
422
|
-
_export.parentNode.childNodes.forEach(node => {
|
|
423
|
-
var nodeValue;
|
|
424
|
-
if (node.nodeType === 1/** ELEMENT_NODE */ && node.matches(exportgroupSelector)) {
|
|
425
|
-
slottedElements.push(node);
|
|
426
|
-
} else if (node.nodeType === 8/** COMMENT_NODE */ && (nodeValue = node.nodeValue.trim())
|
|
427
|
-
&& nodeValue.startsWith('<' + _meta.get('element.import'))
|
|
428
|
-
&& nodeValue.endsWith('</' + _meta.get('element.import') + '>')) {
|
|
429
|
-
var importEl, reviver = document.createElement('div');
|
|
430
|
-
reviver.innerHTML = nodeValue;
|
|
431
|
-
if ((importEl = reviver.firstChild).matches(_meta.get('element.import'))) {
|
|
432
|
-
// Belongs to a composition block?
|
|
433
|
-
var compositionBlock = !importEl.hasAttribute(_meta.get('attr.moduleref'))
|
|
434
|
-
? node.parentNode.closest(modulerefSelector) : (
|
|
435
|
-
importEl.getAttribute(_meta.get('attr.moduleref')).trim().startsWith('~') ? node.parentNode.closest(exportgroupSelector) : null
|
|
436
|
-
)
|
|
437
|
-
var importElInstance = Import.create(importEl);
|
|
438
|
-
importElInstance.hydrate(node, slottedElements, compositionBlock);
|
|
439
|
-
// Empty basket
|
|
440
|
-
slottedElements = [];
|
|
441
|
-
}
|
|
442
|
-
}
|
|
443
|
-
});
|
|
444
|
-
// Scanning is once for every parent
|
|
445
|
-
_internals(_export.parentNode, 'oohtml').set('importsCan', true);
|
|
446
|
-
});
|
|
447
|
-
};
|
|
448
|
-
|
|
449
|
-
// ----------------------
|
|
450
|
-
// Hydrate
|
|
451
|
-
// ----------------------
|
|
452
|
-
|
|
453
|
-
WebQit.DOM.ready.call(WebQit, () => {
|
|
454
|
-
if (_meta.get('isomorphic')) {
|
|
455
|
-
hydrateSlots();
|
|
456
|
-
}
|
|
457
|
-
});
|
|
458
|
-
|
|
459
|
-
};
|
|
460
|
-
|
|
461
|
-
/**
|
|
462
|
-
* Imports exports from from sourceEl into el.
|
|
463
|
-
*
|
|
464
|
-
* @param Element exportEl
|
|
465
|
-
* @param Element superExportEl
|
|
466
|
-
* @param array noinherit
|
|
467
|
-
*
|
|
468
|
-
* @return Element
|
|
469
|
-
*/
|
|
470
|
-
export function mergePartials(exportEl, superExportEl, noinherit = []) {
|
|
471
|
-
if (!superExportEl.exportsSlottables) {
|
|
472
|
-
return exportEl;
|
|
473
|
-
}
|
|
474
|
-
_each(superExportEl.exportsSlottables, (slotId, slottable) => {
|
|
475
|
-
if (exportEl.exportsSlottables && exportEl.exportsSlottables[slotId]) {
|
|
476
|
-
// Simply inherit attributes from the search slottable
|
|
477
|
-
// The export may however define a no-inherit directive for all its slottables
|
|
478
|
-
var _noinherit = noinherit.concat((exportEl.getAttribute('noinherit') || '').split(' ').map(val => val.trim()));
|
|
479
|
-
this.mergeAttributes(exportEl.exportsSlottables[slotId], slottable, _noinherit, false/*prioritize*/);
|
|
480
|
-
} else {
|
|
481
|
-
// Copy new slottables
|
|
482
|
-
exportEl.append(slottable.clone(true));
|
|
483
|
-
}
|
|
484
|
-
});
|
|
485
|
-
return exportEl;
|
|
486
|
-
};
|
|
487
|
-
|
|
488
|
-
/**
|
|
489
|
-
* Imports attributes from sourceEl into el.
|
|
490
|
-
*
|
|
491
|
-
* @param Element el
|
|
492
|
-
* @param Element sourceEl
|
|
493
|
-
* @param array noinherit
|
|
494
|
-
* @param bool prioritize
|
|
495
|
-
*
|
|
496
|
-
* @return Element
|
|
497
|
-
*/
|
|
498
|
-
export function mergeAttributes(el, sourceEl, noinherit = [], prioritize = true) {
|
|
499
|
-
// ----------------------------
|
|
500
|
-
// Norecompose directive
|
|
501
|
-
// ----------------------------
|
|
502
|
-
noinherit = noinherit.concat(_defaultNoInherits);
|
|
503
|
-
if (el.hasAttribute('noinherit')) {
|
|
504
|
-
noinherit = noinherit.concat((el.getAttribute('noinherit') || '*').split(' ').map(val => val.trim()));
|
|
505
|
-
}
|
|
506
|
-
// ----------------------------
|
|
507
|
-
// Merge list attributes...
|
|
508
|
-
// ----------------------------
|
|
509
|
-
var defaultListAttrs = _defaultListAttrs.concat(['role', 'class']);
|
|
510
|
-
_unique(defaultListAttrs).forEach(type => {
|
|
511
|
-
var b_attr, a_attr;
|
|
512
|
-
if (!noinherit.includes(type) && !noinherit.includes('*') && (b_attr = sourceEl.getAttribute(type))) {
|
|
513
|
-
if (a_attr = el.getAttribute(type)) {
|
|
514
|
-
var jointList = !prioritize ? [b_attr, a_attr] : [a_attr, b_attr];
|
|
515
|
-
} else {
|
|
516
|
-
var jointList = [b_attr];
|
|
517
|
-
}
|
|
518
|
-
el.setAttribute(type, _unique(jointList.join(' ').split(' ').map(r => r.trim())).join(' '));
|
|
519
|
-
noinherit.push(type);
|
|
520
|
-
}
|
|
521
|
-
});
|
|
522
|
-
// ----------------------------
|
|
523
|
-
// Merge key/val attributes...
|
|
524
|
-
// ----------------------------
|
|
525
|
-
_unique(_defaultKeyValAttrs.concat('style')).forEach(type => {
|
|
526
|
-
var b_attr, a_attr;
|
|
527
|
-
if (!noinherit.includes(type) && !noinherit.includes('*') && (b_attr = sourceEl.getAttribute(type))) {
|
|
528
|
-
if (a_attr = el.getAttribute(type)) {
|
|
529
|
-
var jointDefs = !prioritize ? [b_attr, a_attr] : [a_attr, b_attr];
|
|
530
|
-
if (!jointDefs[0].trim().endsWith(';')) {
|
|
531
|
-
jointDefs[0] = jointDefs[0] + ';';
|
|
532
|
-
}
|
|
533
|
-
} else {
|
|
534
|
-
var jointDefs = [b_attr];
|
|
535
|
-
}
|
|
536
|
-
el.setAttribute(type, jointDefs.join(' '));
|
|
537
|
-
noinherit.push(type);
|
|
538
|
-
}
|
|
539
|
-
});
|
|
540
|
-
// ----------------------------
|
|
541
|
-
// Port all other attributes...
|
|
542
|
-
// ----------------------------
|
|
543
|
-
if (!noinherit.includes('*')) {
|
|
544
|
-
for (var i = 0; i < sourceEl.attributes.length; i ++) {
|
|
545
|
-
var attr = sourceEl.attributes[i];
|
|
546
|
-
if (!noinherit.includes(attr.name)
|
|
547
|
-
&& (!el.hasAttribute(attr.name) || prioritize)) {
|
|
548
|
-
el.setAttribute(attr.name, attr.value);
|
|
549
|
-
}
|
|
550
|
-
}
|
|
551
|
-
}
|
|
552
|
-
return el;
|
|
553
|
-
};
|
|
554
|
-
|
|
555
|
-
const _defaultNoInherits = ['nocompose'],
|
|
556
|
-
_defaultKeyValAttrs = [],
|
|
557
|
-
_defaultListAttrs = [];
|
|
1
|
+
|
|
2
|
+
/**
|
|
3
|
+
* @imports
|
|
4
|
+
*/
|
|
5
|
+
import wqDom from '@webqit/dom';
|
|
6
|
+
import _HTMLImportElement from './_HTMLImportElement.js';
|
|
7
|
+
import { _ } from '../util.js';
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* Initializes HTML Modules.
|
|
11
|
+
*
|
|
12
|
+
* @param $params Object
|
|
13
|
+
*
|
|
14
|
+
* @return Void
|
|
15
|
+
*/
|
|
16
|
+
export default function init( $params = { }) {
|
|
17
|
+
const window = this, dom = wqDom.call( window );
|
|
18
|
+
// -------
|
|
19
|
+
const params = dom.meta( 'oohtml' ).copyWithDefaults( $params, {
|
|
20
|
+
import: { tagName: 'import', attr: { moduleref: 'module' }, },
|
|
21
|
+
export: { attr: { exportid: 'exportid' }, },
|
|
22
|
+
isomorphic: true,
|
|
23
|
+
} );
|
|
24
|
+
params.slottedElementsSelector = `[${ window.CSS.escape( params.export.attr.exportid ) }]`;
|
|
25
|
+
params.HTMLImportElement = _HTMLImportElement.call( this, params );
|
|
26
|
+
// -------
|
|
27
|
+
dom.ready( () => hydration.call( this, params ) );
|
|
28
|
+
realtime.call( this, params );
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* Performs realtime capture of elements and their attributes
|
|
33
|
+
* and their module query results; then resolves the respective import elements.
|
|
34
|
+
*
|
|
35
|
+
* @param Object params
|
|
36
|
+
*
|
|
37
|
+
* @return Void
|
|
38
|
+
*/
|
|
39
|
+
function realtime( params ) {
|
|
40
|
+
const window = this, { dom } = window.wq;
|
|
41
|
+
dom.realtime( window.document ).observe( params.import.tagName, record => {
|
|
42
|
+
record.entrants.forEach( node => handleRealtime( node, true, record ) );
|
|
43
|
+
record.exits.forEach( node => handleRealtime( node, false, record ) );
|
|
44
|
+
}, { subtree: true, timing: 'sync' } );
|
|
45
|
+
function handleRealtime( entry, connectedState, record ) {
|
|
46
|
+
const elInstance = params.HTMLImportElement.instance( entry );
|
|
47
|
+
if ( connectedState ) { elInstance[ '#' ].connectedCallback(); }
|
|
48
|
+
else { elInstance[ '#' ].disconnectedCallback(); }
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
/**
|
|
53
|
+
* Performs hydration for server-slotted elements.
|
|
54
|
+
*
|
|
55
|
+
* @param Object params
|
|
56
|
+
*
|
|
57
|
+
* @return Void
|
|
58
|
+
*/
|
|
59
|
+
function hydration( params ) {
|
|
60
|
+
const window = this;
|
|
61
|
+
function scan( context ) {
|
|
62
|
+
const slottedElements = new Set;
|
|
63
|
+
context.childNodes.forEach( node => {
|
|
64
|
+
if ( node.nodeType === 1/** ELEMENT_NODE */ ) {
|
|
65
|
+
if ( !node.matches( params.slottedElementsSelector ) ) return;
|
|
66
|
+
if ( _( node ).get( 'slot@imports' ) ) return;
|
|
67
|
+
slottedElements.add( node );
|
|
68
|
+
} else if ( node.nodeType === 8/** COMMENT_NODE */ ) {
|
|
69
|
+
const nodeValue = node.nodeValue.trim();
|
|
70
|
+
if ( !nodeValue.startsWith( '<' + params.import.tagName ) ) return;
|
|
71
|
+
if ( !nodeValue.endsWith( '</' + params.import.tagName + '>' ) ) return;
|
|
72
|
+
const reviver = window.document.createElement( 'div' );
|
|
73
|
+
reviver.innerHTML = nodeValue;
|
|
74
|
+
const importEl = reviver.firstChild;
|
|
75
|
+
if ( !importEl.matches( params.import.tagName ) ) return;
|
|
76
|
+
params.HTMLImportElement.instance( importEl )[ '#' ].hydrate(
|
|
77
|
+
node/* the comment node */, slottedElements
|
|
78
|
+
);
|
|
79
|
+
slottedElements.clear();
|
|
80
|
+
}
|
|
81
|
+
} );
|
|
82
|
+
}
|
|
83
|
+
Array.from( window.document.querySelectorAll( params.slottedElementsSelector ) ).forEach( slottedElement => {
|
|
84
|
+
// hydration() might be running AFTER certain <slots> have resolved
|
|
85
|
+
// and slottedElement might be a just-resolved node
|
|
86
|
+
if ( _( slottedElement ).get( 'slot@imports' ) ) return;
|
|
87
|
+
if ( _( slottedElement.parentNode ).get( 'alreadyscanned@imports' ) ) return;
|
|
88
|
+
scan( slottedElement.parentNode );
|
|
89
|
+
// Scanning is once for every parent
|
|
90
|
+
_( slottedElement.parentNode ).set( 'alreadyscanned@imports', true );
|
|
91
|
+
} );
|
|
92
|
+
}
|
|
@@ -1,10 +1,10 @@
|
|
|
1
|
-
|
|
2
|
-
/**
|
|
3
|
-
* @imports
|
|
4
|
-
*/
|
|
5
|
-
import init from './index.js';
|
|
6
|
-
|
|
7
|
-
/**
|
|
8
|
-
* @init
|
|
9
|
-
*/
|
|
10
|
-
init.call(window);
|
|
1
|
+
|
|
2
|
+
/**
|
|
3
|
+
* @imports
|
|
4
|
+
*/
|
|
5
|
+
import init from './index.js';
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* @init
|
|
9
|
+
*/
|
|
10
|
+
init.call( window );
|