@microsoft/webui-framework 0.0.18 → 0.0.19
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/README.md +75 -60
- package/dist/decorators.d.ts +1 -0
- package/dist/decorators.js +3 -0
- package/dist/element/diff.d.ts +3 -1
- package/dist/element/diff.js +197 -90
- package/dist/element/markers.js +13 -5
- package/dist/element/types.d.ts +18 -10
- package/dist/element/types.js +3 -0
- package/dist/element.js +3 -2
- package/dist/hydration-mismatch.js +3 -2
- package/dist/index.js +1 -1
- package/dist/static-host.js +16 -8
- package/dist/template-element.d.ts +20 -9
- package/dist/template-element.js +345 -205
- package/dist/template-events.js +1 -1
- package/dist/template-roots.d.ts +0 -1
- package/dist/template-roots.js +0 -11
- package/dist/template-types.d.ts +7 -1
- package/dist/template.d.ts +1 -0
- package/package.json +2 -2
package/dist/template-element.js
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import { getTemplate } from './template.js';
|
|
2
2
|
import { hydrationStart, hydrationEnd } from './lifecycle.js';
|
|
3
|
-
import { syncRepeat, dotWalk } from './element/diff.js';
|
|
3
|
+
import { createRepeatKeyState, seedHydratedRepeatKeys, syncRepeat, dotWalk, } from './element/diff.js';
|
|
4
4
|
import { collectItemMarkers, nextElement, findByOrdinal, MARKER_COND_START, MARKER_COND_END, MARKER_REPEAT_START, } from './element/markers.js';
|
|
5
5
|
import { injectModuleStyle, } from './element/styles.js';
|
|
6
|
-
import { ATTR_KIND_BOOLEAN, ATTR_KIND_COMPLEX, ATTR_KIND_TEMPLATE, } from './element/types.js';
|
|
6
|
+
import { ATTR_KIND_BOOLEAN, ATTR_KIND_COMPLEX, ATTR_KIND_TEMPLATE, hasNativeLiveProperty, } from './element/types.js';
|
|
7
7
|
import { templateHasRoot, templateRootForAttribute } from './template-roots.js';
|
|
8
8
|
const DEV = typeof __WEBUI_DEV__ === 'undefined' || __WEBUI_DEV__;
|
|
9
9
|
const templateCache = new WeakMap();
|
|
@@ -36,27 +36,6 @@ const EMPTY_ARR = [];
|
|
|
36
36
|
const EMPTY_SET = Object.freeze(new Set());
|
|
37
37
|
const WEBUI_SET_STATE_KEY = Symbol.for('microsoft.webui.setStateKey');
|
|
38
38
|
const templateMetaByCtor = new WeakMap();
|
|
39
|
-
let domReadyQueue = null;
|
|
40
|
-
function runWhenDomReady(callback) {
|
|
41
|
-
if (document.readyState !== 'loading') {
|
|
42
|
-
callback();
|
|
43
|
-
return;
|
|
44
|
-
}
|
|
45
|
-
if (domReadyQueue) {
|
|
46
|
-
domReadyQueue.push(callback);
|
|
47
|
-
return;
|
|
48
|
-
}
|
|
49
|
-
domReadyQueue = [callback];
|
|
50
|
-
document.addEventListener('DOMContentLoaded', flushDomReadyQueue, { once: true });
|
|
51
|
-
}
|
|
52
|
-
function flushDomReadyQueue() {
|
|
53
|
-
const queue = domReadyQueue;
|
|
54
|
-
domReadyQueue = null;
|
|
55
|
-
if (!queue)
|
|
56
|
-
return;
|
|
57
|
-
for (let i = 0; i < queue.length; i++)
|
|
58
|
-
queue[i]();
|
|
59
|
-
}
|
|
60
39
|
function childNodesArray(parent) {
|
|
61
40
|
const children = parent.childNodes;
|
|
62
41
|
const len = children.length;
|
|
@@ -128,6 +107,9 @@ export class TemplateElement extends HTMLElement {
|
|
|
128
107
|
this.$root = null;
|
|
129
108
|
this.$ready = false;
|
|
130
109
|
this.$hydrated = false;
|
|
110
|
+
this.$deferredSSR = false;
|
|
111
|
+
this.$activatingDeferredSSR = false;
|
|
112
|
+
this.$hasUnknownScopes = false;
|
|
131
113
|
this.$templateState = null;
|
|
132
114
|
this.$dirtyPaths = null;
|
|
133
115
|
this.$pendingFlush = false;
|
|
@@ -135,7 +117,13 @@ export class TemplateElement extends HTMLElement {
|
|
|
135
117
|
this.$resolver = (p, s) => this.$resolveValue(p, s);
|
|
136
118
|
}
|
|
137
119
|
[WEBUI_SET_STATE_KEY](key, value) {
|
|
138
|
-
|
|
120
|
+
const wasDeferred = this.$deferredSSR;
|
|
121
|
+
this.$beforeExternalStateWrite();
|
|
122
|
+
const owned = this.$setStateKey(key, value);
|
|
123
|
+
this.$afterExternalStateWrite(owned);
|
|
124
|
+
if (owned && wasDeferred && !this.$deferredSSR)
|
|
125
|
+
this.$update(key);
|
|
126
|
+
return owned;
|
|
139
127
|
}
|
|
140
128
|
static define(tagName) {
|
|
141
129
|
installTemplateObservedAttributes(this, tagName);
|
|
@@ -143,6 +131,10 @@ export class TemplateElement extends HTMLElement {
|
|
|
143
131
|
}
|
|
144
132
|
connectedCallback() {
|
|
145
133
|
const tag = this.tagName.toLowerCase();
|
|
134
|
+
if (this.$deferredSSR) {
|
|
135
|
+
this.$ready = true;
|
|
136
|
+
return;
|
|
137
|
+
}
|
|
146
138
|
if (this.$hydrated && this.$root) {
|
|
147
139
|
hydrationStart();
|
|
148
140
|
this.$ready = true;
|
|
@@ -157,17 +149,11 @@ export class TemplateElement extends HTMLElement {
|
|
|
157
149
|
return;
|
|
158
150
|
}
|
|
159
151
|
this.$meta = meta;
|
|
160
|
-
|
|
161
|
-
runWhenDomReady(() => this.$mount(meta));
|
|
162
|
-
}
|
|
163
|
-
else {
|
|
164
|
-
this.$mount(meta);
|
|
165
|
-
}
|
|
152
|
+
this.$mount(meta, false);
|
|
166
153
|
}
|
|
167
|
-
$mount(meta) {
|
|
154
|
+
$mount(meta, forceSSR) {
|
|
168
155
|
if (this.$hydrated)
|
|
169
156
|
return;
|
|
170
|
-
hydrationStart();
|
|
171
157
|
const hasShadow = !!this.shadowRoot;
|
|
172
158
|
const wantShadow = hasShadow || !!meta.sd;
|
|
173
159
|
let root;
|
|
@@ -189,10 +175,18 @@ export class TemplateElement extends HTMLElement {
|
|
|
189
175
|
root = this;
|
|
190
176
|
isSSR = false;
|
|
191
177
|
}
|
|
178
|
+
if (isSSR && !forceSSR && this.$shouldDeferSSRHydration()) {
|
|
179
|
+
this.$meta = meta;
|
|
180
|
+
this.$deferredSSR = true;
|
|
181
|
+
this.$ready = true;
|
|
182
|
+
return;
|
|
183
|
+
}
|
|
184
|
+
hydrationStart();
|
|
192
185
|
if (meta.sa)
|
|
193
186
|
injectModuleStyle(meta.sa, this.shadowRoot);
|
|
194
187
|
if (isSSR) {
|
|
195
|
-
this.$
|
|
188
|
+
if (this.$shouldApplySSRBootstrapState())
|
|
189
|
+
this.$applySSRState();
|
|
196
190
|
this.$root = this.$hydrate(root, meta, getTemplateDom(meta));
|
|
197
191
|
}
|
|
198
192
|
else {
|
|
@@ -211,9 +205,10 @@ export class TemplateElement extends HTMLElement {
|
|
|
211
205
|
this.$updateInstance(this.$root);
|
|
212
206
|
if (this.$root.repeats.length !== 0 || this.$root.conds.length !== 0) {
|
|
213
207
|
this.$root.nodes = childNodesArray(clientRoot);
|
|
214
|
-
this.$
|
|
208
|
+
this.$replaceInstanceContainer(this.$root, clientRoot, root);
|
|
215
209
|
}
|
|
216
210
|
this.$appendStagedChildren(root, clientRoot);
|
|
211
|
+
this.$root.container = root;
|
|
217
212
|
}
|
|
218
213
|
hydrationEnd();
|
|
219
214
|
}
|
|
@@ -226,9 +221,13 @@ export class TemplateElement extends HTMLElement {
|
|
|
226
221
|
}
|
|
227
222
|
}
|
|
228
223
|
$destroy() {
|
|
229
|
-
if (!this.$root)
|
|
224
|
+
if (!this.$root) {
|
|
225
|
+
this.$deferredSSR = false;
|
|
226
|
+
this.$ready = false;
|
|
227
|
+
this.$hasUnknownScopes = false;
|
|
230
228
|
return;
|
|
231
|
-
|
|
229
|
+
}
|
|
230
|
+
this.$disposeInstance(this.$root, false);
|
|
232
231
|
this.$root = null;
|
|
233
232
|
this.$pathIndex = undefined;
|
|
234
233
|
this.$wildcardBindings = undefined;
|
|
@@ -236,55 +235,87 @@ export class TemplateElement extends HTMLElement {
|
|
|
236
235
|
this.$pendingFlush = false;
|
|
237
236
|
this.$preReadyWrites = null;
|
|
238
237
|
this.$ready = false;
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
238
|
+
this.$hasUnknownScopes = false;
|
|
239
|
+
}
|
|
240
|
+
$clearRepeatBinding(repeat) {
|
|
241
|
+
repeat.instances.length = 0;
|
|
242
|
+
repeat.container = null;
|
|
243
|
+
repeat.start = null;
|
|
244
|
+
repeat.end = null;
|
|
245
|
+
const state = repeat.keyState;
|
|
246
|
+
if (state) {
|
|
247
|
+
state.keys.length = 0;
|
|
248
|
+
state.nextKeys.length = 0;
|
|
249
|
+
state.map.clear();
|
|
250
|
+
}
|
|
251
|
+
}
|
|
252
|
+
$clearInstance(instance) {
|
|
253
|
+
instance.scope = undefined;
|
|
254
|
+
instance.parent = undefined;
|
|
255
|
+
instance.container = null;
|
|
255
256
|
instance.nodes.length = 0;
|
|
256
257
|
instance.texts.length = 0;
|
|
257
258
|
instance.attrs.length = 0;
|
|
258
259
|
instance.conds.length = 0;
|
|
259
260
|
instance.repeats.length = 0;
|
|
260
261
|
}
|
|
261
|
-
$teardownInstanceCleanups(instance) {
|
|
262
|
-
const cleanups = instance.cleanups;
|
|
263
|
-
if (!cleanups)
|
|
264
|
-
return;
|
|
265
|
-
for (let i = 0; i < cleanups.length; i++)
|
|
266
|
-
cleanups[i]();
|
|
267
|
-
cleanups.length = 0;
|
|
268
|
-
}
|
|
269
262
|
attributeChangedCallback(name, oldValue, newValue) {
|
|
270
263
|
if (Object.is(oldValue, newValue))
|
|
271
264
|
return;
|
|
265
|
+
const wasDeferred = this.$deferredSSR;
|
|
266
|
+
this.$beforeExternalStateWrite();
|
|
272
267
|
const property = this.$templateRootForAttribute(name);
|
|
268
|
+
let changed = false;
|
|
273
269
|
if (property && this.$usesTemplateState(property)) {
|
|
274
|
-
this.$setTemplateState(property, newValue);
|
|
270
|
+
changed = this.$setTemplateState(property, newValue);
|
|
275
271
|
}
|
|
272
|
+
this.$afterExternalStateWrite(changed);
|
|
273
|
+
if (changed && property && wasDeferred && !this.$deferredSSR)
|
|
274
|
+
this.$update(property);
|
|
276
275
|
}
|
|
277
276
|
setState(state) {
|
|
277
|
+
const wasDeferred = this.$deferredSSR;
|
|
278
|
+
this.$beforeExternalStateWrite();
|
|
278
279
|
const keys = Object.keys(state);
|
|
280
|
+
let owned = false;
|
|
279
281
|
for (let i = 0; i < keys.length; i++) {
|
|
280
282
|
const key = keys[i];
|
|
281
|
-
this.$setStateKey(key, state[key]);
|
|
283
|
+
owned = this.$setStateKey(key, state[key]) || owned;
|
|
284
|
+
}
|
|
285
|
+
this.$afterExternalStateWrite(owned);
|
|
286
|
+
if (owned && wasDeferred && !this.$deferredSSR) {
|
|
287
|
+
for (let i = 0; i < keys.length; i++)
|
|
288
|
+
this.$update(keys[i]);
|
|
282
289
|
}
|
|
283
290
|
this.$flushUpdates();
|
|
284
291
|
}
|
|
285
292
|
$observableNames() {
|
|
286
293
|
return EMPTY_SET;
|
|
287
294
|
}
|
|
295
|
+
$beforeExternalStateWrite() {
|
|
296
|
+
}
|
|
297
|
+
$afterExternalStateWrite(_applied) {
|
|
298
|
+
}
|
|
299
|
+
$shouldDeferSSRHydration() {
|
|
300
|
+
return false;
|
|
301
|
+
}
|
|
302
|
+
$activateDeferredSSR() {
|
|
303
|
+
if (!this.$deferredSSR || !this.$meta)
|
|
304
|
+
return;
|
|
305
|
+
this.$deferredSSR = false;
|
|
306
|
+
this.$ready = false;
|
|
307
|
+
this.$preReadyWrites = null;
|
|
308
|
+
this.$activatingDeferredSSR = true;
|
|
309
|
+
try {
|
|
310
|
+
this.$mount(this.$meta, true);
|
|
311
|
+
}
|
|
312
|
+
finally {
|
|
313
|
+
this.$activatingDeferredSSR = false;
|
|
314
|
+
}
|
|
315
|
+
}
|
|
316
|
+
$shouldApplySSRBootstrapState() {
|
|
317
|
+
return true;
|
|
318
|
+
}
|
|
288
319
|
$shouldApplySSRState(_key) {
|
|
289
320
|
return true;
|
|
290
321
|
}
|
|
@@ -294,9 +325,11 @@ export class TemplateElement extends HTMLElement {
|
|
|
294
325
|
return true;
|
|
295
326
|
}
|
|
296
327
|
$setTemplateState(key, value) {
|
|
297
|
-
|
|
328
|
+
const changed = this.$writeTemplateState(key, value);
|
|
329
|
+
if (changed) {
|
|
298
330
|
this.$update(key);
|
|
299
331
|
}
|
|
332
|
+
return changed;
|
|
300
333
|
}
|
|
301
334
|
$writeTemplateState(key, value) {
|
|
302
335
|
if (!this.$templateState) {
|
|
@@ -382,24 +415,34 @@ export class TemplateElement extends HTMLElement {
|
|
|
382
415
|
this.$flush();
|
|
383
416
|
}
|
|
384
417
|
$flush() {
|
|
385
|
-
if (!this.$ready || !this.$root
|
|
418
|
+
if (!this.$ready || !this.$root) {
|
|
386
419
|
this.$dirtyPaths = null;
|
|
387
420
|
this.$pendingFlush = false;
|
|
388
421
|
return;
|
|
389
422
|
}
|
|
423
|
+
if (!this.$pathIndex)
|
|
424
|
+
this.$buildPathIndex();
|
|
425
|
+
if (!this.$pathIndex)
|
|
426
|
+
return;
|
|
390
427
|
while (this.$dirtyPaths && this.$dirtyPaths.size > 0) {
|
|
391
428
|
const dirty = this.$dirtyPaths;
|
|
392
429
|
this.$dirtyPaths = null;
|
|
393
430
|
for (const path of dirty) {
|
|
394
|
-
|
|
431
|
+
if (!this.$pathIndex)
|
|
432
|
+
this.$buildPathIndex();
|
|
433
|
+
const entry = this.$pathIndex?.get(path);
|
|
395
434
|
if (entry) {
|
|
396
435
|
this.$updateBindings(entry.texts, entry.attrs, entry.conds, entry.repeats);
|
|
397
436
|
}
|
|
398
437
|
}
|
|
438
|
+
if (!this.$pathIndex)
|
|
439
|
+
this.$buildPathIndex();
|
|
399
440
|
if (this.$wildcardBindings) {
|
|
400
441
|
const wc = this.$wildcardBindings;
|
|
401
442
|
this.$updateBindings(wc.texts, wc.attrs, wc.conds, wc.repeats);
|
|
402
443
|
}
|
|
444
|
+
if (!this.$pathIndex)
|
|
445
|
+
this.$buildPathIndex();
|
|
403
446
|
}
|
|
404
447
|
this.$pendingFlush = false;
|
|
405
448
|
}
|
|
@@ -501,34 +544,34 @@ export class TemplateElement extends HTMLElement {
|
|
|
501
544
|
}
|
|
502
545
|
root.appendChild(fragment);
|
|
503
546
|
}
|
|
504
|
-
$
|
|
505
|
-
if (
|
|
506
|
-
return;
|
|
507
|
-
if (instance.repeats.length === 0 && instance.conds.length === 0)
|
|
547
|
+
$replaceInstanceContainer(instance, previous, next) {
|
|
548
|
+
if (previous === next)
|
|
508
549
|
return;
|
|
509
550
|
const stack = [instance];
|
|
510
551
|
while (stack.length > 0) {
|
|
511
552
|
const current = stack.pop();
|
|
512
553
|
if (!current)
|
|
513
554
|
continue;
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
if (repeat.container === stagingRoot)
|
|
517
|
-
repeat.container = null;
|
|
518
|
-
for (let j = 0; j < repeat.instances.length; j++) {
|
|
519
|
-
stack.push(repeat.instances[j].instance);
|
|
520
|
-
}
|
|
521
|
-
}
|
|
555
|
+
if (current.container === previous)
|
|
556
|
+
current.container = next;
|
|
522
557
|
for (let i = 0; i < current.conds.length; i++) {
|
|
523
558
|
const child = current.conds[i].instance;
|
|
524
559
|
if (child)
|
|
525
560
|
stack.push(child);
|
|
526
561
|
}
|
|
562
|
+
for (let i = 0; i < current.repeats.length; i++) {
|
|
563
|
+
const repeat = current.repeats[i];
|
|
564
|
+
if (repeat.container === previous)
|
|
565
|
+
repeat.container = next;
|
|
566
|
+
const children = repeat.instances;
|
|
567
|
+
for (let j = 0; j < children.length; j++)
|
|
568
|
+
stack.push(children[j]);
|
|
569
|
+
}
|
|
527
570
|
}
|
|
528
571
|
}
|
|
529
572
|
$wire(root, meta, scope) {
|
|
530
573
|
const instance = {
|
|
531
|
-
scope, nodes: childNodesArray(root),
|
|
574
|
+
scope, container: root, nodes: childNodesArray(root),
|
|
532
575
|
texts: [], attrs: [], conds: [], repeats: [],
|
|
533
576
|
};
|
|
534
577
|
const textRefs = new Array(meta.tx?.length ?? 0);
|
|
@@ -563,12 +606,19 @@ export class TemplateElement extends HTMLElement {
|
|
|
563
606
|
let repRefCount = 0;
|
|
564
607
|
if (meta.r) {
|
|
565
608
|
for (let i = 0; i < meta.r.length; i++) {
|
|
566
|
-
const [collection, itemVar, blockIndex, slotMeta] = meta.r[i];
|
|
609
|
+
const [collection, itemVar, blockIndex, slotMeta, keyPath] = meta.r[i];
|
|
567
610
|
const [parentPath, beforeIndex] = slotMeta;
|
|
568
611
|
const parent = parentPath.length > 0 ? this.$resolve(root, parentPath) : root;
|
|
569
612
|
if (!parent || (parent.nodeType !== 1 && parent.nodeType !== 11))
|
|
570
613
|
continue;
|
|
571
|
-
repRefs[repRefCount] = {
|
|
614
|
+
repRefs[repRefCount] = {
|
|
615
|
+
parent,
|
|
616
|
+
ref: parent.childNodes[beforeIndex] || null,
|
|
617
|
+
collection,
|
|
618
|
+
itemVar,
|
|
619
|
+
blockIndex,
|
|
620
|
+
keyPath,
|
|
621
|
+
};
|
|
572
622
|
repRefCount += 1;
|
|
573
623
|
}
|
|
574
624
|
}
|
|
@@ -594,19 +644,28 @@ export class TemplateElement extends HTMLElement {
|
|
|
594
644
|
const c = condRefs[i];
|
|
595
645
|
const anchor = document.createComment('');
|
|
596
646
|
c.parent.insertBefore(anchor, c.ref);
|
|
597
|
-
instance.conds.push({
|
|
647
|
+
instance.conds.push({
|
|
648
|
+
condition: c.condition,
|
|
649
|
+
blockIndex: c.blockIndex,
|
|
650
|
+
anchor,
|
|
651
|
+
scope,
|
|
652
|
+
owner: instance,
|
|
653
|
+
instance: null,
|
|
654
|
+
});
|
|
598
655
|
}
|
|
599
656
|
for (let i = 0; i < repRefCount; i++) {
|
|
600
657
|
const r = repRefs[i];
|
|
601
658
|
const anchor = document.createComment('');
|
|
602
659
|
r.parent.insertBefore(anchor, r.ref);
|
|
603
|
-
const
|
|
604
|
-
instance.repeats.push({
|
|
660
|
+
const binding = {
|
|
605
661
|
markerId: i, collection: r.collection, itemVar: r.itemVar, blockIndex: r.blockIndex,
|
|
606
662
|
container: r.parent, start: anchor, end: null,
|
|
607
|
-
scope, owner: instance, instances: [],
|
|
608
|
-
|
|
609
|
-
|
|
663
|
+
scope, owner: instance, instances: [],
|
|
664
|
+
};
|
|
665
|
+
if (r.keyPath !== undefined) {
|
|
666
|
+
binding.keyState = createRepeatKeyState(r.keyPath);
|
|
667
|
+
}
|
|
668
|
+
instance.repeats.push(binding);
|
|
610
669
|
}
|
|
611
670
|
for (let i = 0; i < instance.conds.length; i++)
|
|
612
671
|
this.$toggleCond(instance.conds[i]);
|
|
@@ -615,6 +674,7 @@ export class TemplateElement extends HTMLElement {
|
|
|
615
674
|
$hydrate(ssrRoot, meta, tplDom, scope, pathStart = 0) {
|
|
616
675
|
const instance = {
|
|
617
676
|
scope,
|
|
677
|
+
container: (pathStart > 0 ? ssrRoot.parentNode : ssrRoot),
|
|
618
678
|
nodes: pathStart > 0 ? [ssrRoot] : childNodesArray(ssrRoot),
|
|
619
679
|
texts: [], attrs: [], conds: [], repeats: [],
|
|
620
680
|
};
|
|
@@ -657,7 +717,6 @@ export class TemplateElement extends HTMLElement {
|
|
|
657
717
|
const [parentPath] = slotMeta;
|
|
658
718
|
const ssrParent = this.$resolveSSR(ssrRoot, tplDom, parentPath, pathStart) ?? ssrRoot;
|
|
659
719
|
const blockMeta = this.$block(blockIndex);
|
|
660
|
-
const shown = condition[0](this.$resolver, scope);
|
|
661
720
|
let condInstance = null;
|
|
662
721
|
if (ssrParent !== lastCondParent) {
|
|
663
722
|
lastCondMarker = null;
|
|
@@ -676,11 +735,10 @@ export class TemplateElement extends HTMLElement {
|
|
|
676
735
|
}
|
|
677
736
|
if (marker)
|
|
678
737
|
lastCondMarker = marker;
|
|
679
|
-
|
|
680
|
-
|
|
681
|
-
if (
|
|
682
|
-
condInstance =
|
|
683
|
-
}
|
|
738
|
+
if (marker && blockMeta) {
|
|
739
|
+
condInstance = this.$hydrateCondContent(condAnchor, blockMeta, scope);
|
|
740
|
+
if (condInstance)
|
|
741
|
+
condInstance.parent = instance;
|
|
684
742
|
}
|
|
685
743
|
if (marker) {
|
|
686
744
|
const lastNode = condInstance ? condInstance.nodes[condInstance.nodes.length - 1] : condAnchor;
|
|
@@ -692,7 +750,7 @@ export class TemplateElement extends HTMLElement {
|
|
|
692
750
|
instance.conds.push({
|
|
693
751
|
condition: condition, blockIndex,
|
|
694
752
|
anchor: condAnchor,
|
|
695
|
-
scope, instance: condInstance,
|
|
753
|
+
scope, owner: instance, instance: condInstance,
|
|
696
754
|
});
|
|
697
755
|
}
|
|
698
756
|
}
|
|
@@ -700,7 +758,7 @@ export class TemplateElement extends HTMLElement {
|
|
|
700
758
|
let lastRepMarker = null;
|
|
701
759
|
let lastRepParent = null;
|
|
702
760
|
for (let i = 0; i < meta.r.length; i++) {
|
|
703
|
-
const [collection, itemVar, blockIndex, slotMeta] = meta.r[i];
|
|
761
|
+
const [collection, itemVar, blockIndex, slotMeta, keyPath] = meta.r[i];
|
|
704
762
|
const [parentPath] = slotMeta;
|
|
705
763
|
const ssrParent = this.$resolveSSR(ssrRoot, tplDom, parentPath, pathStart) ?? ssrRoot;
|
|
706
764
|
if (ssrParent !== lastRepParent) {
|
|
@@ -708,7 +766,6 @@ export class TemplateElement extends HTMLElement {
|
|
|
708
766
|
lastRepParent = ssrParent;
|
|
709
767
|
}
|
|
710
768
|
const blockMeta = this.$block(blockIndex);
|
|
711
|
-
const { keyAttribute, keyPath } = this.$repeatMaps(blockIndex, itemVar);
|
|
712
769
|
const blockTplDom = blockMeta ? getTemplateDom(blockMeta) : null;
|
|
713
770
|
const rootTag = blockMeta && blockTplDom?.childNodes.length === 1 && blockTplDom.children.length === 1
|
|
714
771
|
? this.$rootTag(blockMeta)
|
|
@@ -728,27 +785,35 @@ export class TemplateElement extends HTMLElement {
|
|
|
728
785
|
}
|
|
729
786
|
lastRepMarker = anchor;
|
|
730
787
|
const repeatInsts = [];
|
|
788
|
+
const hasCollectionState = this.$hasStateRoot(collection, scope);
|
|
731
789
|
const itemsArr = this.$resolveValue(collection, scope);
|
|
732
790
|
const items = Array.isArray(itemsArr) ? itemsArr : [];
|
|
733
791
|
const { items: itemMarkers, end: endMarker } = marker
|
|
734
792
|
? collectItemMarkers(anchor)
|
|
735
793
|
: { items: [], end: null };
|
|
736
|
-
if (blockMeta && blockTplDom &&
|
|
737
|
-
if (
|
|
794
|
+
if (blockMeta && blockTplDom && anchor.parentNode && itemMarkers.length > 0) {
|
|
795
|
+
if (!this.$activatingDeferredSSR
|
|
796
|
+
&& hasCollectionState
|
|
797
|
+
&& itemMarkers.length !== items.length) {
|
|
738
798
|
console.warn(`[webui] hydration: repeat marker count (${itemMarkers.length}) ≠ data length (${items.length}) for "${collection}"`);
|
|
739
799
|
}
|
|
740
|
-
|
|
741
|
-
for (let j = 0; j < limit; j++) {
|
|
800
|
+
for (let j = 0; j < itemMarkers.length; j++) {
|
|
742
801
|
const itemValue = items[j];
|
|
743
|
-
const
|
|
802
|
+
const known = hasCollectionState && j < items.length;
|
|
803
|
+
if (!known)
|
|
804
|
+
this.$hasUnknownScopes = true;
|
|
805
|
+
const itemScope = {
|
|
806
|
+
name: itemVar,
|
|
807
|
+
value: itemValue,
|
|
808
|
+
parent: scope,
|
|
809
|
+
known,
|
|
810
|
+
};
|
|
744
811
|
if (rootTag) {
|
|
745
812
|
const itemEl = nextElement(itemMarkers[j]);
|
|
746
813
|
if (itemEl) {
|
|
747
|
-
const key = keyAttribute !== undefined
|
|
748
|
-
? itemEl.getAttribute(keyAttribute)
|
|
749
|
-
: String(j);
|
|
750
814
|
const childInstance = this.$hydrate(itemEl, blockMeta, blockTplDom, itemScope, 1);
|
|
751
|
-
|
|
815
|
+
childInstance.parent = instance;
|
|
816
|
+
repeatInsts.push(childInstance);
|
|
752
817
|
}
|
|
753
818
|
}
|
|
754
819
|
else {
|
|
@@ -762,6 +827,7 @@ export class TemplateElement extends HTMLElement {
|
|
|
762
827
|
cursor = next;
|
|
763
828
|
}
|
|
764
829
|
const inst = this.$hydrate(wrapper, blockMeta, blockTplDom, itemScope);
|
|
830
|
+
inst.parent = instance;
|
|
765
831
|
inst.nodes = childNodesArray(wrapper);
|
|
766
832
|
let afterNode = itemMarkers[j];
|
|
767
833
|
for (let nodeIndex = 0; nodeIndex < inst.nodes.length; nodeIndex++) {
|
|
@@ -769,8 +835,10 @@ export class TemplateElement extends HTMLElement {
|
|
|
769
835
|
itemParent?.insertBefore(node, afterNode.nextSibling);
|
|
770
836
|
afterNode = node;
|
|
771
837
|
}
|
|
772
|
-
|
|
773
|
-
|
|
838
|
+
if (itemParent) {
|
|
839
|
+
this.$replaceInstanceContainer(inst, wrapper, itemParent);
|
|
840
|
+
}
|
|
841
|
+
repeatInsts.push(inst);
|
|
774
842
|
}
|
|
775
843
|
}
|
|
776
844
|
for (let m = 0; m < itemMarkers.length; m++) {
|
|
@@ -779,43 +847,76 @@ export class TemplateElement extends HTMLElement {
|
|
|
779
847
|
}
|
|
780
848
|
if (endMarker)
|
|
781
849
|
staleMarkers.push(endMarker);
|
|
782
|
-
|
|
850
|
+
const binding = {
|
|
783
851
|
markerId: i, collection, itemVar, blockIndex,
|
|
784
852
|
container: (anchor.parentNode ?? ssrRoot),
|
|
785
853
|
start: anchor, end: null,
|
|
786
|
-
scope, owner: instance, instances: repeatInsts,
|
|
787
|
-
|
|
788
|
-
}
|
|
854
|
+
scope, owner: instance, instances: repeatInsts,
|
|
855
|
+
synced: hasCollectionState,
|
|
856
|
+
};
|
|
857
|
+
if (keyPath !== undefined) {
|
|
858
|
+
binding.keyState = createRepeatKeyState(keyPath);
|
|
859
|
+
if (hasCollectionState) {
|
|
860
|
+
seedHydratedRepeatKeys(binding, items);
|
|
861
|
+
}
|
|
862
|
+
}
|
|
863
|
+
instance.repeats.push(binding);
|
|
789
864
|
}
|
|
790
865
|
}
|
|
791
866
|
this.$finalize(instance, ssrRoot, meta, (r, p) => this.$resolveSSR(r, tplDom, p, pathStart), scope);
|
|
792
867
|
for (let i = 0; i < staleMarkers.length; i++) {
|
|
793
868
|
staleMarkers[i].parentNode?.removeChild(staleMarkers[i]);
|
|
794
869
|
}
|
|
870
|
+
this.$compactNodeArray(instance);
|
|
795
871
|
return instance;
|
|
796
872
|
}
|
|
797
|
-
$
|
|
873
|
+
$collectConditionalRange(start) {
|
|
798
874
|
const nodes = [];
|
|
875
|
+
let depth = 0;
|
|
799
876
|
let node = start.nextSibling;
|
|
800
877
|
while (node) {
|
|
801
|
-
if (node.nodeType === 8
|
|
802
|
-
|
|
878
|
+
if (node.nodeType === 8) {
|
|
879
|
+
const data = node.data;
|
|
880
|
+
if (data === MARKER_COND_START) {
|
|
881
|
+
depth++;
|
|
882
|
+
}
|
|
883
|
+
else if (data === MARKER_COND_END) {
|
|
884
|
+
if (depth === 0)
|
|
885
|
+
break;
|
|
886
|
+
depth--;
|
|
887
|
+
}
|
|
888
|
+
}
|
|
803
889
|
nodes.push(node);
|
|
804
890
|
node = node.nextSibling;
|
|
805
891
|
}
|
|
806
892
|
return nodes;
|
|
807
893
|
}
|
|
894
|
+
$hasRootStructuralSlot(meta) {
|
|
895
|
+
if (meta.c) {
|
|
896
|
+
for (let i = 0; i < meta.c.length; i++) {
|
|
897
|
+
if (meta.c[i][2][0].length === 0)
|
|
898
|
+
return true;
|
|
899
|
+
}
|
|
900
|
+
}
|
|
901
|
+
if (meta.r) {
|
|
902
|
+
for (let i = 0; i < meta.r.length; i++) {
|
|
903
|
+
if (meta.r[i][3][0].length === 0)
|
|
904
|
+
return true;
|
|
905
|
+
}
|
|
906
|
+
}
|
|
907
|
+
return false;
|
|
908
|
+
}
|
|
808
909
|
$hydrateCondContent(condAnchor, blockMeta, scope) {
|
|
809
910
|
const rootTag = this.$rootTag(blockMeta);
|
|
810
911
|
const tplDom = getTemplateDom(blockMeta);
|
|
811
|
-
if (rootTag && tplDom.children.length === 1) {
|
|
912
|
+
if (rootTag && tplDom.children.length === 1 && !this.$hasRootStructuralSlot(blockMeta)) {
|
|
812
913
|
const el = nextElement(condAnchor);
|
|
813
914
|
if (el) {
|
|
814
915
|
return this.$hydrate(el, blockMeta, tplDom, scope, 1);
|
|
815
916
|
}
|
|
816
917
|
return null;
|
|
817
918
|
}
|
|
818
|
-
const condNodes = this.$
|
|
919
|
+
const condNodes = this.$collectConditionalRange(condAnchor);
|
|
819
920
|
if (condNodes.length === 0)
|
|
820
921
|
return null;
|
|
821
922
|
const wrapper = document.createElement('div');
|
|
@@ -828,6 +929,9 @@ export class TemplateElement extends HTMLElement {
|
|
|
828
929
|
condAnchor.parentNode?.insertBefore(inst.nodes[cn], afterNode.nextSibling);
|
|
829
930
|
afterNode = inst.nodes[cn];
|
|
830
931
|
}
|
|
932
|
+
const container = condAnchor.parentNode;
|
|
933
|
+
if (container)
|
|
934
|
+
this.$replaceInstanceContainer(inst, wrapper, container);
|
|
831
935
|
return inst;
|
|
832
936
|
}
|
|
833
937
|
$findMarker(parent, data, after) {
|
|
@@ -840,16 +944,6 @@ export class TemplateElement extends HTMLElement {
|
|
|
840
944
|
}
|
|
841
945
|
return null;
|
|
842
946
|
}
|
|
843
|
-
$hasContentAfterMarker(anchor, endData) {
|
|
844
|
-
let sibling = anchor.nextSibling;
|
|
845
|
-
while (sibling) {
|
|
846
|
-
if (sibling.nodeType === 8 && sibling.data === endData) {
|
|
847
|
-
return false;
|
|
848
|
-
}
|
|
849
|
-
return true;
|
|
850
|
-
}
|
|
851
|
-
return false;
|
|
852
|
-
}
|
|
853
947
|
$findSSRText(ssrParent, tplParent, beforeIndex) {
|
|
854
948
|
const ordinals = getTplOrdinals(tplParent);
|
|
855
949
|
let textOrd = 0;
|
|
@@ -926,32 +1020,6 @@ export class TemplateElement extends HTMLElement {
|
|
|
926
1020
|
return { element: el, name, kind, parts: entry[2], scope };
|
|
927
1021
|
return { element: el, name, kind: kind, path: entry[2] || '', scope };
|
|
928
1022
|
}
|
|
929
|
-
$repeatMaps(blockIndex, itemVar) {
|
|
930
|
-
let keyAttribute;
|
|
931
|
-
let keyPath;
|
|
932
|
-
const bm = this.$block(blockIndex);
|
|
933
|
-
if (bm?.a && bm.ag) {
|
|
934
|
-
for (let g = 0; g < bm.ag.length; g++) {
|
|
935
|
-
const [tp, s, c] = bm.ag[g];
|
|
936
|
-
const isRoot = tp.length === 0 || (tp.length === 1 && tp[0] === 0);
|
|
937
|
-
if (isRoot) {
|
|
938
|
-
for (let j = 0; j < c; j++) {
|
|
939
|
-
const entry = bm.a[s + j];
|
|
940
|
-
if (entry) {
|
|
941
|
-
if (entry[1] === 0 || entry[1] === 3) {
|
|
942
|
-
const dp = this.$singleDynamic(entry[1] === 3 ? entry[2] : [[entry[2]]]);
|
|
943
|
-
if (dp && keyPath === undefined && dp.path.startsWith(itemVar + '.')) {
|
|
944
|
-
keyAttribute = entry[0];
|
|
945
|
-
keyPath = dp.path.slice(itemVar.length + 1);
|
|
946
|
-
}
|
|
947
|
-
}
|
|
948
|
-
}
|
|
949
|
-
}
|
|
950
|
-
}
|
|
951
|
-
}
|
|
952
|
-
}
|
|
953
|
-
return { keyAttribute, keyPath };
|
|
954
|
-
}
|
|
955
1023
|
$buildPathIndex() {
|
|
956
1024
|
if (!this.$root)
|
|
957
1025
|
return;
|
|
@@ -1025,7 +1093,7 @@ export class TemplateElement extends HTMLElement {
|
|
|
1025
1093
|
ensure(keyFor(rep.collection)).repeats.push(rep);
|
|
1026
1094
|
}
|
|
1027
1095
|
for (let i = 0; i < rep.instances.length; i++) {
|
|
1028
|
-
visit(rep.instances[i]
|
|
1096
|
+
visit(rep.instances[i]);
|
|
1029
1097
|
}
|
|
1030
1098
|
}
|
|
1031
1099
|
};
|
|
@@ -1041,16 +1109,37 @@ export class TemplateElement extends HTMLElement {
|
|
|
1041
1109
|
this.$pathIndex = index;
|
|
1042
1110
|
}
|
|
1043
1111
|
$updateBindings(texts, attrs, conds, repeats) {
|
|
1044
|
-
|
|
1045
|
-
|
|
1046
|
-
|
|
1047
|
-
this.$
|
|
1048
|
-
|
|
1049
|
-
|
|
1112
|
+
const gated = this.$hasUnknownScopes;
|
|
1113
|
+
for (let i = 0; i < texts.length; i++) {
|
|
1114
|
+
const binding = texts[i];
|
|
1115
|
+
if (!gated || !binding.scope || this.$scopeIsKnown(binding.scope))
|
|
1116
|
+
this.$patchText(binding);
|
|
1117
|
+
}
|
|
1118
|
+
for (let i = 0; i < attrs.length; i++) {
|
|
1119
|
+
const binding = attrs[i];
|
|
1120
|
+
if (!gated || !binding.scope || this.$scopeIsKnown(binding.scope))
|
|
1121
|
+
this.$patchAttr(binding);
|
|
1122
|
+
}
|
|
1123
|
+
for (let i = 0; i < conds.length; i++) {
|
|
1124
|
+
const binding = conds[i];
|
|
1125
|
+
if (!gated || !binding.scope || this.$scopeIsKnown(binding.scope))
|
|
1126
|
+
this.$toggleCond(binding);
|
|
1127
|
+
}
|
|
1050
1128
|
for (let i = 0; i < repeats.length; i++) {
|
|
1051
|
-
|
|
1129
|
+
const binding = repeats[i];
|
|
1130
|
+
if (!gated || !binding.scope || this.$scopeIsKnown(binding.scope))
|
|
1131
|
+
syncRepeat(this, binding);
|
|
1052
1132
|
}
|
|
1053
1133
|
}
|
|
1134
|
+
$scopeIsKnown(scope) {
|
|
1135
|
+
let frame = scope;
|
|
1136
|
+
while (frame) {
|
|
1137
|
+
if (frame.known === false)
|
|
1138
|
+
return false;
|
|
1139
|
+
frame = frame.parent;
|
|
1140
|
+
}
|
|
1141
|
+
return true;
|
|
1142
|
+
}
|
|
1054
1143
|
$updateInstance(instance) {
|
|
1055
1144
|
this.$updateBindings(instance.texts, instance.attrs, instance.conds, instance.repeats);
|
|
1056
1145
|
}
|
|
@@ -1099,7 +1188,8 @@ export class TemplateElement extends HTMLElement {
|
|
|
1099
1188
|
el.setAttribute(b.name, '');
|
|
1100
1189
|
else
|
|
1101
1190
|
el.removeAttribute(b.name);
|
|
1102
|
-
if (b.name === 'checked' || b.name === 'selected' || b.name === 'disabled')
|
|
1191
|
+
if ((b.name === 'checked' || b.name === 'selected' || b.name === 'disabled')
|
|
1192
|
+
&& hasNativeLiveProperty(el, b.name)) {
|
|
1103
1193
|
el[b.name] = show;
|
|
1104
1194
|
}
|
|
1105
1195
|
break;
|
|
@@ -1113,12 +1203,14 @@ export class TemplateElement extends HTMLElement {
|
|
|
1113
1203
|
default: {
|
|
1114
1204
|
const v = this.$resolveValue(b.path, b.scope);
|
|
1115
1205
|
const s = v == null ? '' : String(v);
|
|
1116
|
-
if (b.name === 'checked' || b.name === 'selected')
|
|
1206
|
+
if ((b.name === 'checked' || b.name === 'selected')
|
|
1207
|
+
&& hasNativeLiveProperty(el, b.name)) {
|
|
1117
1208
|
el[b.name] = !!v && v !== 'false' && v !== '0';
|
|
1118
1209
|
}
|
|
1119
|
-
else if (b.name === 'value') {
|
|
1120
|
-
|
|
1121
|
-
|
|
1210
|
+
else if (b.name === 'value' && hasNativeLiveProperty(el, b.name)) {
|
|
1211
|
+
const target = el;
|
|
1212
|
+
if (target.value !== s)
|
|
1213
|
+
target.value = s;
|
|
1122
1214
|
}
|
|
1123
1215
|
else {
|
|
1124
1216
|
if (el.getAttribute(b.name) !== s)
|
|
@@ -1131,22 +1223,25 @@ export class TemplateElement extends HTMLElement {
|
|
|
1131
1223
|
$toggleCond(c) {
|
|
1132
1224
|
const show = c.condition[0](this.$resolver, c.scope);
|
|
1133
1225
|
if (show) {
|
|
1226
|
+
let created = false;
|
|
1227
|
+
const container = c.anchor.parentNode;
|
|
1134
1228
|
if (!c.instance) {
|
|
1135
|
-
c.instance = this.$createBlockInstance(c.blockIndex, c.scope);
|
|
1136
|
-
|
|
1137
|
-
const frag = document.createDocumentFragment();
|
|
1138
|
-
for (const n of c.instance.nodes)
|
|
1139
|
-
frag.appendChild(n);
|
|
1140
|
-
c.anchor.parentNode?.insertBefore(frag, c.anchor.nextSibling);
|
|
1141
|
-
}
|
|
1229
|
+
c.instance = this.$createBlockInstance(c.blockIndex, c.scope, c.owner, container ?? undefined);
|
|
1230
|
+
created = c.instance !== null;
|
|
1142
1231
|
}
|
|
1143
1232
|
else {
|
|
1144
1233
|
this.$updateInstance(c.instance);
|
|
1145
1234
|
}
|
|
1235
|
+
if (c.instance && container) {
|
|
1236
|
+
this.$insertInstanceAfter(c.anchor, container, c.instance);
|
|
1237
|
+
if (created)
|
|
1238
|
+
this.$changeStructure();
|
|
1239
|
+
}
|
|
1146
1240
|
}
|
|
1147
1241
|
else if (c.instance) {
|
|
1148
1242
|
this.$removeInstance(c.instance);
|
|
1149
1243
|
c.instance = null;
|
|
1244
|
+
this.$changeStructure(c.owner);
|
|
1150
1245
|
}
|
|
1151
1246
|
}
|
|
1152
1247
|
$resolveValue(path, scope) {
|
|
@@ -1164,6 +1259,23 @@ export class TemplateElement extends HTMLElement {
|
|
|
1164
1259
|
return this.$resolveComponentRoot(path);
|
|
1165
1260
|
return dotWalk(this.$resolveComponentRoot(path.substring(0, dot)), path, dot + 1);
|
|
1166
1261
|
}
|
|
1262
|
+
$hasStateRoot(path, scope) {
|
|
1263
|
+
let frame = scope;
|
|
1264
|
+
while (frame) {
|
|
1265
|
+
if (path === frame.name
|
|
1266
|
+
|| (path.length > frame.name.length
|
|
1267
|
+
&& path.charCodeAt(frame.name.length) === 46
|
|
1268
|
+
&& path.startsWith(frame.name))) {
|
|
1269
|
+
return frame.value !== undefined;
|
|
1270
|
+
}
|
|
1271
|
+
frame = frame.parent;
|
|
1272
|
+
}
|
|
1273
|
+
const dot = path.indexOf('.');
|
|
1274
|
+
const root = dot === -1 ? path : path.substring(0, dot);
|
|
1275
|
+
return hasAuthoredMember(this, root)
|
|
1276
|
+
|| (this.$templateState !== null
|
|
1277
|
+
&& Object.prototype.hasOwnProperty.call(this.$templateState, root));
|
|
1278
|
+
}
|
|
1167
1279
|
$resolveComponentRoot(root) {
|
|
1168
1280
|
const instance = this;
|
|
1169
1281
|
if (this.$templateState &&
|
|
@@ -1189,64 +1301,92 @@ export class TemplateElement extends HTMLElement {
|
|
|
1189
1301
|
$block(blockIndex) {
|
|
1190
1302
|
return this.$meta?.b?.[blockIndex];
|
|
1191
1303
|
}
|
|
1192
|
-
$createBlockInstance(blockIndex, scope) {
|
|
1304
|
+
$createBlockInstance(blockIndex, scope, parent, container) {
|
|
1193
1305
|
const bm = this.$block(blockIndex);
|
|
1194
1306
|
if (!bm)
|
|
1195
1307
|
return null;
|
|
1196
1308
|
const wrapper = this.$createStagingRoot(bm);
|
|
1197
1309
|
const inst = this.$wire(wrapper, bm, scope);
|
|
1310
|
+
inst.parent = parent;
|
|
1198
1311
|
inst.nodes = childNodesArray(wrapper);
|
|
1199
1312
|
this.$updateInstance(inst);
|
|
1200
1313
|
if (inst.repeats.length !== 0 || inst.conds.length !== 0) {
|
|
1201
1314
|
inst.nodes = childNodesArray(wrapper);
|
|
1202
|
-
this.$
|
|
1315
|
+
this.$replaceInstanceContainer(inst, wrapper, container ?? null);
|
|
1316
|
+
}
|
|
1317
|
+
else if (container) {
|
|
1318
|
+
inst.container = container;
|
|
1203
1319
|
}
|
|
1204
1320
|
return inst;
|
|
1205
1321
|
}
|
|
1206
1322
|
$removeInstance(instance) {
|
|
1207
|
-
this.$
|
|
1208
|
-
|
|
1209
|
-
|
|
1210
|
-
|
|
1211
|
-
|
|
1212
|
-
|
|
1323
|
+
this.$disposeInstance(instance, true);
|
|
1324
|
+
}
|
|
1325
|
+
$disposeInstance(root, removeNodes) {
|
|
1326
|
+
const stack = [root];
|
|
1327
|
+
while (stack.length > 0) {
|
|
1328
|
+
const instance = stack.pop();
|
|
1329
|
+
if (!instance)
|
|
1330
|
+
continue;
|
|
1331
|
+
const cleanups = instance.cleanups;
|
|
1332
|
+
if (cleanups) {
|
|
1333
|
+
for (const cleanup of cleanups)
|
|
1334
|
+
cleanup();
|
|
1335
|
+
cleanups.length = 0;
|
|
1336
|
+
}
|
|
1337
|
+
if (removeNodes) {
|
|
1338
|
+
for (const node of instance.nodes)
|
|
1339
|
+
node.parentNode?.removeChild(node);
|
|
1340
|
+
}
|
|
1341
|
+
for (const binding of instance.conds) {
|
|
1342
|
+
if (binding.instance)
|
|
1343
|
+
stack.push(binding.instance);
|
|
1344
|
+
binding.instance = null;
|
|
1345
|
+
}
|
|
1346
|
+
for (const repeat of instance.repeats) {
|
|
1347
|
+
for (const child of repeat.instances)
|
|
1348
|
+
stack.push(child);
|
|
1349
|
+
this.$clearRepeatBinding(repeat);
|
|
1350
|
+
}
|
|
1351
|
+
this.$clearInstance(instance);
|
|
1352
|
+
}
|
|
1353
|
+
}
|
|
1354
|
+
$compactNodeArray(instance) {
|
|
1355
|
+
const container = instance.container;
|
|
1356
|
+
if (!container)
|
|
1357
|
+
return;
|
|
1358
|
+
const nodes = instance.nodes;
|
|
1359
|
+
let write = 0;
|
|
1360
|
+
for (let read = 0; read < nodes.length; read++) {
|
|
1361
|
+
const node = nodes[read];
|
|
1362
|
+
if (node.parentNode === container) {
|
|
1363
|
+
nodes[write] = node;
|
|
1364
|
+
write++;
|
|
1365
|
+
}
|
|
1213
1366
|
}
|
|
1214
|
-
|
|
1215
|
-
|
|
1216
|
-
|
|
1367
|
+
nodes.length = write;
|
|
1368
|
+
}
|
|
1369
|
+
$changeStructure(removedFrom) {
|
|
1370
|
+
if (removedFrom) {
|
|
1371
|
+
let current = removedFrom;
|
|
1372
|
+
while (current) {
|
|
1373
|
+
this.$compactNodeArray(current);
|
|
1374
|
+
current = current.parent;
|
|
1375
|
+
}
|
|
1217
1376
|
}
|
|
1377
|
+
this.$pathIndex = undefined;
|
|
1378
|
+
this.$wildcardBindings = undefined;
|
|
1218
1379
|
}
|
|
1219
1380
|
$insertInstanceAfter(cursor, container, instance) {
|
|
1381
|
+
this.$replaceInstanceContainer(instance, instance.container, container);
|
|
1220
1382
|
const nodes = instance.nodes;
|
|
1221
1383
|
if (nodes.length === 0)
|
|
1222
1384
|
return cursor;
|
|
1223
1385
|
const ref = cursor ? cursor.nextSibling : container.firstChild;
|
|
1224
1386
|
if (nodes[0] === ref)
|
|
1225
1387
|
return nodes[nodes.length - 1];
|
|
1226
|
-
const frag = document.createDocumentFragment();
|
|
1227
1388
|
for (let i = 0; i < nodes.length; i++)
|
|
1228
|
-
|
|
1229
|
-
container.insertBefore(frag, ref);
|
|
1389
|
+
container.insertBefore(nodes[i], ref);
|
|
1230
1390
|
return nodes[nodes.length - 1];
|
|
1231
1391
|
}
|
|
1232
|
-
$singleDynamic(parts) {
|
|
1233
|
-
let path = '';
|
|
1234
|
-
let prefix = '';
|
|
1235
|
-
let suffix = '';
|
|
1236
|
-
let seen = false;
|
|
1237
|
-
for (const p of parts) {
|
|
1238
|
-
if (typeof p === 'string') {
|
|
1239
|
-
if (seen)
|
|
1240
|
-
suffix += p;
|
|
1241
|
-
else
|
|
1242
|
-
prefix += p;
|
|
1243
|
-
continue;
|
|
1244
|
-
}
|
|
1245
|
-
if (seen)
|
|
1246
|
-
return null;
|
|
1247
|
-
path = p[0];
|
|
1248
|
-
seen = true;
|
|
1249
|
-
}
|
|
1250
|
-
return seen ? { path, prefix, suffix } : null;
|
|
1251
|
-
}
|
|
1252
1392
|
}
|