@microsoft/webui-framework 0.0.16 → 0.0.18

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.
@@ -0,0 +1,1252 @@
1
+ import { getTemplate } from './template.js';
2
+ import { hydrationStart, hydrationEnd } from './lifecycle.js';
3
+ import { syncRepeat, dotWalk } from './element/diff.js';
4
+ import { collectItemMarkers, nextElement, findByOrdinal, MARKER_COND_START, MARKER_COND_END, MARKER_REPEAT_START, } from './element/markers.js';
5
+ import { injectModuleStyle, } from './element/styles.js';
6
+ import { ATTR_KIND_BOOLEAN, ATTR_KIND_COMPLEX, ATTR_KIND_TEMPLATE, } from './element/types.js';
7
+ import { templateHasRoot, templateRootForAttribute } from './template-roots.js';
8
+ const DEV = typeof __WEBUI_DEV__ === 'undefined' || __WEBUI_DEV__;
9
+ const templateCache = new WeakMap();
10
+ const templateDOMCache = new WeakMap();
11
+ const rootTagCache = new WeakMap();
12
+ const tplOrdinalCache = new WeakMap();
13
+ function getTplOrdinals(tplNode) {
14
+ let map = tplOrdinalCache.get(tplNode);
15
+ if (map)
16
+ return map;
17
+ map = new Map();
18
+ let elemOrd = 0;
19
+ let textOrd = 0;
20
+ const children = tplNode.childNodes;
21
+ for (let k = 0; k < children.length; k++) {
22
+ const type = children[k].nodeType;
23
+ if (type === 1) {
24
+ map.set(k, [1, elemOrd]);
25
+ elemOrd++;
26
+ }
27
+ else if (type === 3) {
28
+ map.set(k, [3, textOrd]);
29
+ textOrd++;
30
+ }
31
+ }
32
+ tplOrdinalCache.set(tplNode, map);
33
+ return map;
34
+ }
35
+ const EMPTY_ARR = [];
36
+ const EMPTY_SET = Object.freeze(new Set());
37
+ const WEBUI_SET_STATE_KEY = Symbol.for('microsoft.webui.setStateKey');
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
+ function childNodesArray(parent) {
61
+ const children = parent.childNodes;
62
+ const len = children.length;
63
+ const result = new Array(len);
64
+ for (let i = 0; i < len; i++)
65
+ result[i] = children[i];
66
+ return result;
67
+ }
68
+ function getTemplateDom(meta) {
69
+ let cached = templateDOMCache.get(meta);
70
+ if (cached)
71
+ return cached;
72
+ const div = document.createElement('div');
73
+ div.innerHTML = meta.h;
74
+ templateDOMCache.set(meta, div);
75
+ return div;
76
+ }
77
+ function installTemplateObservedAttributes(ctor, tagName) {
78
+ const meta = getTemplate(tagName);
79
+ if (!meta)
80
+ return;
81
+ templateMetaByCtor.set(ctor, meta);
82
+ const attrs = meta.ta ?? EMPTY_ARR;
83
+ if (attrs.length === 0)
84
+ return;
85
+ const existing = ctor.observedAttributes ?? EMPTY_ARR;
86
+ const merged = new Array(existing.length + attrs.length);
87
+ let count = 0;
88
+ for (let i = 0; i < existing.length; i++) {
89
+ merged[count] = existing[i];
90
+ count += 1;
91
+ }
92
+ for (let attrIndex = 0; attrIndex < attrs.length; attrIndex++) {
93
+ const attrName = attrs[attrIndex];
94
+ let found = false;
95
+ for (let i = 0; i < count; i++) {
96
+ if (merged[i] === attrName) {
97
+ found = true;
98
+ break;
99
+ }
100
+ }
101
+ if (!found) {
102
+ merged[count] = attrName;
103
+ count += 1;
104
+ }
105
+ }
106
+ merged.length = count;
107
+ Object.defineProperty(ctor, 'observedAttributes', {
108
+ get() {
109
+ return merged;
110
+ },
111
+ configurable: true,
112
+ });
113
+ }
114
+ function hasAuthoredMember(instance, key) {
115
+ if (Object.prototype.hasOwnProperty.call(instance, key))
116
+ return true;
117
+ let proto = Object.getPrototypeOf(instance);
118
+ while (proto && proto !== TemplateElement.prototype) {
119
+ if (Object.prototype.hasOwnProperty.call(proto, key))
120
+ return true;
121
+ proto = Object.getPrototypeOf(proto);
122
+ }
123
+ return false;
124
+ }
125
+ export class TemplateElement extends HTMLElement {
126
+ constructor() {
127
+ super(...arguments);
128
+ this.$root = null;
129
+ this.$ready = false;
130
+ this.$hydrated = false;
131
+ this.$templateState = null;
132
+ this.$dirtyPaths = null;
133
+ this.$pendingFlush = false;
134
+ this.$preReadyWrites = null;
135
+ this.$resolver = (p, s) => this.$resolveValue(p, s);
136
+ }
137
+ [WEBUI_SET_STATE_KEY](key, value) {
138
+ return this.$setStateKey(key, value);
139
+ }
140
+ static define(tagName) {
141
+ installTemplateObservedAttributes(this, tagName);
142
+ customElements.define(tagName, this);
143
+ }
144
+ connectedCallback() {
145
+ const tag = this.tagName.toLowerCase();
146
+ if (this.$hydrated && this.$root) {
147
+ hydrationStart();
148
+ this.$ready = true;
149
+ this.$update();
150
+ hydrationEnd();
151
+ return;
152
+ }
153
+ const meta = getTemplate(tag);
154
+ if (!meta) {
155
+ console.warn(`[WebUI] Template metadata for <${tag}> not found. ` +
156
+ `Ensure the component is included in the SSR output or registered via __webui.templates.`);
157
+ return;
158
+ }
159
+ this.$meta = meta;
160
+ if (document.readyState === 'loading') {
161
+ runWhenDomReady(() => this.$mount(meta));
162
+ }
163
+ else {
164
+ this.$mount(meta);
165
+ }
166
+ }
167
+ $mount(meta) {
168
+ if (this.$hydrated)
169
+ return;
170
+ hydrationStart();
171
+ const hasShadow = !!this.shadowRoot;
172
+ const wantShadow = hasShadow || !!meta.sd;
173
+ let root;
174
+ let isSSR;
175
+ let clientRoot = null;
176
+ if (hasShadow) {
177
+ root = this.shadowRoot;
178
+ isSSR = true;
179
+ }
180
+ else if (this.childNodes.length > 0 && !meta.sd) {
181
+ root = this;
182
+ isSSR = true;
183
+ }
184
+ else if (wantShadow) {
185
+ root = this.attachShadow({ mode: 'open' });
186
+ isSSR = false;
187
+ }
188
+ else {
189
+ root = this;
190
+ isSSR = false;
191
+ }
192
+ if (meta.sa)
193
+ injectModuleStyle(meta.sa, this.shadowRoot);
194
+ if (isSSR) {
195
+ this.$applySSRState();
196
+ this.$root = this.$hydrate(root, meta, getTemplateDom(meta));
197
+ }
198
+ else {
199
+ clientRoot = this.$createStagingRoot(meta);
200
+ this.$root = this.$wire(clientRoot, meta);
201
+ }
202
+ this.$meta = meta;
203
+ this.$hydrated = true;
204
+ this.$ready = true;
205
+ this.$syncAuthoredAttributes();
206
+ if (isSSR && DEV)
207
+ this.$checkHydrationMismatch();
208
+ else
209
+ this.$preReadyWrites = null;
210
+ if (!isSSR && clientRoot) {
211
+ this.$updateInstance(this.$root);
212
+ if (this.$root.repeats.length !== 0 || this.$root.conds.length !== 0) {
213
+ this.$root.nodes = childNodesArray(clientRoot);
214
+ this.$releaseStagingRepeatContainers(this.$root, clientRoot);
215
+ }
216
+ this.$appendStagedChildren(root, clientRoot);
217
+ }
218
+ hydrationEnd();
219
+ }
220
+ disconnectedCallback() {
221
+ if (this.$root) {
222
+ queueMicrotask(() => {
223
+ if (!this.isConnected)
224
+ this.$destroy();
225
+ });
226
+ }
227
+ }
228
+ $destroy() {
229
+ if (!this.$root)
230
+ return;
231
+ this.$teardown(this.$root);
232
+ this.$root = null;
233
+ this.$pathIndex = undefined;
234
+ this.$wildcardBindings = undefined;
235
+ this.$dirtyPaths = null;
236
+ this.$pendingFlush = false;
237
+ this.$preReadyWrites = null;
238
+ this.$ready = false;
239
+ }
240
+ $teardown(instance) {
241
+ this.$teardownInstanceCleanups(instance);
242
+ for (const c of instance.conds) {
243
+ if (c.instance)
244
+ this.$teardown(c.instance);
245
+ c.instance = null;
246
+ }
247
+ for (const r of instance.repeats) {
248
+ for (const item of r.instances)
249
+ this.$teardown(item.instance);
250
+ r.instances.length = 0;
251
+ r.container = null;
252
+ r.start = null;
253
+ r.end = null;
254
+ }
255
+ instance.nodes.length = 0;
256
+ instance.texts.length = 0;
257
+ instance.attrs.length = 0;
258
+ instance.conds.length = 0;
259
+ instance.repeats.length = 0;
260
+ }
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
+ attributeChangedCallback(name, oldValue, newValue) {
270
+ if (Object.is(oldValue, newValue))
271
+ return;
272
+ const property = this.$templateRootForAttribute(name);
273
+ if (property && this.$usesTemplateState(property)) {
274
+ this.$setTemplateState(property, newValue);
275
+ }
276
+ }
277
+ setState(state) {
278
+ const keys = Object.keys(state);
279
+ for (let i = 0; i < keys.length; i++) {
280
+ const key = keys[i];
281
+ this.$setStateKey(key, state[key]);
282
+ }
283
+ this.$flushUpdates();
284
+ }
285
+ $observableNames() {
286
+ return EMPTY_SET;
287
+ }
288
+ $shouldApplySSRState(_key) {
289
+ return true;
290
+ }
291
+ $syncAuthoredAttributes() {
292
+ }
293
+ $shouldApplyTemplateStateFromSSR(_key) {
294
+ return true;
295
+ }
296
+ $setTemplateState(key, value) {
297
+ if (this.$writeTemplateState(key, value)) {
298
+ this.$update(key);
299
+ }
300
+ }
301
+ $writeTemplateState(key, value) {
302
+ if (!this.$templateState) {
303
+ this.$templateState = Object.create(null);
304
+ }
305
+ if (Object.is(this.$templateState[key], value))
306
+ return false;
307
+ this.$templateState[key] = value;
308
+ return true;
309
+ }
310
+ $templateMeta() {
311
+ if (this.$meta)
312
+ return this.$meta;
313
+ const fromCtor = templateMetaByCtor.get(this.constructor);
314
+ if (fromCtor)
315
+ return fromCtor;
316
+ const tagName = this.tagName;
317
+ return tagName ? getTemplate(tagName.toLowerCase()) : undefined;
318
+ }
319
+ $templateRootForAttribute(name) {
320
+ const meta = this.$templateMeta();
321
+ return meta ? templateRootForAttribute(meta, name) : undefined;
322
+ }
323
+ $usesTemplateState(key) {
324
+ const meta = this.$templateMeta();
325
+ return !!meta && templateHasRoot(meta, key) && !hasAuthoredMember(this, key);
326
+ }
327
+ $setStateKey(key, value) {
328
+ if (this.$observableNames().has(key)) {
329
+ this[key] = value;
330
+ return true;
331
+ }
332
+ if (this.$usesTemplateState(key)) {
333
+ this.$setTemplateState(key, value);
334
+ return true;
335
+ }
336
+ return false;
337
+ }
338
+ $applySSRState() {
339
+ const state = window.__webui?.state;
340
+ if (!state || typeof state !== 'object')
341
+ return;
342
+ const observableNames = this.$observableNames();
343
+ const keys = Object.keys(state);
344
+ for (let i = 0; i < keys.length; i++) {
345
+ const key = keys[i];
346
+ if (observableNames.has(key)) {
347
+ if (!this.$shouldApplySSRState(key))
348
+ continue;
349
+ this[`_${key}`] = state[key];
350
+ }
351
+ else if (this.$usesTemplateState(key) && this.$shouldApplyTemplateStateFromSSR(key)) {
352
+ this.$writeTemplateState(key, state[key]);
353
+ }
354
+ }
355
+ }
356
+ $update(path) {
357
+ if (!this.$ready || !this.$root) {
358
+ if (DEV && path && this.isConnected)
359
+ this.$recordPreReadyWrite(path);
360
+ return;
361
+ }
362
+ if (!this.$pathIndex)
363
+ this.$buildPathIndex();
364
+ if (path && this.$pathIndex) {
365
+ const entry = this.$pathIndex.get(path);
366
+ if (entry) {
367
+ if (!this.$dirtyPaths)
368
+ this.$dirtyPaths = new Set();
369
+ this.$dirtyPaths.add(path);
370
+ if (!this.$pendingFlush) {
371
+ this.$pendingFlush = true;
372
+ queueMicrotask(() => this.$flush());
373
+ }
374
+ return;
375
+ }
376
+ }
377
+ this.$dirtyPaths = null;
378
+ this.$updateInstance(this.$root);
379
+ }
380
+ $flushUpdates() {
381
+ if (this.$pendingFlush)
382
+ this.$flush();
383
+ }
384
+ $flush() {
385
+ if (!this.$ready || !this.$root || !this.$pathIndex) {
386
+ this.$dirtyPaths = null;
387
+ this.$pendingFlush = false;
388
+ return;
389
+ }
390
+ while (this.$dirtyPaths && this.$dirtyPaths.size > 0) {
391
+ const dirty = this.$dirtyPaths;
392
+ this.$dirtyPaths = null;
393
+ for (const path of dirty) {
394
+ const entry = this.$pathIndex.get(path);
395
+ if (entry) {
396
+ this.$updateBindings(entry.texts, entry.attrs, entry.conds, entry.repeats);
397
+ }
398
+ }
399
+ if (this.$wildcardBindings) {
400
+ const wc = this.$wildcardBindings;
401
+ this.$updateBindings(wc.texts, wc.attrs, wc.conds, wc.repeats);
402
+ }
403
+ }
404
+ this.$pendingFlush = false;
405
+ }
406
+ $recordPreReadyWrite(path) {
407
+ if (!this.$preReadyWrites)
408
+ this.$preReadyWrites = new Set();
409
+ this.$preReadyWrites.add(path);
410
+ }
411
+ $checkHydrationMismatch() {
412
+ if (!DEV)
413
+ return;
414
+ const writes = this.$preReadyWrites;
415
+ this.$preReadyWrites = null;
416
+ if (!writes || writes.size === 0 || !this.$root)
417
+ return;
418
+ if (!this.$pathIndex)
419
+ this.$buildPathIndex();
420
+ const index = this.$pathIndex;
421
+ if (!index)
422
+ return;
423
+ const ctx = {
424
+ resolver: this.$resolver,
425
+ resolveParts: (parts, scope) => this.$resolveParts(parts, scope),
426
+ resolveValue: (path, scope) => this.$resolveValue(path, scope),
427
+ };
428
+ const tag = this.tagName.toLowerCase();
429
+ void import('./hydration-mismatch.js').then((m) => m.reportHydrationMismatch(tag, writes, index, ctx));
430
+ }
431
+ $resolve(root, path, pathStart = 0) {
432
+ let cur = root;
433
+ for (let i = 0; i < pathStart; i++) {
434
+ const child = cur.childNodes[path[i]];
435
+ if (!child)
436
+ return null;
437
+ cur = child;
438
+ }
439
+ for (let i = pathStart; i < path.length; i++) {
440
+ const child = cur.childNodes[path[i]];
441
+ if (!child)
442
+ return null;
443
+ cur = child;
444
+ }
445
+ return cur;
446
+ }
447
+ $resolveSSR(ssrRoot, tplRoot, path, pathStart = 0) {
448
+ let ssr = ssrRoot;
449
+ let tpl = tplRoot;
450
+ for (let i = 0; i < pathStart; i++) {
451
+ const tplChild = tpl.childNodes[path[i]];
452
+ if (!tplChild)
453
+ return null;
454
+ tpl = tplChild;
455
+ }
456
+ for (let i = pathStart; i < path.length; i++) {
457
+ const idx = path[i];
458
+ const tplChild = tpl.childNodes[idx];
459
+ if (!tplChild)
460
+ return null;
461
+ const ordinals = getTplOrdinals(tpl);
462
+ const entry = ordinals.get(idx);
463
+ if (!entry)
464
+ return null;
465
+ const [nodeType, ordinal] = entry;
466
+ const child = findByOrdinal(ssr, nodeType, ordinal);
467
+ if (!child)
468
+ return null;
469
+ ssr = child;
470
+ tpl = tplChild;
471
+ }
472
+ return ssr;
473
+ }
474
+ $parseTemplate(meta) {
475
+ let cached = templateCache.get(meta);
476
+ if (cached)
477
+ return cached.cloneNode(true);
478
+ const tpl = document.createElement('template');
479
+ tpl.innerHTML = meta.h;
480
+ templateCache.set(meta, tpl.content);
481
+ return tpl.content.cloneNode(true);
482
+ }
483
+ $createStagingRoot(meta) {
484
+ const wrapper = document.createElement('div');
485
+ const fragment = this.$parseTemplate(meta);
486
+ wrapper.appendChild(fragment);
487
+ customElements.upgrade(wrapper);
488
+ return wrapper;
489
+ }
490
+ $appendStagedChildren(root, stagingRoot) {
491
+ const first = stagingRoot.firstChild;
492
+ if (!first)
493
+ return;
494
+ if (!first.nextSibling) {
495
+ root.appendChild(first);
496
+ return;
497
+ }
498
+ const fragment = document.createDocumentFragment();
499
+ while (stagingRoot.firstChild) {
500
+ fragment.appendChild(stagingRoot.firstChild);
501
+ }
502
+ root.appendChild(fragment);
503
+ }
504
+ $releaseStagingRepeatContainers(instance, stagingRoot) {
505
+ if (!instance || !stagingRoot)
506
+ return;
507
+ if (instance.repeats.length === 0 && instance.conds.length === 0)
508
+ return;
509
+ const stack = [instance];
510
+ while (stack.length > 0) {
511
+ const current = stack.pop();
512
+ if (!current)
513
+ continue;
514
+ for (let i = 0; i < current.repeats.length; i++) {
515
+ const repeat = current.repeats[i];
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
+ }
522
+ for (let i = 0; i < current.conds.length; i++) {
523
+ const child = current.conds[i].instance;
524
+ if (child)
525
+ stack.push(child);
526
+ }
527
+ }
528
+ }
529
+ $wire(root, meta, scope) {
530
+ const instance = {
531
+ scope, nodes: childNodesArray(root),
532
+ texts: [], attrs: [], conds: [], repeats: [],
533
+ };
534
+ const textRefs = new Array(meta.tx?.length ?? 0);
535
+ let textRefCount = 0;
536
+ if (meta.tx) {
537
+ for (let i = 0; i < meta.tx.length; i++) {
538
+ const entry = meta.tx[i];
539
+ const [slot, parts] = entry;
540
+ const raw = entry[2] === 1;
541
+ const [parentPath, beforeIndex] = slot;
542
+ const parent = parentPath.length > 0 ? this.$resolve(root, parentPath) : root;
543
+ if (!parent || (parent.nodeType !== 1 && parent.nodeType !== 11))
544
+ continue;
545
+ textRefs[textRefCount] = { parent, ref: parent.childNodes[beforeIndex] || null, parts, raw };
546
+ textRefCount += 1;
547
+ }
548
+ }
549
+ const condRefs = new Array(meta.c?.length ?? 0);
550
+ let condRefCount = 0;
551
+ if (meta.c) {
552
+ for (let i = 0; i < meta.c.length; i++) {
553
+ const [condition, blockIndex, slotMeta] = meta.c[i];
554
+ const [parentPath, beforeIndex] = slotMeta;
555
+ const parent = parentPath.length > 0 ? this.$resolve(root, parentPath) : root;
556
+ if (!parent || (parent.nodeType !== 1 && parent.nodeType !== 11))
557
+ continue;
558
+ condRefs[condRefCount] = { parent, ref: parent.childNodes[beforeIndex] || null, condition: condition, blockIndex };
559
+ condRefCount += 1;
560
+ }
561
+ }
562
+ const repRefs = new Array(meta.r?.length ?? 0);
563
+ let repRefCount = 0;
564
+ if (meta.r) {
565
+ for (let i = 0; i < meta.r.length; i++) {
566
+ const [collection, itemVar, blockIndex, slotMeta] = meta.r[i];
567
+ const [parentPath, beforeIndex] = slotMeta;
568
+ const parent = parentPath.length > 0 ? this.$resolve(root, parentPath) : root;
569
+ if (!parent || (parent.nodeType !== 1 && parent.nodeType !== 11))
570
+ continue;
571
+ repRefs[repRefCount] = { parent, ref: parent.childNodes[beforeIndex] || null, collection, itemVar, blockIndex };
572
+ repRefCount += 1;
573
+ }
574
+ }
575
+ this.$wireAttrs(instance, meta, scope, (p) => this.$resolve(root, p));
576
+ this.$finalize(instance, root, meta, (r, p) => this.$resolve(r, p), scope);
577
+ for (let i = 0; i < textRefCount; i++) {
578
+ const t = textRefs[i];
579
+ const anchor = document.createComment('');
580
+ t.parent.insertBefore(anchor, t.ref);
581
+ if (t.raw) {
582
+ const container = document.createElement('span');
583
+ t.parent.insertBefore(container, anchor);
584
+ const textNode = document.createTextNode('');
585
+ instance.texts.push({ node: textNode, parts: t.parts, scope, raw: true, rawParent: container });
586
+ }
587
+ else {
588
+ const textNode = document.createTextNode('');
589
+ t.parent.insertBefore(textNode, anchor);
590
+ instance.texts.push({ node: textNode, parts: t.parts, scope });
591
+ }
592
+ }
593
+ for (let i = 0; i < condRefCount; i++) {
594
+ const c = condRefs[i];
595
+ const anchor = document.createComment('');
596
+ c.parent.insertBefore(anchor, c.ref);
597
+ instance.conds.push({ condition: c.condition, blockIndex: c.blockIndex, anchor, scope, instance: null });
598
+ }
599
+ for (let i = 0; i < repRefCount; i++) {
600
+ const r = repRefs[i];
601
+ const anchor = document.createComment('');
602
+ r.parent.insertBefore(anchor, r.ref);
603
+ const { keyAttribute, keyPath } = this.$repeatMaps(r.blockIndex, r.itemVar);
604
+ instance.repeats.push({
605
+ markerId: i, collection: r.collection, itemVar: r.itemVar, blockIndex: r.blockIndex,
606
+ container: r.parent, start: anchor, end: null,
607
+ scope, owner: instance, instances: [], rootTag: null,
608
+ keyAttribute, keyPath,
609
+ });
610
+ }
611
+ for (let i = 0; i < instance.conds.length; i++)
612
+ this.$toggleCond(instance.conds[i]);
613
+ return instance;
614
+ }
615
+ $hydrate(ssrRoot, meta, tplDom, scope, pathStart = 0) {
616
+ const instance = {
617
+ scope,
618
+ nodes: pathStart > 0 ? [ssrRoot] : childNodesArray(ssrRoot),
619
+ texts: [], attrs: [], conds: [], repeats: [],
620
+ };
621
+ const staleMarkers = [];
622
+ if (meta.tx) {
623
+ for (let i = 0; i < meta.tx.length; i++) {
624
+ const entry = meta.tx[i];
625
+ const [slot, parts] = entry;
626
+ const raw = entry[2] === 1;
627
+ const [parentPath, beforeIndex] = slot;
628
+ const ssrParent = this.$resolveSSR(ssrRoot, tplDom, parentPath, pathStart);
629
+ if (!ssrParent)
630
+ continue;
631
+ const tplParent = this.$resolve(tplDom, parentPath, pathStart);
632
+ if (!tplParent)
633
+ continue;
634
+ if (raw) {
635
+ const rawParent = ssrParent;
636
+ const textNode = document.createTextNode('');
637
+ instance.texts.push({ node: textNode, parts, scope, raw: true, rawParent });
638
+ }
639
+ else {
640
+ let textNode = this.$findSSRText(ssrParent, tplParent, beforeIndex);
641
+ if (!textNode) {
642
+ textNode = document.createTextNode('');
643
+ const insertRef = this.$findSSRSlotRef(ssrParent, tplParent, beforeIndex);
644
+ ssrParent.insertBefore(textNode, insertRef);
645
+ }
646
+ if (textNode)
647
+ instance.texts.push({ node: textNode, parts, scope });
648
+ }
649
+ }
650
+ }
651
+ this.$wireAttrs(instance, meta, scope, (p) => this.$resolveSSR(ssrRoot, tplDom, p, pathStart));
652
+ if (meta.c) {
653
+ let lastCondMarker = null;
654
+ let lastCondParent = null;
655
+ for (let i = 0; i < meta.c.length; i++) {
656
+ const [condition, blockIndex, slotMeta] = meta.c[i];
657
+ const [parentPath] = slotMeta;
658
+ const ssrParent = this.$resolveSSR(ssrRoot, tplDom, parentPath, pathStart) ?? ssrRoot;
659
+ const blockMeta = this.$block(blockIndex);
660
+ const shown = condition[0](this.$resolver, scope);
661
+ let condInstance = null;
662
+ if (ssrParent !== lastCondParent) {
663
+ lastCondMarker = null;
664
+ lastCondParent = ssrParent;
665
+ }
666
+ const marker = this.$findMarker(ssrParent, MARKER_COND_START, lastCondMarker);
667
+ let condAnchor;
668
+ if (marker) {
669
+ condAnchor = marker;
670
+ }
671
+ else {
672
+ condAnchor = document.createComment('');
673
+ const [, beforeIndex] = slotMeta;
674
+ const insertRef = ssrParent.childNodes[beforeIndex ?? ssrParent.childNodes.length] ?? null;
675
+ ssrParent.insertBefore(condAnchor, insertRef);
676
+ }
677
+ if (marker)
678
+ lastCondMarker = marker;
679
+ const ssrContentPresent = marker && blockMeta && this.$hasContentAfterMarker(condAnchor, MARKER_COND_END);
680
+ if (blockMeta && (shown || ssrContentPresent)) {
681
+ if (marker) {
682
+ condInstance = this.$hydrateCondContent(condAnchor, blockMeta, scope);
683
+ }
684
+ }
685
+ if (marker) {
686
+ const lastNode = condInstance ? condInstance.nodes[condInstance.nodes.length - 1] : condAnchor;
687
+ const endMarker = lastNode?.nextSibling;
688
+ if (endMarker && endMarker.nodeType === 8 && endMarker.data === MARKER_COND_END) {
689
+ staleMarkers.push(endMarker);
690
+ }
691
+ }
692
+ instance.conds.push({
693
+ condition: condition, blockIndex,
694
+ anchor: condAnchor,
695
+ scope, instance: condInstance,
696
+ });
697
+ }
698
+ }
699
+ if (meta.r) {
700
+ let lastRepMarker = null;
701
+ let lastRepParent = null;
702
+ for (let i = 0; i < meta.r.length; i++) {
703
+ const [collection, itemVar, blockIndex, slotMeta] = meta.r[i];
704
+ const [parentPath] = slotMeta;
705
+ const ssrParent = this.$resolveSSR(ssrRoot, tplDom, parentPath, pathStart) ?? ssrRoot;
706
+ if (ssrParent !== lastRepParent) {
707
+ lastRepMarker = null;
708
+ lastRepParent = ssrParent;
709
+ }
710
+ const blockMeta = this.$block(blockIndex);
711
+ const { keyAttribute, keyPath } = this.$repeatMaps(blockIndex, itemVar);
712
+ const blockTplDom = blockMeta ? getTemplateDom(blockMeta) : null;
713
+ const rootTag = blockMeta && blockTplDom?.childNodes.length === 1 && blockTplDom.children.length === 1
714
+ ? this.$rootTag(blockMeta)
715
+ : null;
716
+ const marker = this.$findMarker(ssrParent, MARKER_REPEAT_START, lastRepMarker);
717
+ let anchor;
718
+ if (marker) {
719
+ anchor = marker;
720
+ }
721
+ else {
722
+ anchor = document.createComment('');
723
+ const [, beforeIndex] = slotMeta;
724
+ const tplParent = this.$resolve(tplDom, parentPath, pathStart);
725
+ const staticCount = tplParent ? tplParent.childNodes.length : 0;
726
+ const insertRef = ssrParent.childNodes[Math.min(beforeIndex ?? staticCount, ssrParent.childNodes.length)] ?? null;
727
+ ssrParent.insertBefore(anchor, insertRef);
728
+ }
729
+ lastRepMarker = anchor;
730
+ const repeatInsts = [];
731
+ const itemsArr = this.$resolveValue(collection, scope);
732
+ const items = Array.isArray(itemsArr) ? itemsArr : [];
733
+ const { items: itemMarkers, end: endMarker } = marker
734
+ ? collectItemMarkers(anchor)
735
+ : { items: [], end: null };
736
+ if (blockMeta && blockTplDom && items.length > 0 && anchor.parentNode && itemMarkers.length > 0) {
737
+ if (itemMarkers.length !== items.length) {
738
+ console.warn(`[webui] hydration: repeat marker count (${itemMarkers.length}) ≠ data length (${items.length}) for "${collection}"`);
739
+ }
740
+ const limit = Math.min(itemMarkers.length, items.length);
741
+ for (let j = 0; j < limit; j++) {
742
+ const itemValue = items[j];
743
+ const itemScope = { name: itemVar, value: itemValue, parent: scope };
744
+ if (rootTag) {
745
+ const itemEl = nextElement(itemMarkers[j]);
746
+ if (itemEl) {
747
+ const key = keyAttribute !== undefined
748
+ ? itemEl.getAttribute(keyAttribute)
749
+ : String(j);
750
+ const childInstance = this.$hydrate(itemEl, blockMeta, blockTplDom, itemScope, 1);
751
+ repeatInsts.push({ key, value: itemValue, instance: childInstance });
752
+ }
753
+ }
754
+ else {
755
+ const itemParent = itemMarkers[j].parentNode;
756
+ const nextBound = j + 1 < itemMarkers.length ? itemMarkers[j + 1] : endMarker;
757
+ const wrapper = document.createElement('div');
758
+ let cursor = itemMarkers[j].nextSibling;
759
+ while (cursor && cursor !== nextBound) {
760
+ const next = cursor.nextSibling;
761
+ wrapper.appendChild(cursor);
762
+ cursor = next;
763
+ }
764
+ const inst = this.$hydrate(wrapper, blockMeta, blockTplDom, itemScope);
765
+ inst.nodes = childNodesArray(wrapper);
766
+ let afterNode = itemMarkers[j];
767
+ for (let nodeIndex = 0; nodeIndex < inst.nodes.length; nodeIndex++) {
768
+ const node = inst.nodes[nodeIndex];
769
+ itemParent?.insertBefore(node, afterNode.nextSibling);
770
+ afterNode = node;
771
+ }
772
+ const key = keyPath ? String(dotWalk(itemValue, keyPath, 0) ?? '') : null;
773
+ repeatInsts.push({ key, value: itemValue, instance: inst });
774
+ }
775
+ }
776
+ for (let m = 0; m < itemMarkers.length; m++) {
777
+ staleMarkers.push(itemMarkers[m]);
778
+ }
779
+ }
780
+ if (endMarker)
781
+ staleMarkers.push(endMarker);
782
+ instance.repeats.push({
783
+ markerId: i, collection, itemVar, blockIndex,
784
+ container: (anchor.parentNode ?? ssrRoot),
785
+ start: anchor, end: null,
786
+ scope, owner: instance, instances: repeatInsts, rootTag,
787
+ keyAttribute, keyPath, synced: true,
788
+ });
789
+ }
790
+ }
791
+ this.$finalize(instance, ssrRoot, meta, (r, p) => this.$resolveSSR(r, tplDom, p, pathStart), scope);
792
+ for (let i = 0; i < staleMarkers.length; i++) {
793
+ staleMarkers[i].parentNode?.removeChild(staleMarkers[i]);
794
+ }
795
+ return instance;
796
+ }
797
+ $collectBetween(start, endData) {
798
+ const nodes = [];
799
+ let node = start.nextSibling;
800
+ while (node) {
801
+ if (node.nodeType === 8 && node.data === endData)
802
+ break;
803
+ nodes.push(node);
804
+ node = node.nextSibling;
805
+ }
806
+ return nodes;
807
+ }
808
+ $hydrateCondContent(condAnchor, blockMeta, scope) {
809
+ const rootTag = this.$rootTag(blockMeta);
810
+ const tplDom = getTemplateDom(blockMeta);
811
+ if (rootTag && tplDom.children.length === 1) {
812
+ const el = nextElement(condAnchor);
813
+ if (el) {
814
+ return this.$hydrate(el, blockMeta, tplDom, scope, 1);
815
+ }
816
+ return null;
817
+ }
818
+ const condNodes = this.$collectBetween(condAnchor, MARKER_COND_END);
819
+ if (condNodes.length === 0)
820
+ return null;
821
+ const wrapper = document.createElement('div');
822
+ for (let cn = 0; cn < condNodes.length; cn++)
823
+ wrapper.appendChild(condNodes[cn]);
824
+ const inst = this.$hydrate(wrapper, blockMeta, tplDom, scope);
825
+ inst.nodes = childNodesArray(wrapper);
826
+ let afterNode = condAnchor;
827
+ for (let cn = 0; cn < inst.nodes.length; cn++) {
828
+ condAnchor.parentNode?.insertBefore(inst.nodes[cn], afterNode.nextSibling);
829
+ afterNode = inst.nodes[cn];
830
+ }
831
+ return inst;
832
+ }
833
+ $findMarker(parent, data, after) {
834
+ let child = after ? after.nextSibling : parent.firstChild;
835
+ while (child) {
836
+ if (child.nodeType === 8 && child.data === data) {
837
+ return child;
838
+ }
839
+ child = child.nextSibling;
840
+ }
841
+ return null;
842
+ }
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
+ $findSSRText(ssrParent, tplParent, beforeIndex) {
854
+ const ordinals = getTplOrdinals(tplParent);
855
+ let textOrd = 0;
856
+ for (let k = 0; k < beforeIndex; k++) {
857
+ const entry = ordinals.get(k);
858
+ if (entry && entry[0] === 3)
859
+ textOrd++;
860
+ }
861
+ const found = findByOrdinal(ssrParent, 3, textOrd);
862
+ if (found)
863
+ return found;
864
+ let child = ssrParent.firstChild;
865
+ while (child) {
866
+ if (child.nodeType === 3 && child.data && child.data.trim()) {
867
+ return child;
868
+ }
869
+ child = child.nextSibling;
870
+ }
871
+ return null;
872
+ }
873
+ $findSSRSlotRef(ssrParent, tplParent, beforeIndex) {
874
+ const ordinals = getTplOrdinals(tplParent);
875
+ const children = tplParent.childNodes;
876
+ for (let i = beforeIndex; i < children.length; i++) {
877
+ const entry = ordinals.get(i);
878
+ if (!entry)
879
+ continue;
880
+ return findByOrdinal(ssrParent, entry[0], entry[1]);
881
+ }
882
+ return null;
883
+ }
884
+ $rootTag(meta) {
885
+ let cached = rootTagCache.get(meta);
886
+ if (cached !== undefined)
887
+ return cached;
888
+ const h = meta.h;
889
+ if (!h || h.charCodeAt(0) !== 60) {
890
+ rootTagCache.set(meta, null);
891
+ return null;
892
+ }
893
+ let end = 1;
894
+ while (end < h.length) {
895
+ const c = h.charCodeAt(end);
896
+ if (c === 32 || c === 62 || c === 47)
897
+ break;
898
+ end++;
899
+ }
900
+ const tag = h.slice(1, end).toLowerCase();
901
+ rootTagCache.set(meta, tag);
902
+ return tag;
903
+ }
904
+ $wireAttrs(instance, meta, scope, resolve) {
905
+ if (!meta.a || !meta.ag)
906
+ return;
907
+ for (let g = 0; g < meta.ag.length; g++) {
908
+ const [targetPath, start, count] = meta.ag[g];
909
+ const el = resolve(targetPath);
910
+ if (!el || el.nodeType !== 1)
911
+ continue;
912
+ for (let j = 0; j < count; j++) {
913
+ const entry = meta.a[start + j];
914
+ if (entry)
915
+ instance.attrs.push(this.$makeAttr(el, entry, scope));
916
+ }
917
+ }
918
+ }
919
+ $finalize(_instance, _root, _meta, _resolver, _scope) { }
920
+ $makeAttr(el, entry, scope) {
921
+ const name = entry[0];
922
+ const kind = entry[1];
923
+ if (kind === ATTR_KIND_BOOLEAN)
924
+ return { element: el, name, kind, condition: entry[2], scope };
925
+ if (kind === ATTR_KIND_TEMPLATE)
926
+ return { element: el, name, kind, parts: entry[2], scope };
927
+ return { element: el, name, kind: kind, path: entry[2] || '', scope };
928
+ }
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
+ $buildPathIndex() {
956
+ if (!this.$root)
957
+ return;
958
+ const observableNames = this.$observableNames();
959
+ const index = new Map();
960
+ const ensure = (key) => {
961
+ let e = index.get(key);
962
+ if (!e) {
963
+ e = { texts: [], attrs: [], conds: [], repeats: [] };
964
+ index.set(key, e);
965
+ }
966
+ return e;
967
+ };
968
+ const keyFor = (path) => {
969
+ const dot = path.indexOf('.');
970
+ const root = dot > -1 ? path.slice(0, dot) : path;
971
+ return observableNames.has(root) || this.$usesTemplateState(root) ? root : '*';
972
+ };
973
+ const isLocalPath = (path, scope) => {
974
+ const dot = path.indexOf('.');
975
+ const root = dot > -1 ? path.slice(0, dot) : path;
976
+ let current = scope;
977
+ while (current) {
978
+ if (current.name === root)
979
+ return true;
980
+ current = current.parent;
981
+ }
982
+ return false;
983
+ };
984
+ const visit = (instance) => {
985
+ for (const t of instance.texts) {
986
+ if (t.parts) {
987
+ for (const p of t.parts) {
988
+ if (typeof p !== 'string' && !isLocalPath(p[0], t.scope)) {
989
+ ensure(keyFor(p[0])).texts.push(t);
990
+ }
991
+ }
992
+ }
993
+ else if (t.path && !isLocalPath(t.path, t.scope)) {
994
+ ensure(keyFor(t.path)).texts.push(t);
995
+ }
996
+ }
997
+ for (const a of instance.attrs) {
998
+ if (a.path && !isLocalPath(a.path, a.scope)) {
999
+ ensure(keyFor(a.path)).attrs.push(a);
1000
+ }
1001
+ if (a.parts) {
1002
+ for (const p of a.parts) {
1003
+ if (typeof p !== 'string' && !isLocalPath(p[0], a.scope)) {
1004
+ ensure(keyFor(p[0])).attrs.push(a);
1005
+ }
1006
+ }
1007
+ }
1008
+ if (a.condition) {
1009
+ for (const p of a.condition[1]) {
1010
+ if (!isLocalPath(p, a.scope))
1011
+ ensure(keyFor(p)).attrs.push(a);
1012
+ }
1013
+ }
1014
+ }
1015
+ for (const c of instance.conds) {
1016
+ for (const p of c.condition[1]) {
1017
+ if (!isLocalPath(p, c.scope))
1018
+ ensure(keyFor(p)).conds.push(c);
1019
+ }
1020
+ if (c.instance)
1021
+ visit(c.instance);
1022
+ }
1023
+ for (const rep of instance.repeats) {
1024
+ if (!isLocalPath(rep.collection, rep.scope)) {
1025
+ ensure(keyFor(rep.collection)).repeats.push(rep);
1026
+ }
1027
+ for (let i = 0; i < rep.instances.length; i++) {
1028
+ visit(rep.instances[i].instance);
1029
+ }
1030
+ }
1031
+ };
1032
+ visit(this.$root);
1033
+ const wc = index.get('*');
1034
+ if (wc) {
1035
+ index.delete('*');
1036
+ this.$wildcardBindings = wc;
1037
+ }
1038
+ else {
1039
+ this.$wildcardBindings = null;
1040
+ }
1041
+ this.$pathIndex = index;
1042
+ }
1043
+ $updateBindings(texts, attrs, conds, repeats) {
1044
+ for (let i = 0; i < texts.length; i++)
1045
+ this.$patchText(texts[i]);
1046
+ for (let i = 0; i < attrs.length; i++)
1047
+ this.$patchAttr(attrs[i]);
1048
+ for (let i = 0; i < conds.length; i++)
1049
+ this.$toggleCond(conds[i]);
1050
+ for (let i = 0; i < repeats.length; i++) {
1051
+ syncRepeat(this, repeats[i]);
1052
+ }
1053
+ }
1054
+ $updateInstance(instance) {
1055
+ this.$updateBindings(instance.texts, instance.attrs, instance.conds, instance.repeats);
1056
+ }
1057
+ $patchText(b) {
1058
+ let val;
1059
+ if (b.parts) {
1060
+ val = this.$resolveParts(b.parts, b.scope);
1061
+ }
1062
+ else if (b.path) {
1063
+ const raw = this.$resolveValue(b.path, b.scope);
1064
+ val = raw == null ? '' : String(raw);
1065
+ }
1066
+ else {
1067
+ return;
1068
+ }
1069
+ if (b.raw && b.rawParent) {
1070
+ if (b.rawParent.innerHTML !== val)
1071
+ b.rawParent.innerHTML = val;
1072
+ }
1073
+ else {
1074
+ if (b.node.data !== val)
1075
+ b.node.data = val;
1076
+ }
1077
+ }
1078
+ $patchAttr(b) {
1079
+ const el = b.element;
1080
+ switch (b.kind) {
1081
+ case ATTR_KIND_COMPLEX: {
1082
+ const v = this.$resolveValue(b.path, b.scope);
1083
+ const target = el;
1084
+ const setStateKey = target[WEBUI_SET_STATE_KEY];
1085
+ if (typeof setStateKey === 'function') {
1086
+ if (setStateKey.call(el, b.name, v)) {
1087
+ const flush = target['$flushUpdates'];
1088
+ if (typeof flush === 'function')
1089
+ flush.call(el);
1090
+ break;
1091
+ }
1092
+ }
1093
+ target[b.name] = v;
1094
+ break;
1095
+ }
1096
+ case ATTR_KIND_BOOLEAN: {
1097
+ const show = b.condition[0](this.$resolver, b.scope);
1098
+ if (show)
1099
+ el.setAttribute(b.name, '');
1100
+ else
1101
+ el.removeAttribute(b.name);
1102
+ if (b.name === 'checked' || b.name === 'selected' || b.name === 'disabled') {
1103
+ el[b.name] = show;
1104
+ }
1105
+ break;
1106
+ }
1107
+ case ATTR_KIND_TEMPLATE: {
1108
+ const v = this.$resolveParts(b.parts, b.scope);
1109
+ if (el.getAttribute(b.name) !== v)
1110
+ el.setAttribute(b.name, v);
1111
+ break;
1112
+ }
1113
+ default: {
1114
+ const v = this.$resolveValue(b.path, b.scope);
1115
+ const s = v == null ? '' : String(v);
1116
+ if (b.name === 'checked' || b.name === 'selected') {
1117
+ el[b.name] = !!v && v !== 'false' && v !== '0';
1118
+ }
1119
+ else if (b.name === 'value') {
1120
+ if (el.value !== s)
1121
+ el.value = s;
1122
+ }
1123
+ else {
1124
+ if (el.getAttribute(b.name) !== s)
1125
+ el.setAttribute(b.name, s);
1126
+ }
1127
+ break;
1128
+ }
1129
+ }
1130
+ }
1131
+ $toggleCond(c) {
1132
+ const show = c.condition[0](this.$resolver, c.scope);
1133
+ if (show) {
1134
+ if (!c.instance) {
1135
+ c.instance = this.$createBlockInstance(c.blockIndex, c.scope);
1136
+ if (c.instance) {
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
+ }
1142
+ }
1143
+ else {
1144
+ this.$updateInstance(c.instance);
1145
+ }
1146
+ }
1147
+ else if (c.instance) {
1148
+ this.$removeInstance(c.instance);
1149
+ c.instance = null;
1150
+ }
1151
+ }
1152
+ $resolveValue(path, scope) {
1153
+ let frame = scope;
1154
+ while (frame) {
1155
+ if (path === frame.name)
1156
+ return frame.value;
1157
+ if (path.length > frame.name.length && path.charCodeAt(frame.name.length) === 46 && path.startsWith(frame.name)) {
1158
+ return dotWalk(frame.value, path, frame.name.length + 1);
1159
+ }
1160
+ frame = frame.parent;
1161
+ }
1162
+ const dot = path.indexOf('.');
1163
+ if (dot === -1)
1164
+ return this.$resolveComponentRoot(path);
1165
+ return dotWalk(this.$resolveComponentRoot(path.substring(0, dot)), path, dot + 1);
1166
+ }
1167
+ $resolveComponentRoot(root) {
1168
+ const instance = this;
1169
+ if (this.$templateState &&
1170
+ Object.prototype.hasOwnProperty.call(this.$templateState, root) &&
1171
+ !hasAuthoredMember(this, root)) {
1172
+ return this.$templateState[root];
1173
+ }
1174
+ return instance[root];
1175
+ }
1176
+ $resolveParts(parts, scope) {
1177
+ let result = '';
1178
+ for (let i = 0; i < parts.length; i++) {
1179
+ const p = parts[i];
1180
+ if (typeof p === 'string') {
1181
+ result += p;
1182
+ continue;
1183
+ }
1184
+ const v = this.$resolveValue(p[0], scope);
1185
+ result += v == null ? '' : String(v);
1186
+ }
1187
+ return result;
1188
+ }
1189
+ $block(blockIndex) {
1190
+ return this.$meta?.b?.[blockIndex];
1191
+ }
1192
+ $createBlockInstance(blockIndex, scope) {
1193
+ const bm = this.$block(blockIndex);
1194
+ if (!bm)
1195
+ return null;
1196
+ const wrapper = this.$createStagingRoot(bm);
1197
+ const inst = this.$wire(wrapper, bm, scope);
1198
+ inst.nodes = childNodesArray(wrapper);
1199
+ this.$updateInstance(inst);
1200
+ if (inst.repeats.length !== 0 || inst.conds.length !== 0) {
1201
+ inst.nodes = childNodesArray(wrapper);
1202
+ this.$releaseStagingRepeatContainers(inst, wrapper);
1203
+ }
1204
+ return inst;
1205
+ }
1206
+ $removeInstance(instance) {
1207
+ this.$teardownInstanceCleanups(instance);
1208
+ for (const n of instance.nodes)
1209
+ n.parentNode?.removeChild(n);
1210
+ for (const c of instance.conds) {
1211
+ if (c.instance)
1212
+ this.$removeInstance(c.instance);
1213
+ }
1214
+ for (const r of instance.repeats) {
1215
+ for (const item of r.instances)
1216
+ this.$removeInstance(item.instance);
1217
+ }
1218
+ }
1219
+ $insertInstanceAfter(cursor, container, instance) {
1220
+ const nodes = instance.nodes;
1221
+ if (nodes.length === 0)
1222
+ return cursor;
1223
+ const ref = cursor ? cursor.nextSibling : container.firstChild;
1224
+ if (nodes[0] === ref)
1225
+ return nodes[nodes.length - 1];
1226
+ const frag = document.createDocumentFragment();
1227
+ for (let i = 0; i < nodes.length; i++)
1228
+ frag.appendChild(nodes[i]);
1229
+ container.insertBefore(frag, ref);
1230
+ return nodes[nodes.length - 1];
1231
+ }
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
+ }