@webqit/oohtml 1.10.2 → 1.10.4
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 +21 -0
- package/README.md +400 -396
- package/dist/html-imports.js.map +1 -1
- package/dist/html-modules.js.map +1 -1
- package/dist/main.js.map +1 -1
- package/dist/namespaced-html.js.map +1 -1
- package/dist/state-api.js.map +1 -1
- package/dist/subscript.js.map +1 -1
- package/package.json +76 -76
- package/src/browser-entry.js +9 -9
- package/src/html-imports/browser-entry.js +9 -9
- package/src/html-imports/index.js +557 -557
- package/src/html-modules/browser-entry.js +9 -9
- package/src/html-modules/index.js +384 -384
- package/src/index.js +38 -38
- package/src/namespaced-html/browser-entry.js +9 -9
- package/src/namespaced-html/index.js +143 -143
- package/src/state-api/browser-entry.js +9 -9
- package/src/state-api/index.js +141 -141
- package/src/subscript/Element.js +102 -102
- package/src/subscript/browser-entry.js +9 -9
- package/src/subscript/index.js +69 -69
- package/src/util.js +180 -180
|
@@ -1,557 +1,557 @@
|
|
|
1
|
-
|
|
2
|
-
/**
|
|
3
|
-
* @imports
|
|
4
|
-
*/
|
|
5
|
-
import { _any, _remove, _unique, _difference, _from as _arrFrom } from '@webqit/util/arr/index.js';
|
|
6
|
-
import { _internals } from '@webqit/util/js/index.js';
|
|
7
|
-
import { _each } from '@webqit/util/obj/index.js';
|
|
8
|
-
import domInit from '@webqit/browser-pie/src/dom/index.js';
|
|
9
|
-
import { config, scopeQuery,
|
|
10
|
-
parseScopeReferenceExpr, queryMatchPath
|
|
11
|
-
} from '../util.js';
|
|
12
|
-
|
|
13
|
-
/**
|
|
14
|
-
* ---------------------------
|
|
15
|
-
* HTML Partials
|
|
16
|
-
* ---------------------------
|
|
17
|
-
*/
|
|
18
|
-
|
|
19
|
-
/**
|
|
20
|
-
* @init
|
|
21
|
-
*
|
|
22
|
-
* @param Object config
|
|
23
|
-
*/
|
|
24
|
-
export default function init( _config = {} ) {
|
|
25
|
-
|
|
26
|
-
const WebQit = domInit.call( this );
|
|
27
|
-
if ( _config.onDomReady ) {
|
|
28
|
-
WebQit.DOM.ready( () => {
|
|
29
|
-
init.call( this, { ..._config, onDomReady: false } );
|
|
30
|
-
} );
|
|
31
|
-
return;
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
const window = WebQit.window;
|
|
35
|
-
const document = WebQit.window.document;
|
|
36
|
-
const mutations = WebQit.DOM.mutations;
|
|
37
|
-
|
|
38
|
-
const importInertContexts = [];
|
|
39
|
-
const _meta = config.call(this, {
|
|
40
|
-
element: {
|
|
41
|
-
import: 'import',
|
|
42
|
-
},
|
|
43
|
-
attr: {
|
|
44
|
-
importid: 'name',
|
|
45
|
-
exportsearch: 'exportsearch',
|
|
46
|
-
},
|
|
47
|
-
}, _config.params );
|
|
48
|
-
|
|
49
|
-
_defaultNoInherits.push(_meta.get('attr.importid'), _meta.get('attr.moduleref'));
|
|
50
|
-
const modulerefSelector = '[' + window.CSS.escape(_meta.get('attr.moduleref')) + ']';
|
|
51
|
-
const exportgroupSelector = '[' + window.CSS.escape(_meta.get('attr.exportgroup')) + ']';
|
|
52
|
-
|
|
53
|
-
// ----------------------
|
|
54
|
-
// Capture slot elements
|
|
55
|
-
// ----------------------
|
|
56
|
-
|
|
57
|
-
let prev;
|
|
58
|
-
const Import = class/* extends window.HTMLElement*/ {
|
|
59
|
-
|
|
60
|
-
/*
|
|
61
|
-
static create(el) {
|
|
62
|
-
return el;
|
|
63
|
-
}
|
|
64
|
-
constructor(importEl) {
|
|
65
|
-
super();
|
|
66
|
-
this.el = this;
|
|
67
|
-
}
|
|
68
|
-
*/
|
|
69
|
-
|
|
70
|
-
static create(el) {
|
|
71
|
-
return _internals(this.el, 'oohtml').get('instance') || new Import(el);
|
|
72
|
-
}
|
|
73
|
-
constructor(importEl) {
|
|
74
|
-
this.el = importEl;
|
|
75
|
-
_internals(this.el, 'oohtml').set('instance', this);
|
|
76
|
-
const [ importID, modifiers ] = parseScopeReferenceExpr(importEl.getAttribute(_meta.get('attr.importid')) || 'default');
|
|
77
|
-
_internals(this.el, 'oohtml').set('importID', importID);
|
|
78
|
-
_internals(this.el, 'oohtml').set('importModifiers', modifiers);
|
|
79
|
-
}
|
|
80
|
-
|
|
81
|
-
/**
|
|
82
|
-
* Called by the Slots hydrator.
|
|
83
|
-
*
|
|
84
|
-
* @param Comment anchorNode
|
|
85
|
-
* @param array slottedElements
|
|
86
|
-
* @param Element compositionBlock
|
|
87
|
-
*
|
|
88
|
-
* @return void
|
|
89
|
-
*/
|
|
90
|
-
hydrate(anchorNode, slottedElements, compositionBlock) {
|
|
91
|
-
_internals(this.el, 'oohtml').set('anchorNode', anchorNode);
|
|
92
|
-
_internals(this.el, 'oohtml').set('slottedElements', slottedElements);
|
|
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 { _any, _remove, _unique, _difference, _from as _arrFrom } from '@webqit/util/arr/index.js';
|
|
6
|
+
import { _internals } from '@webqit/util/js/index.js';
|
|
7
|
+
import { _each } from '@webqit/util/obj/index.js';
|
|
8
|
+
import domInit from '@webqit/browser-pie/src/dom/index.js';
|
|
9
|
+
import { config, scopeQuery,
|
|
10
|
+
parseScopeReferenceExpr, queryMatchPath
|
|
11
|
+
} from '../util.js';
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* ---------------------------
|
|
15
|
+
* HTML Partials
|
|
16
|
+
* ---------------------------
|
|
17
|
+
*/
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* @init
|
|
21
|
+
*
|
|
22
|
+
* @param Object config
|
|
23
|
+
*/
|
|
24
|
+
export default function init( _config = {} ) {
|
|
25
|
+
|
|
26
|
+
const WebQit = domInit.call( this );
|
|
27
|
+
if ( _config.onDomReady ) {
|
|
28
|
+
WebQit.DOM.ready( () => {
|
|
29
|
+
init.call( this, { ..._config, onDomReady: false } );
|
|
30
|
+
} );
|
|
31
|
+
return;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
const window = WebQit.window;
|
|
35
|
+
const document = WebQit.window.document;
|
|
36
|
+
const mutations = WebQit.DOM.mutations;
|
|
37
|
+
|
|
38
|
+
const importInertContexts = [];
|
|
39
|
+
const _meta = config.call(this, {
|
|
40
|
+
element: {
|
|
41
|
+
import: 'import',
|
|
42
|
+
},
|
|
43
|
+
attr: {
|
|
44
|
+
importid: 'name',
|
|
45
|
+
exportsearch: 'exportsearch',
|
|
46
|
+
},
|
|
47
|
+
}, _config.params );
|
|
48
|
+
|
|
49
|
+
_defaultNoInherits.push(_meta.get('attr.importid'), _meta.get('attr.moduleref'));
|
|
50
|
+
const modulerefSelector = '[' + window.CSS.escape(_meta.get('attr.moduleref')) + ']';
|
|
51
|
+
const exportgroupSelector = '[' + window.CSS.escape(_meta.get('attr.exportgroup')) + ']';
|
|
52
|
+
|
|
53
|
+
// ----------------------
|
|
54
|
+
// Capture slot elements
|
|
55
|
+
// ----------------------
|
|
56
|
+
|
|
57
|
+
let prev;
|
|
58
|
+
const Import = class/* extends window.HTMLElement*/ {
|
|
59
|
+
|
|
60
|
+
/*
|
|
61
|
+
static create(el) {
|
|
62
|
+
return el;
|
|
63
|
+
}
|
|
64
|
+
constructor(importEl) {
|
|
65
|
+
super();
|
|
66
|
+
this.el = this;
|
|
67
|
+
}
|
|
68
|
+
*/
|
|
69
|
+
|
|
70
|
+
static create(el) {
|
|
71
|
+
return _internals(this.el, 'oohtml').get('instance') || new Import(el);
|
|
72
|
+
}
|
|
73
|
+
constructor(importEl) {
|
|
74
|
+
this.el = importEl;
|
|
75
|
+
_internals(this.el, 'oohtml').set('instance', this);
|
|
76
|
+
const [ importID, modifiers ] = parseScopeReferenceExpr(importEl.getAttribute(_meta.get('attr.importid')) || 'default');
|
|
77
|
+
_internals(this.el, 'oohtml').set('importID', importID);
|
|
78
|
+
_internals(this.el, 'oohtml').set('importModifiers', modifiers);
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
/**
|
|
82
|
+
* Called by the Slots hydrator.
|
|
83
|
+
*
|
|
84
|
+
* @param Comment anchorNode
|
|
85
|
+
* @param array slottedElements
|
|
86
|
+
* @param Element compositionBlock
|
|
87
|
+
*
|
|
88
|
+
* @return void
|
|
89
|
+
*/
|
|
90
|
+
hydrate(anchorNode, slottedElements, compositionBlock) {
|
|
91
|
+
_internals(this.el, 'oohtml').set('anchorNode', anchorNode);
|
|
92
|
+
_internals(this.el, 'oohtml').set('slottedElements', slottedElements);
|
|
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 = [];
|