@odoo/owl 3.0.0-alpha.2 → 3.0.0-alpha.21

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (90) hide show
  1. package/README.md +100 -110
  2. package/dist/compile_templates.mjs +2434 -2532
  3. package/dist/compiler.js +2371 -0
  4. package/dist/owl-devtools.zip +0 -0
  5. package/dist/owl.cjs.js +6709 -6616
  6. package/dist/owl.cjs.runtime.js +4480 -0
  7. package/dist/owl.es.js +6697 -6600
  8. package/dist/owl.es.runtime.js +4436 -0
  9. package/dist/owl.iife.js +6710 -6617
  10. package/dist/owl.iife.min.js +1 -1
  11. package/dist/owl.iife.runtime.js +4484 -0
  12. package/dist/owl.iife.runtime.min.js +1 -0
  13. package/dist/types/common/owl_error.d.ts +3 -3
  14. package/dist/types/common/types.d.ts +1 -29
  15. package/dist/types/common/utils.d.ts +8 -8
  16. package/dist/types/compiler/code_generator.d.ts +133 -152
  17. package/dist/types/compiler/index.d.ts +13 -13
  18. package/dist/types/compiler/inline_expressions.d.ts +41 -59
  19. package/dist/types/compiler/parser.d.ts +170 -178
  20. package/dist/types/compiler/standalone/index.d.ts +2 -2
  21. package/dist/types/compiler/standalone/setup_jsdom.d.ts +1 -1
  22. package/dist/types/index.d.ts +1 -1
  23. package/dist/types/owl.d.ts +709 -665
  24. package/dist/types/runtime/app.d.ts +55 -62
  25. package/dist/types/runtime/blockdom/attributes.d.ts +8 -6
  26. package/dist/types/runtime/blockdom/block_compiler.d.ts +21 -21
  27. package/dist/types/runtime/blockdom/config.d.ts +8 -8
  28. package/dist/types/runtime/blockdom/event_catcher.d.ts +7 -7
  29. package/dist/types/runtime/blockdom/events.d.ts +8 -8
  30. package/dist/types/runtime/blockdom/html.d.ts +17 -17
  31. package/dist/types/runtime/blockdom/index.d.ts +25 -26
  32. package/dist/types/runtime/blockdom/list.d.ts +18 -18
  33. package/dist/types/runtime/blockdom/multi.d.ts +17 -17
  34. package/dist/types/runtime/blockdom/text.d.ts +26 -26
  35. package/dist/types/runtime/blockdom/toggler.d.ts +17 -17
  36. package/dist/types/runtime/component.d.ts +17 -28
  37. package/dist/types/runtime/component_node.d.ts +59 -83
  38. package/dist/types/runtime/context.d.ts +36 -0
  39. package/dist/types/runtime/error_handling.d.ts +13 -13
  40. package/dist/types/runtime/event_handling.d.ts +1 -1
  41. package/dist/types/runtime/fibers.d.ts +37 -37
  42. package/dist/types/runtime/hooks.d.ts +32 -57
  43. package/dist/types/runtime/index.d.ts +46 -35
  44. package/dist/types/runtime/lifecycle_hooks.d.ts +10 -12
  45. package/dist/types/runtime/plugin_hooks.d.ts +6 -0
  46. package/dist/types/runtime/plugin_manager.d.ts +36 -0
  47. package/dist/types/runtime/props.d.ts +21 -0
  48. package/dist/types/runtime/reactivity/computations.d.ts +34 -0
  49. package/dist/types/runtime/reactivity/computed.d.ts +6 -0
  50. package/dist/types/runtime/reactivity/effect.d.ts +1 -0
  51. package/dist/types/runtime/reactivity/proxy.d.ts +47 -0
  52. package/dist/types/runtime/reactivity/signal.d.ts +31 -0
  53. package/dist/types/runtime/reactivity.d.ts +57 -46
  54. package/dist/types/runtime/registry.d.ts +24 -15
  55. package/dist/types/runtime/rendering/error_handling.d.ts +13 -0
  56. package/dist/types/runtime/rendering/fibers.d.ts +37 -0
  57. package/dist/types/runtime/rendering/scheduler.d.ts +21 -0
  58. package/dist/types/runtime/rendering/template_helpers.d.ts +51 -0
  59. package/dist/types/runtime/resource.d.ts +18 -0
  60. package/dist/types/runtime/scheduler.d.ts +21 -21
  61. package/dist/types/runtime/status.d.ts +11 -10
  62. package/dist/types/runtime/template_set.d.ts +36 -40
  63. package/dist/types/runtime/types.d.ts +70 -0
  64. package/dist/types/runtime/utils.d.ts +24 -25
  65. package/dist/types/runtime/validation.d.ts +19 -36
  66. package/dist/types/version.d.ts +1 -1
  67. package/package.json +45 -19
  68. package/dist/types/runtime/cancellableContext.d.ts +0 -15
  69. package/dist/types/runtime/cancellablePromise.d.ts +0 -15
  70. package/dist/types/runtime/executionContext.d.ts +0 -0
  71. package/dist/types/runtime/listOperation.d.ts +0 -1
  72. package/dist/types/runtime/plugins.d.ts +0 -39
  73. package/dist/types/runtime/relationalModel/discussModel.d.ts +0 -19
  74. package/dist/types/runtime/relationalModel/discussModelTypes.d.ts +0 -22
  75. package/dist/types/runtime/relationalModel/field.d.ts +0 -20
  76. package/dist/types/runtime/relationalModel/model.d.ts +0 -59
  77. package/dist/types/runtime/relationalModel/modelData.d.ts +0 -18
  78. package/dist/types/runtime/relationalModel/modelRegistry.d.ts +0 -3
  79. package/dist/types/runtime/relationalModel/modelUtils.d.ts +0 -4
  80. package/dist/types/runtime/relationalModel/store.d.ts +0 -16
  81. package/dist/types/runtime/relationalModel/types.d.ts +0 -83
  82. package/dist/types/runtime/relationalModel/util.d.ts +0 -1
  83. package/dist/types/runtime/relationalModel/web/WebDataPoint.d.ts +0 -25
  84. package/dist/types/runtime/relationalModel/web/WebRecord.d.ts +0 -131
  85. package/dist/types/runtime/relationalModel/web/WebStaticList.d.ts +0 -63
  86. package/dist/types/runtime/relationalModel/web/webModel.d.ts +0 -5
  87. package/dist/types/runtime/relationalModel/web/webModelTypes.d.ts +0 -139
  88. package/dist/types/runtime/signals.d.ts +0 -17
  89. package/dist/types/runtime/task.d.ts +0 -12
  90. package/dist/types/utils/registry.d.ts +0 -15
@@ -0,0 +1,4480 @@
1
+ 'use strict';
2
+
3
+ // do not modify manually. This file is generated by the release script.
4
+ const version = "3.0.0-alpha.21";
5
+
6
+ // Custom error class that wraps error that happen in the owl lifecycle
7
+ class OwlError extends Error {
8
+ cause;
9
+ }
10
+
11
+ let contextStack = [];
12
+ function saveContext() {
13
+ const savedStack = contextStack.slice();
14
+ return () => {
15
+ contextStack = savedStack;
16
+ };
17
+ }
18
+ function getContext(type) {
19
+ const context = contextStack.at(-1);
20
+ if (!context) {
21
+ throw new OwlError(`No active context`);
22
+ }
23
+ if (type && type !== context.type) {
24
+ throw new OwlError(`Expected to be in a ${type} context`);
25
+ }
26
+ return context;
27
+ }
28
+ function createAsyncProtection(context, callback) {
29
+ return async function asyncContextProtection(...args) {
30
+ if (context.status > 1 /* STATUS.MOUNTED */) {
31
+ throw new OwlError(`Function called after the end of life of the ${context.type}`);
32
+ }
33
+ const result = await callback.call(this, ...args);
34
+ if (context.status > 1 /* STATUS.MOUNTED */) {
35
+ return new Promise(() => { });
36
+ }
37
+ return result;
38
+ };
39
+ }
40
+ /**
41
+ * Captures the current context and gives methods to run
42
+ * functions within the captured context.
43
+ */
44
+ function useContext() {
45
+ const context = contextStack.at(-1);
46
+ return {
47
+ run(callback) {
48
+ if (context) {
49
+ contextStack.push(context);
50
+ let result;
51
+ try {
52
+ result = callback();
53
+ }
54
+ finally {
55
+ contextStack.pop();
56
+ }
57
+ return result;
58
+ }
59
+ else {
60
+ return callback();
61
+ }
62
+ },
63
+ protectAsync(callback) {
64
+ if (context) {
65
+ callback = createAsyncProtection(context, callback);
66
+ }
67
+ return callback;
68
+ },
69
+ runWithAsyncProtection(callback) {
70
+ if (context) {
71
+ callback = createAsyncProtection(context, callback);
72
+ }
73
+ return callback();
74
+ },
75
+ };
76
+ }
77
+
78
+ /**
79
+ * Creates a batched version of a callback so that all calls to it in the same
80
+ * microtick will only call the original callback once.
81
+ *
82
+ * @param callback the callback to batch
83
+ * @returns a batched version of the original callback
84
+ */
85
+ function batched(callback) {
86
+ let scheduled = false;
87
+ return function batchedCall(...args) {
88
+ if (!scheduled) {
89
+ scheduled = true;
90
+ queueMicrotask(() => {
91
+ scheduled = false;
92
+ callback(...args);
93
+ });
94
+ }
95
+ };
96
+ }
97
+ /**
98
+ * Determine whether the given element is contained in its ownerDocument:
99
+ * either directly or with a shadow root in between.
100
+ */
101
+ function inOwnerDocument(el) {
102
+ if (!el) {
103
+ return false;
104
+ }
105
+ if (el.ownerDocument.contains(el)) {
106
+ return true;
107
+ }
108
+ const rootNode = el.getRootNode();
109
+ return rootNode instanceof ShadowRoot && el.ownerDocument.contains(rootNode.host);
110
+ }
111
+ /**
112
+ * Determine whether the given element is contained in a specific root documnet:
113
+ * either directly or with a shadow root in between or in an iframe.
114
+ */
115
+ function isAttachedToDocument(element, documentElement) {
116
+ let current = element;
117
+ const shadowRoot = documentElement.defaultView.ShadowRoot;
118
+ while (current) {
119
+ if (current === documentElement) {
120
+ return true;
121
+ }
122
+ if (current.parentNode) {
123
+ current = current.parentNode;
124
+ }
125
+ else if (current instanceof shadowRoot && current.host) {
126
+ current = current.host;
127
+ }
128
+ else {
129
+ return false;
130
+ }
131
+ }
132
+ return false;
133
+ }
134
+ function validateTarget(target) {
135
+ // Get the document and HTMLElement corresponding to the target to allow mounting in iframes
136
+ const document = target && target.ownerDocument;
137
+ if (document) {
138
+ if (!document.defaultView) {
139
+ throw new OwlError("Cannot mount a component: the target document is not attached to a window (defaultView is missing)");
140
+ }
141
+ const HTMLElement = document.defaultView.HTMLElement;
142
+ if (target instanceof HTMLElement || target instanceof ShadowRoot) {
143
+ if (!isAttachedToDocument(target, document)) {
144
+ throw new OwlError("Cannot mount a component on a detached dom node");
145
+ }
146
+ return;
147
+ }
148
+ }
149
+ throw new OwlError("Cannot mount component: the target is not a valid DOM element");
150
+ }
151
+ class EventBus extends EventTarget {
152
+ trigger(name, payload) {
153
+ this.dispatchEvent(new CustomEvent(name, { detail: payload }));
154
+ }
155
+ }
156
+ function whenReady(fn) {
157
+ return new Promise(function (resolve) {
158
+ if (document.readyState !== "loading") {
159
+ resolve(true);
160
+ }
161
+ else {
162
+ document.addEventListener("DOMContentLoaded", resolve, false);
163
+ }
164
+ }).then(fn || function () { });
165
+ }
166
+ /*
167
+ * This class just transports the fact that a string is safe
168
+ * to be injected as HTML. Overriding a JS primitive is quite painful though
169
+ * so we need to redfine toString and valueOf.
170
+ */
171
+ class Markup extends String {
172
+ }
173
+ function htmlEscape(str) {
174
+ if (str instanceof Markup) {
175
+ return str;
176
+ }
177
+ if (str === undefined) {
178
+ return markup("");
179
+ }
180
+ if (typeof str === "number") {
181
+ return markup(String(str));
182
+ }
183
+ [
184
+ ["&", "&"],
185
+ ["<", "&lt;"],
186
+ [">", "&gt;"],
187
+ ["'", "&#x27;"],
188
+ ['"', "&quot;"],
189
+ ["`", "&#x60;"],
190
+ ].forEach((pairs) => {
191
+ str = String(str).replace(new RegExp(pairs[0], "g"), pairs[1]);
192
+ });
193
+ return markup(str);
194
+ }
195
+ function markup(valueOrStrings, ...placeholders) {
196
+ if (!Array.isArray(valueOrStrings)) {
197
+ return new Markup(valueOrStrings);
198
+ }
199
+ const strings = valueOrStrings;
200
+ let acc = "";
201
+ let i = 0;
202
+ for (; i < placeholders.length; ++i) {
203
+ acc += strings[i] + htmlEscape(placeholders[i]);
204
+ }
205
+ acc += strings[i];
206
+ return new Markup(acc);
207
+ }
208
+
209
+ var ComputationState;
210
+ (function (ComputationState) {
211
+ ComputationState[ComputationState["EXECUTED"] = 0] = "EXECUTED";
212
+ ComputationState[ComputationState["STALE"] = 1] = "STALE";
213
+ ComputationState[ComputationState["PENDING"] = 2] = "PENDING";
214
+ })(ComputationState || (ComputationState = {}));
215
+ const atomSymbol = Symbol("Atom");
216
+ let observers = [];
217
+ let currentComputation;
218
+ function createComputation(compute, isDerived, state = ComputationState.STALE) {
219
+ return {
220
+ state,
221
+ value: undefined,
222
+ compute,
223
+ sources: new Set(),
224
+ observers: new Set(),
225
+ isDerived,
226
+ };
227
+ }
228
+ function onReadAtom(atom) {
229
+ if (!currentComputation) {
230
+ return;
231
+ }
232
+ currentComputation.sources.add(atom);
233
+ atom.observers.add(currentComputation);
234
+ }
235
+ function onWriteAtom(atom) {
236
+ for (const ctx of atom.observers) {
237
+ if (ctx.state === ComputationState.EXECUTED) {
238
+ if (ctx.isDerived) {
239
+ markDownstream(ctx);
240
+ }
241
+ else {
242
+ observers.push(ctx);
243
+ }
244
+ }
245
+ ctx.state = ComputationState.STALE;
246
+ }
247
+ batchProcessEffects();
248
+ }
249
+ const batchProcessEffects = batched(processEffects);
250
+ function processEffects() {
251
+ for (let i = 0; i < observers.length; i++) {
252
+ updateComputation(observers[i]);
253
+ }
254
+ observers.length = 0;
255
+ }
256
+ function getCurrentComputation() {
257
+ return currentComputation;
258
+ }
259
+ function setComputation(computation) {
260
+ currentComputation = computation;
261
+ }
262
+ function updateComputation(computation) {
263
+ const state = computation.state;
264
+ if (state === ComputationState.EXECUTED) {
265
+ return;
266
+ }
267
+ if (state === ComputationState.PENDING) {
268
+ for (const source of computation.sources) {
269
+ if (!("compute" in source)) {
270
+ continue;
271
+ }
272
+ updateComputation(source);
273
+ }
274
+ // If the state is still not stale after processing the sources, it means
275
+ // none of the dependencies have changed.
276
+ // todo: test it
277
+ if (computation.state !== ComputationState.STALE) {
278
+ computation.state = ComputationState.EXECUTED;
279
+ return;
280
+ }
281
+ }
282
+ // todo: test performance. We might want to avoid removing the atoms to
283
+ // directly re-add them at compute. Especially as we are making them stale.
284
+ removeSources(computation);
285
+ const previousComputation = currentComputation;
286
+ currentComputation = computation;
287
+ computation.value = computation.compute();
288
+ computation.state = ComputationState.EXECUTED;
289
+ currentComputation = previousComputation;
290
+ }
291
+ function removeSources(computation) {
292
+ const sources = computation.sources;
293
+ for (const source of sources) {
294
+ const observers = source.observers;
295
+ observers.delete(computation);
296
+ // todo: if source has no effect observer anymore, remove its sources too
297
+ // todo: test it
298
+ }
299
+ sources.clear();
300
+ }
301
+ function disposeComputation(computation) {
302
+ for (const source of computation.sources) {
303
+ source.observers.delete(computation);
304
+ // Recursively dispose derived computations that lost all observers
305
+ if ("compute" in source &&
306
+ source.isDerived &&
307
+ source.observers.size === 0) {
308
+ disposeComputation(source);
309
+ }
310
+ }
311
+ computation.sources.clear();
312
+ // Mark as stale so it recomputes correctly if ever re-used (shared computed case)
313
+ computation.state = ComputationState.STALE;
314
+ }
315
+ function markDownstream(computation) {
316
+ const stack = [computation];
317
+ let current;
318
+ while ((current = stack.pop())) {
319
+ for (const observer of current.observers) {
320
+ if (observer.state) {
321
+ continue;
322
+ }
323
+ observer.state = ComputationState.PENDING;
324
+ if (observer.isDerived) {
325
+ stack.push(observer);
326
+ }
327
+ else {
328
+ observers.push(observer);
329
+ }
330
+ }
331
+ }
332
+ }
333
+ function untrack(fn) {
334
+ const previousComputation = currentComputation;
335
+ currentComputation = undefined;
336
+ let result;
337
+ try {
338
+ result = fn();
339
+ }
340
+ finally {
341
+ currentComputation = previousComputation;
342
+ }
343
+ return result;
344
+ }
345
+
346
+ // Maps fibers to thrown errors
347
+ const fibersInError = new WeakMap();
348
+ const nodeErrorHandlers = new WeakMap();
349
+ function destroyApp(app, error) {
350
+ try {
351
+ app.destroy();
352
+ }
353
+ catch (e) {
354
+ // mute all errors here because we are in a corrupted state anyway
355
+ }
356
+ const e = Object.assign(new OwlError(`[Owl] Unhandled error. Destroying the root component`), {
357
+ cause: error,
358
+ });
359
+ return e;
360
+ }
361
+ function _handleError(node, error) {
362
+ if (!node) {
363
+ return false;
364
+ }
365
+ const fiber = node.fiber;
366
+ if (fiber) {
367
+ fibersInError.set(fiber, error);
368
+ }
369
+ const errorHandlers = nodeErrorHandlers.get(node);
370
+ if (errorHandlers) {
371
+ let handled = false;
372
+ // execute in the opposite order
373
+ const finalize = () => destroyApp(node.app, error);
374
+ for (let i = errorHandlers.length - 1; i >= 0; i--) {
375
+ try {
376
+ errorHandlers[i](error, finalize);
377
+ handled = true;
378
+ break;
379
+ }
380
+ catch (e) {
381
+ error = e;
382
+ }
383
+ }
384
+ if (handled) {
385
+ return true;
386
+ }
387
+ }
388
+ return _handleError(node.parent, error);
389
+ }
390
+ function handleError(params) {
391
+ let { error } = params;
392
+ const node = "node" in params ? params.node : params.fiber.node;
393
+ const fiber = "fiber" in params ? params.fiber : node.fiber;
394
+ if (fiber) {
395
+ // resets the fibers on components if possible. This is important so that
396
+ // new renderings can be properly included in the initial one, if any.
397
+ let current = fiber;
398
+ do {
399
+ current.node.fiber = current;
400
+ fibersInError.set(current, error);
401
+ current = current.parent;
402
+ } while (current);
403
+ fibersInError.set(fiber.root, error);
404
+ }
405
+ const handled = _handleError(node, error);
406
+ if (!handled) {
407
+ throw destroyApp(node.app, error);
408
+ }
409
+ }
410
+
411
+ function filterOutModifiersFromData(dataList) {
412
+ dataList = dataList.slice();
413
+ const modifiers = [];
414
+ let elm;
415
+ while ((elm = dataList[0]) && typeof elm === "string") {
416
+ modifiers.push(dataList.shift());
417
+ }
418
+ return { modifiers, data: dataList };
419
+ }
420
+ const config$1 = {
421
+ // whether or not blockdom should normalize DOM whenever a block is created.
422
+ // Normalizing dom mean removing empty text nodes (or containing only spaces)
423
+ shouldNormalizeDom: true,
424
+ // this is the main event handler. Every event handler registered with blockdom
425
+ // will go through this function, giving it the data registered in the block
426
+ // and the event
427
+ mainEventHandler: (data, ev, currentTarget) => {
428
+ if (typeof data === "function") {
429
+ data(ev);
430
+ }
431
+ else if (Array.isArray(data)) {
432
+ data = filterOutModifiersFromData(data).data;
433
+ data[0](data[1], ev);
434
+ }
435
+ return false;
436
+ },
437
+ };
438
+
439
+ // -----------------------------------------------------------------------------
440
+ // Toggler node
441
+ // -----------------------------------------------------------------------------
442
+ const txt = document.createTextNode("");
443
+ class VToggler {
444
+ key;
445
+ child;
446
+ parentEl;
447
+ constructor(key, child) {
448
+ this.key = key;
449
+ this.child = child;
450
+ }
451
+ mount(parent, afterNode) {
452
+ this.parentEl = parent;
453
+ this.child.mount(parent, afterNode);
454
+ }
455
+ moveBeforeDOMNode(node, parent) {
456
+ this.child.moveBeforeDOMNode(node, parent);
457
+ }
458
+ moveBeforeVNode(other, afterNode) {
459
+ this.moveBeforeDOMNode((other && other.firstNode()) || afterNode);
460
+ }
461
+ patch(other, withBeforeRemove) {
462
+ if (this === other) {
463
+ return;
464
+ }
465
+ let child1 = this.child;
466
+ let child2 = other.child;
467
+ if (this.key === other.key) {
468
+ child1.patch(child2, withBeforeRemove);
469
+ }
470
+ else {
471
+ const firstNode = child1.firstNode();
472
+ firstNode.parentElement.insertBefore(txt, firstNode);
473
+ if (withBeforeRemove) {
474
+ child1.beforeRemove();
475
+ }
476
+ child1.remove();
477
+ child2.mount(this.parentEl, txt);
478
+ this.child = child2;
479
+ this.key = other.key;
480
+ }
481
+ }
482
+ beforeRemove() {
483
+ this.child.beforeRemove();
484
+ }
485
+ remove() {
486
+ this.child.remove();
487
+ }
488
+ firstNode() {
489
+ return this.child.firstNode();
490
+ }
491
+ toString() {
492
+ return this.child.toString();
493
+ }
494
+ }
495
+ function toggler(key, child) {
496
+ return new VToggler(key, child);
497
+ }
498
+
499
+ let elemSetAttribute;
500
+ let removeAttribute;
501
+ let tokenListAdd;
502
+ let tokenListRemove;
503
+ if (typeof Element !== "undefined") {
504
+ ({ setAttribute: elemSetAttribute, removeAttribute } = Element.prototype);
505
+ const tokenList = DOMTokenList.prototype;
506
+ tokenListAdd = tokenList.add;
507
+ tokenListRemove = tokenList.remove;
508
+ }
509
+ const isArray = Array.isArray;
510
+ const { split, trim } = String.prototype;
511
+ const wordRegexp = /\s+/;
512
+ /**
513
+ * We regroup here all code related to updating attributes in a very loose sense:
514
+ * attributes, properties and classs are all managed by the functions in this
515
+ * file.
516
+ */
517
+ function setAttribute(key, value) {
518
+ switch (value) {
519
+ case false:
520
+ case undefined:
521
+ removeAttribute.call(this, key);
522
+ break;
523
+ case true:
524
+ elemSetAttribute.call(this, key, "");
525
+ break;
526
+ default:
527
+ elemSetAttribute.call(this, key, value);
528
+ }
529
+ }
530
+ function createAttrUpdater(attr) {
531
+ return function (value) {
532
+ setAttribute.call(this, attr, value);
533
+ };
534
+ }
535
+ function attrsSetter(attrs) {
536
+ if (isArray(attrs)) {
537
+ if (attrs[0] === "class") {
538
+ setClass.call(this, attrs[1]);
539
+ }
540
+ else if (attrs[0] === "style") {
541
+ setStyle.call(this, attrs[1]);
542
+ }
543
+ else {
544
+ setAttribute.call(this, attrs[0], attrs[1]);
545
+ }
546
+ }
547
+ else {
548
+ for (let k in attrs) {
549
+ if (k === "class") {
550
+ setClass.call(this, attrs[k]);
551
+ }
552
+ else if (k === "style") {
553
+ setStyle.call(this, attrs[k]);
554
+ }
555
+ else {
556
+ setAttribute.call(this, k, attrs[k]);
557
+ }
558
+ }
559
+ }
560
+ }
561
+ function attrsUpdater(attrs, oldAttrs) {
562
+ if (isArray(attrs)) {
563
+ const name = attrs[0];
564
+ const val = attrs[1];
565
+ if (name === oldAttrs[0]) {
566
+ if (val === oldAttrs[1]) {
567
+ return;
568
+ }
569
+ if (name === "class") {
570
+ updateClass.call(this, val, oldAttrs[1]);
571
+ }
572
+ else if (name === "style") {
573
+ updateStyle.call(this, val, oldAttrs[1]);
574
+ }
575
+ else {
576
+ setAttribute.call(this, name, val);
577
+ }
578
+ }
579
+ else {
580
+ removeAttribute.call(this, oldAttrs[0]);
581
+ setAttribute.call(this, name, val);
582
+ }
583
+ }
584
+ else {
585
+ for (let k in oldAttrs) {
586
+ if (!(k in attrs)) {
587
+ if (k === "class") {
588
+ updateClass.call(this, "", oldAttrs[k]);
589
+ }
590
+ else if (k === "style") {
591
+ updateStyle.call(this, "", oldAttrs[k]);
592
+ }
593
+ else {
594
+ removeAttribute.call(this, k);
595
+ }
596
+ }
597
+ }
598
+ for (let k in attrs) {
599
+ const val = attrs[k];
600
+ if (val !== oldAttrs[k]) {
601
+ if (k === "class") {
602
+ updateClass.call(this, val, oldAttrs[k]);
603
+ }
604
+ else if (k === "style") {
605
+ updateStyle.call(this, val, oldAttrs[k]);
606
+ }
607
+ else {
608
+ setAttribute.call(this, k, val);
609
+ }
610
+ }
611
+ }
612
+ }
613
+ }
614
+ function toClassObj(expr) {
615
+ const result = {};
616
+ switch (typeof expr) {
617
+ case "string":
618
+ // we transform here a list of classes into an object:
619
+ // 'hey you' becomes {hey: true, you: true}
620
+ const str = trim.call(expr);
621
+ if (!str) {
622
+ return {};
623
+ }
624
+ let words = split.call(str, wordRegexp);
625
+ for (let i = 0, l = words.length; i < l; i++) {
626
+ result[words[i]] = true;
627
+ }
628
+ return result;
629
+ case "object":
630
+ // this is already an object but we may need to split keys:
631
+ // {'a': true, 'b c': true} should become {a: true, b: true, c: true}
632
+ for (let key in expr) {
633
+ const value = expr[key];
634
+ if (value) {
635
+ key = trim.call(key);
636
+ if (!key) {
637
+ continue;
638
+ }
639
+ const words = split.call(key, wordRegexp);
640
+ for (let word of words) {
641
+ result[word] = value;
642
+ }
643
+ }
644
+ }
645
+ return result;
646
+ case "undefined":
647
+ return {};
648
+ case "number":
649
+ return { [expr]: true };
650
+ default:
651
+ return { [expr]: true };
652
+ }
653
+ }
654
+ function setClass(val) {
655
+ val = val === "" ? {} : toClassObj(val);
656
+ // add classes
657
+ const cl = this.classList;
658
+ for (let c in val) {
659
+ tokenListAdd.call(cl, c);
660
+ }
661
+ }
662
+ function updateClass(val, oldVal) {
663
+ oldVal = oldVal === "" ? {} : toClassObj(oldVal);
664
+ val = val === "" ? {} : toClassObj(val);
665
+ const cl = this.classList;
666
+ // remove classes
667
+ for (let c in oldVal) {
668
+ if (!(c in val)) {
669
+ tokenListRemove.call(cl, c);
670
+ }
671
+ }
672
+ // add classes
673
+ for (let c in val) {
674
+ if (!(c in oldVal)) {
675
+ tokenListAdd.call(cl, c);
676
+ }
677
+ }
678
+ }
679
+ // ---------------------------------------------------------------------------
680
+ // Style
681
+ // ---------------------------------------------------------------------------
682
+ const CSS_PROP_CACHE = {};
683
+ function toKebabCase(prop) {
684
+ if (prop in CSS_PROP_CACHE) {
685
+ return CSS_PROP_CACHE[prop];
686
+ }
687
+ const result = prop.replace(/[A-Z]/g, (m) => "-" + m.toLowerCase());
688
+ CSS_PROP_CACHE[prop] = result;
689
+ return result;
690
+ }
691
+ function toStyleObj(expr) {
692
+ const result = {};
693
+ switch (typeof expr) {
694
+ case "string": {
695
+ const str = trim.call(expr);
696
+ if (!str) {
697
+ return {};
698
+ }
699
+ const parts = str.split(";");
700
+ for (let part of parts) {
701
+ part = trim.call(part);
702
+ if (!part) {
703
+ continue;
704
+ }
705
+ const colonIdx = part.indexOf(":");
706
+ if (colonIdx === -1) {
707
+ continue;
708
+ }
709
+ const prop = trim.call(part.slice(0, colonIdx));
710
+ const value = trim.call(part.slice(colonIdx + 1));
711
+ if (prop && value) {
712
+ result[prop] = value;
713
+ }
714
+ }
715
+ return result;
716
+ }
717
+ case "object":
718
+ for (let prop in expr) {
719
+ const value = expr[prop];
720
+ if (value || value === 0) {
721
+ result[toKebabCase(prop)] = String(value);
722
+ }
723
+ }
724
+ return result;
725
+ default:
726
+ return {};
727
+ }
728
+ }
729
+ function setStyle(val) {
730
+ val = val === "" ? {} : toStyleObj(val);
731
+ const style = this.style;
732
+ for (let prop in val) {
733
+ style.setProperty(prop, val[prop]);
734
+ }
735
+ }
736
+ function updateStyle(val, oldVal) {
737
+ oldVal = oldVal === "" ? {} : toStyleObj(oldVal);
738
+ val = val === "" ? {} : toStyleObj(val);
739
+ const style = this.style;
740
+ // remove old styles
741
+ for (let prop in oldVal) {
742
+ if (!(prop in val)) {
743
+ style.removeProperty(prop);
744
+ }
745
+ }
746
+ // set new/changed styles
747
+ for (let prop in val) {
748
+ if (val[prop] !== oldVal[prop]) {
749
+ style.setProperty(prop, val[prop]);
750
+ }
751
+ }
752
+ }
753
+
754
+ function createEventHandler(rawEvent) {
755
+ const eventName = rawEvent.split(".")[0];
756
+ const capture = rawEvent.includes(".capture");
757
+ const passive = rawEvent.includes(".passive");
758
+ if (rawEvent.includes(".synthetic")) {
759
+ return createSyntheticHandler(eventName, capture, passive);
760
+ }
761
+ else {
762
+ return createElementHandler(eventName, capture, passive);
763
+ }
764
+ }
765
+ // Native listener
766
+ let nextNativeEventId = 1;
767
+ function createElementHandler(evName, capture = false, passive = false) {
768
+ let eventKey = `__event__${evName}_${nextNativeEventId++}`;
769
+ if (capture) {
770
+ eventKey = `${eventKey}_capture`;
771
+ }
772
+ function listener(ev) {
773
+ const currentTarget = ev.currentTarget;
774
+ if (!currentTarget || !inOwnerDocument(currentTarget))
775
+ return;
776
+ const data = currentTarget[eventKey];
777
+ if (!data)
778
+ return;
779
+ config$1.mainEventHandler(data, ev, currentTarget);
780
+ }
781
+ const options = { capture, passive };
782
+ function setup(data) {
783
+ this[eventKey] = data;
784
+ this.addEventListener(evName, listener, options);
785
+ }
786
+ function remove() {
787
+ delete this[eventKey];
788
+ this.removeEventListener(evName, listener, options);
789
+ }
790
+ function update(data) {
791
+ this[eventKey] = data;
792
+ }
793
+ return { setup, update, remove };
794
+ }
795
+ // Synthetic handler: a form of event delegation that allows placing only one
796
+ // listener per event type.
797
+ let nextSyntheticEventId = 1;
798
+ function createSyntheticHandler(evName, capture = false, passive = false) {
799
+ let eventKey = `__event__synthetic_${evName}`;
800
+ if (capture) {
801
+ eventKey = `${eventKey}_capture`;
802
+ }
803
+ setupSyntheticEvent(evName, eventKey, capture, passive);
804
+ const currentId = nextSyntheticEventId++;
805
+ function setup(data) {
806
+ const _data = this[eventKey] || {};
807
+ _data[currentId] = data;
808
+ this[eventKey] = _data;
809
+ }
810
+ function remove() {
811
+ delete this[eventKey];
812
+ }
813
+ return { setup, update: setup, remove };
814
+ }
815
+ function nativeToSyntheticEvent(eventKey, event) {
816
+ let dom = event.target;
817
+ while (dom !== null) {
818
+ const _data = dom[eventKey];
819
+ if (_data) {
820
+ for (const data of Object.values(_data)) {
821
+ const stopped = config$1.mainEventHandler(data, event, dom);
822
+ if (stopped)
823
+ return;
824
+ }
825
+ }
826
+ dom = dom.parentNode;
827
+ }
828
+ }
829
+ const CONFIGURED_SYNTHETIC_EVENTS = {};
830
+ function setupSyntheticEvent(evName, eventKey, capture = false, passive = false) {
831
+ if (CONFIGURED_SYNTHETIC_EVENTS[eventKey]) {
832
+ return;
833
+ }
834
+ document.addEventListener(evName, (event) => nativeToSyntheticEvent(eventKey, event), {
835
+ capture,
836
+ passive,
837
+ });
838
+ CONFIGURED_SYNTHETIC_EVENTS[eventKey] = true;
839
+ }
840
+
841
+ const getDescriptor$3 = (o, p) => Object.getOwnPropertyDescriptor(o, p);
842
+ let nodeInsertBefore$3;
843
+ let nodeSetTextContent$1;
844
+ let nodeRemoveChild$3;
845
+ if (typeof Node !== "undefined") {
846
+ const nodeProto = Node.prototype;
847
+ nodeInsertBefore$3 = nodeProto.insertBefore;
848
+ nodeSetTextContent$1 = getDescriptor$3(nodeProto, "textContent").set;
849
+ nodeRemoveChild$3 = nodeProto.removeChild;
850
+ }
851
+ // -----------------------------------------------------------------------------
852
+ // Multi NODE
853
+ // -----------------------------------------------------------------------------
854
+ class VMulti {
855
+ children;
856
+ anchors;
857
+ parentEl;
858
+ isOnlyChild;
859
+ constructor(children) {
860
+ this.children = children;
861
+ }
862
+ mount(parent, afterNode) {
863
+ const children = this.children;
864
+ const l = children.length;
865
+ const anchors = new Array(l);
866
+ for (let i = 0; i < l; i++) {
867
+ let child = children[i];
868
+ if (child) {
869
+ child.mount(parent, afterNode);
870
+ }
871
+ else {
872
+ const childAnchor = document.createTextNode("");
873
+ anchors[i] = childAnchor;
874
+ nodeInsertBefore$3.call(parent, childAnchor, afterNode);
875
+ }
876
+ }
877
+ this.anchors = anchors;
878
+ this.parentEl = parent;
879
+ }
880
+ moveBeforeDOMNode(node, parent = this.parentEl) {
881
+ this.parentEl = parent;
882
+ const children = this.children;
883
+ const anchors = this.anchors;
884
+ for (let i = 0, l = children.length; i < l; i++) {
885
+ let child = children[i];
886
+ if (child) {
887
+ child.moveBeforeDOMNode(node, parent);
888
+ }
889
+ else {
890
+ const anchor = anchors[i];
891
+ nodeInsertBefore$3.call(parent, anchor, node);
892
+ }
893
+ }
894
+ }
895
+ moveBeforeVNode(other, afterNode) {
896
+ if (other) {
897
+ const next = other.children[0];
898
+ afterNode = (next ? next.firstNode() : other.anchors[0]) || null;
899
+ }
900
+ const children = this.children;
901
+ const parent = this.parentEl;
902
+ const anchors = this.anchors;
903
+ for (let i = 0, l = children.length; i < l; i++) {
904
+ let child = children[i];
905
+ if (child) {
906
+ child.moveBeforeVNode(null, afterNode);
907
+ }
908
+ else {
909
+ const anchor = anchors[i];
910
+ nodeInsertBefore$3.call(parent, anchor, afterNode);
911
+ }
912
+ }
913
+ }
914
+ patch(other, withBeforeRemove) {
915
+ if (this === other) {
916
+ return;
917
+ }
918
+ const children1 = this.children;
919
+ const children2 = other.children;
920
+ const anchors = this.anchors;
921
+ const parentEl = this.parentEl;
922
+ for (let i = 0, l = children1.length; i < l; i++) {
923
+ const vn1 = children1[i];
924
+ const vn2 = children2[i];
925
+ if (vn1) {
926
+ if (vn2) {
927
+ vn1.patch(vn2, withBeforeRemove);
928
+ }
929
+ else {
930
+ const afterNode = vn1.firstNode();
931
+ const anchor = document.createTextNode("");
932
+ anchors[i] = anchor;
933
+ nodeInsertBefore$3.call(parentEl, anchor, afterNode);
934
+ if (withBeforeRemove) {
935
+ vn1.beforeRemove();
936
+ }
937
+ vn1.remove();
938
+ children1[i] = undefined;
939
+ }
940
+ }
941
+ else if (vn2) {
942
+ children1[i] = vn2;
943
+ const anchor = anchors[i];
944
+ vn2.mount(parentEl, anchor);
945
+ nodeRemoveChild$3.call(parentEl, anchor);
946
+ }
947
+ }
948
+ }
949
+ beforeRemove() {
950
+ const children = this.children;
951
+ for (let i = 0, l = children.length; i < l; i++) {
952
+ const child = children[i];
953
+ if (child) {
954
+ child.beforeRemove();
955
+ }
956
+ }
957
+ }
958
+ remove() {
959
+ const parentEl = this.parentEl;
960
+ if (this.isOnlyChild) {
961
+ nodeSetTextContent$1.call(parentEl, "");
962
+ }
963
+ else {
964
+ const children = this.children;
965
+ const anchors = this.anchors;
966
+ for (let i = 0, l = children.length; i < l; i++) {
967
+ const child = children[i];
968
+ if (child) {
969
+ child.remove();
970
+ }
971
+ else {
972
+ nodeRemoveChild$3.call(parentEl, anchors[i]);
973
+ }
974
+ }
975
+ }
976
+ }
977
+ firstNode() {
978
+ const child = this.children[0];
979
+ return child ? child.firstNode() : this.anchors[0];
980
+ }
981
+ toString() {
982
+ return this.children.map((c) => (c ? c.toString() : "")).join("");
983
+ }
984
+ }
985
+ function multi(children) {
986
+ return new VMulti(children);
987
+ }
988
+
989
+ const getDescriptor$2 = (o, p) => Object.getOwnPropertyDescriptor(o, p);
990
+ let nodeInsertBefore$2;
991
+ let characterDataSetData$1;
992
+ let nodeRemoveChild$2;
993
+ if (typeof Node !== "undefined") {
994
+ const nodeProto = Node.prototype;
995
+ nodeInsertBefore$2 = nodeProto.insertBefore;
996
+ nodeRemoveChild$2 = nodeProto.removeChild;
997
+ characterDataSetData$1 = getDescriptor$2(CharacterData.prototype, "data").set;
998
+ }
999
+ class VSimpleNode {
1000
+ text;
1001
+ parentEl;
1002
+ el;
1003
+ constructor(text) {
1004
+ this.text = text;
1005
+ }
1006
+ mountNode(node, parent, afterNode) {
1007
+ this.parentEl = parent;
1008
+ nodeInsertBefore$2.call(parent, node, afterNode);
1009
+ this.el = node;
1010
+ }
1011
+ moveBeforeDOMNode(node, parent = this.parentEl) {
1012
+ this.parentEl = parent;
1013
+ nodeInsertBefore$2.call(parent, this.el, node);
1014
+ }
1015
+ moveBeforeVNode(other, afterNode) {
1016
+ nodeInsertBefore$2.call(this.parentEl, this.el, other ? other.el : afterNode);
1017
+ }
1018
+ beforeRemove() { }
1019
+ remove() {
1020
+ nodeRemoveChild$2.call(this.parentEl, this.el);
1021
+ }
1022
+ firstNode() {
1023
+ return this.el;
1024
+ }
1025
+ toString() {
1026
+ return this.text;
1027
+ }
1028
+ }
1029
+ class VText extends VSimpleNode {
1030
+ mount(parent, afterNode) {
1031
+ this.mountNode(document.createTextNode(toText(this.text)), parent, afterNode);
1032
+ }
1033
+ patch(other) {
1034
+ const text2 = other.text;
1035
+ if (this.text !== text2) {
1036
+ characterDataSetData$1.call(this.el, toText(text2));
1037
+ this.text = text2;
1038
+ }
1039
+ }
1040
+ }
1041
+ class VComment extends VSimpleNode {
1042
+ mount(parent, afterNode) {
1043
+ this.mountNode(document.createComment(toText(this.text)), parent, afterNode);
1044
+ }
1045
+ patch() { }
1046
+ }
1047
+ function text(str) {
1048
+ return new VText(str);
1049
+ }
1050
+ function comment(str) {
1051
+ return new VComment(str);
1052
+ }
1053
+ function toText(value) {
1054
+ switch (typeof value) {
1055
+ case "string":
1056
+ return value;
1057
+ case "number":
1058
+ return String(value);
1059
+ case "boolean":
1060
+ return value ? "true" : "false";
1061
+ default:
1062
+ return value || "";
1063
+ }
1064
+ }
1065
+
1066
+ const getDescriptor$1 = (o, p) => Object.getOwnPropertyDescriptor(o, p);
1067
+ let nodeProto;
1068
+ let elementProto;
1069
+ let characterDataSetData;
1070
+ let nodeGetFirstChild;
1071
+ let nodeGetNextSibling;
1072
+ if (typeof Node !== "undefined") {
1073
+ nodeProto = Node.prototype;
1074
+ elementProto = Element.prototype;
1075
+ characterDataSetData = getDescriptor$1(CharacterData.prototype, "data").set;
1076
+ nodeGetFirstChild = getDescriptor$1(nodeProto, "firstChild").get;
1077
+ nodeGetNextSibling = getDescriptor$1(nodeProto, "nextSibling").get;
1078
+ }
1079
+ const NO_OP = () => { };
1080
+ function makePropSetter(name) {
1081
+ return function setProp(value) {
1082
+ // support 0, fallback to empty string for other falsy values
1083
+ this[name] = value === 0 ? 0 : value ? value.valueOf() : "";
1084
+ };
1085
+ }
1086
+ const cache = {};
1087
+ /**
1088
+ * Compiling blocks is a multi-step process:
1089
+ *
1090
+ * 1. build an IntermediateTree from the HTML element. This intermediate tree
1091
+ * is a binary tree structure that encode dynamic info sub nodes, and the
1092
+ * path required to reach them
1093
+ * 2. process the tree to build a block context, which is an object that aggregate
1094
+ * all dynamic info in a list, and also, all ref indexes.
1095
+ * 3. process the context to build appropriate builder/setter functions
1096
+ * 4. make a dynamic block class, which will efficiently collect references and
1097
+ * create/update dynamic locations/children
1098
+ *
1099
+ * @param str
1100
+ * @returns a new block type, that can build concrete blocks
1101
+ */
1102
+ function createBlock(str) {
1103
+ if (str in cache) {
1104
+ return cache[str];
1105
+ }
1106
+ // step 0: prepare html base element
1107
+ const doc = new DOMParser().parseFromString(`<t>${str}</t>`, "text/xml");
1108
+ const node = doc.firstChild.firstChild;
1109
+ if (config$1.shouldNormalizeDom) {
1110
+ normalizeNode(node);
1111
+ }
1112
+ // step 1: prepare intermediate tree
1113
+ const tree = buildTree(node);
1114
+ // step 2: prepare block context
1115
+ const context = buildContext(tree);
1116
+ // step 3: build the final block class
1117
+ const template = tree.el;
1118
+ const Block = buildBlock(template, context);
1119
+ cache[str] = Block;
1120
+ return Block;
1121
+ }
1122
+ // -----------------------------------------------------------------------------
1123
+ // Helper
1124
+ // -----------------------------------------------------------------------------
1125
+ function normalizeNode(node) {
1126
+ if (node.nodeType === Node.TEXT_NODE) {
1127
+ if (!/\S/.test(node.textContent)) {
1128
+ node.remove();
1129
+ return;
1130
+ }
1131
+ }
1132
+ if (node.nodeType === Node.ELEMENT_NODE) {
1133
+ if (node.tagName === "pre") {
1134
+ return;
1135
+ }
1136
+ }
1137
+ for (let i = node.childNodes.length - 1; i >= 0; --i) {
1138
+ normalizeNode(node.childNodes.item(i));
1139
+ }
1140
+ }
1141
+ function buildTree(node, parent = null, domParentTree = null) {
1142
+ switch (node.nodeType) {
1143
+ case Node.ELEMENT_NODE: {
1144
+ // HTMLElement
1145
+ let currentNS = domParentTree && domParentTree.currentNS;
1146
+ const tagName = node.tagName;
1147
+ let el = undefined;
1148
+ const info = [];
1149
+ if (tagName.startsWith("block-text-")) {
1150
+ const index = parseInt(tagName.slice(11), 10);
1151
+ info.push({ type: "text", idx: index });
1152
+ el = document.createTextNode("");
1153
+ }
1154
+ if (tagName.startsWith("block-child-")) {
1155
+ if (!domParentTree.isRef) {
1156
+ addRef(domParentTree);
1157
+ }
1158
+ const index = parseInt(tagName.slice(12), 10);
1159
+ info.push({ type: "child", idx: index });
1160
+ el = document.createTextNode("");
1161
+ }
1162
+ currentNS ||= node.namespaceURI;
1163
+ if (!el) {
1164
+ el = currentNS
1165
+ ? document.createElementNS(currentNS, tagName)
1166
+ : document.createElement(tagName);
1167
+ }
1168
+ if (el instanceof Element) {
1169
+ if (!domParentTree) {
1170
+ // some html elements may have side effects when setting their attributes.
1171
+ // For example, setting the src attribute of an <img/> will trigger a
1172
+ // request to get the corresponding image. This is something that we
1173
+ // don't want at compile time. We avoid that by putting the content of
1174
+ // the block in a <template/> element
1175
+ const fragment = document.createElement("template").content;
1176
+ fragment.appendChild(el);
1177
+ }
1178
+ const attrs = node.attributes;
1179
+ for (let i = 0; i < attrs.length; i++) {
1180
+ const attrName = attrs[i].name;
1181
+ const attrValue = attrs[i].value;
1182
+ if (attrName.startsWith("block-handler-")) {
1183
+ const idx = parseInt(attrName.slice(14), 10);
1184
+ info.push({
1185
+ type: "handler",
1186
+ idx,
1187
+ event: attrValue,
1188
+ });
1189
+ }
1190
+ else if (attrName.startsWith("block-attribute-")) {
1191
+ const idx = parseInt(attrName.slice(16), 10);
1192
+ info.push({
1193
+ type: "attribute",
1194
+ idx,
1195
+ name: attrValue,
1196
+ tag: tagName,
1197
+ });
1198
+ }
1199
+ else if (attrName.startsWith("block-property-")) {
1200
+ const idx = parseInt(attrName.slice(15), 10);
1201
+ info.push({
1202
+ type: "property",
1203
+ idx,
1204
+ name: attrValue,
1205
+ tag: tagName,
1206
+ });
1207
+ }
1208
+ else if (attrName === "block-attributes") {
1209
+ info.push({
1210
+ type: "attributes",
1211
+ idx: parseInt(attrValue, 10),
1212
+ });
1213
+ }
1214
+ else if (attrName === "block-ref") {
1215
+ info.push({
1216
+ type: "ref",
1217
+ idx: parseInt(attrValue, 10),
1218
+ });
1219
+ }
1220
+ else {
1221
+ el.setAttribute(attrs[i].name, attrValue);
1222
+ }
1223
+ }
1224
+ }
1225
+ const tree = {
1226
+ parent,
1227
+ firstChild: null,
1228
+ nextSibling: null,
1229
+ el,
1230
+ info,
1231
+ refN: 0,
1232
+ currentNS,
1233
+ };
1234
+ if (node.firstChild) {
1235
+ const childNode = node.childNodes[0];
1236
+ if (node.childNodes.length === 1 &&
1237
+ childNode.nodeType === Node.ELEMENT_NODE &&
1238
+ childNode.tagName.startsWith("block-child-")) {
1239
+ const tagName = childNode.tagName;
1240
+ const index = parseInt(tagName.slice(12), 10);
1241
+ info.push({ idx: index, type: "child", isOnlyChild: true });
1242
+ }
1243
+ else {
1244
+ tree.firstChild = buildTree(node.firstChild, tree, tree);
1245
+ el.appendChild(tree.firstChild.el);
1246
+ let curNode = node.firstChild;
1247
+ let curTree = tree.firstChild;
1248
+ while ((curNode = curNode.nextSibling)) {
1249
+ curTree.nextSibling = buildTree(curNode, curTree, tree);
1250
+ el.appendChild(curTree.nextSibling.el);
1251
+ curTree = curTree.nextSibling;
1252
+ }
1253
+ }
1254
+ }
1255
+ if (tree.info.length) {
1256
+ addRef(tree);
1257
+ }
1258
+ return tree;
1259
+ }
1260
+ case Node.TEXT_NODE:
1261
+ case Node.COMMENT_NODE: {
1262
+ // text node or comment node
1263
+ const el = node.nodeType === Node.TEXT_NODE
1264
+ ? document.createTextNode(node.textContent)
1265
+ : document.createComment(node.textContent);
1266
+ return {
1267
+ parent: parent,
1268
+ firstChild: null,
1269
+ nextSibling: null,
1270
+ el,
1271
+ info: [],
1272
+ refN: 0,
1273
+ currentNS: null,
1274
+ };
1275
+ }
1276
+ }
1277
+ throw new OwlError("boom");
1278
+ }
1279
+ function addRef(tree) {
1280
+ tree.isRef = true;
1281
+ do {
1282
+ tree.refN++;
1283
+ } while ((tree = tree.parent));
1284
+ }
1285
+ function parentTree(tree) {
1286
+ let parent = tree.parent;
1287
+ while (parent && parent.nextSibling === tree) {
1288
+ tree = parent;
1289
+ parent = parent.parent;
1290
+ }
1291
+ return parent;
1292
+ }
1293
+ function buildContext(tree, ctx, fromIdx) {
1294
+ if (!ctx) {
1295
+ const children = new Array(tree.info.filter((v) => v.type === "child").length);
1296
+ ctx = { collectors: [], locations: [], children, cbRefs: [], refN: tree.refN };
1297
+ fromIdx = 0;
1298
+ }
1299
+ if (tree.refN) {
1300
+ const initialIdx = fromIdx;
1301
+ const isRef = tree.isRef;
1302
+ const firstChild = tree.firstChild ? tree.firstChild.refN : 0;
1303
+ const nextSibling = tree.nextSibling ? tree.nextSibling.refN : 0;
1304
+ //node
1305
+ if (isRef) {
1306
+ for (let info of tree.info) {
1307
+ info.refIdx = initialIdx;
1308
+ }
1309
+ tree.refIdx = initialIdx;
1310
+ updateCtx(ctx, tree);
1311
+ fromIdx++;
1312
+ }
1313
+ // right
1314
+ if (nextSibling) {
1315
+ const idx = fromIdx + firstChild;
1316
+ ctx.collectors.push({ idx, prevIdx: initialIdx, getVal: nodeGetNextSibling });
1317
+ buildContext(tree.nextSibling, ctx, idx);
1318
+ }
1319
+ // left
1320
+ if (firstChild) {
1321
+ ctx.collectors.push({ idx: fromIdx, prevIdx: initialIdx, getVal: nodeGetFirstChild });
1322
+ buildContext(tree.firstChild, ctx, fromIdx);
1323
+ }
1324
+ }
1325
+ return ctx;
1326
+ }
1327
+ function updateCtx(ctx, tree) {
1328
+ for (let info of tree.info) {
1329
+ switch (info.type) {
1330
+ case "text":
1331
+ ctx.locations.push({
1332
+ idx: info.idx,
1333
+ refIdx: info.refIdx,
1334
+ setData: setText,
1335
+ updateData: setText,
1336
+ });
1337
+ break;
1338
+ case "child":
1339
+ if (info.isOnlyChild) {
1340
+ // tree is the parentnode here
1341
+ ctx.children[info.idx] = {
1342
+ parentRefIdx: info.refIdx,
1343
+ isOnlyChild: true,
1344
+ };
1345
+ }
1346
+ else {
1347
+ // tree is the anchor text node
1348
+ ctx.children[info.idx] = {
1349
+ parentRefIdx: parentTree(tree).refIdx,
1350
+ afterRefIdx: info.refIdx,
1351
+ };
1352
+ }
1353
+ break;
1354
+ case "property": {
1355
+ const refIdx = info.refIdx;
1356
+ const setProp = makePropSetter(info.name);
1357
+ ctx.locations.push({
1358
+ idx: info.idx,
1359
+ refIdx,
1360
+ setData: setProp,
1361
+ updateData: setProp,
1362
+ });
1363
+ break;
1364
+ }
1365
+ case "attribute": {
1366
+ const refIdx = info.refIdx;
1367
+ let updater;
1368
+ let setter;
1369
+ if (info.name === "class") {
1370
+ setter = setClass;
1371
+ updater = updateClass;
1372
+ }
1373
+ else if (info.name === "style") {
1374
+ setter = setStyle;
1375
+ updater = updateStyle;
1376
+ }
1377
+ else {
1378
+ setter = createAttrUpdater(info.name);
1379
+ updater = setter;
1380
+ }
1381
+ ctx.locations.push({
1382
+ idx: info.idx,
1383
+ refIdx,
1384
+ setData: setter,
1385
+ updateData: updater,
1386
+ });
1387
+ break;
1388
+ }
1389
+ case "attributes":
1390
+ ctx.locations.push({
1391
+ idx: info.idx,
1392
+ refIdx: info.refIdx,
1393
+ setData: attrsSetter,
1394
+ updateData: attrsUpdater,
1395
+ });
1396
+ break;
1397
+ case "handler": {
1398
+ const { setup, update } = createEventHandler(info.event);
1399
+ ctx.locations.push({
1400
+ idx: info.idx,
1401
+ refIdx: info.refIdx,
1402
+ setData: setup,
1403
+ updateData: update,
1404
+ });
1405
+ break;
1406
+ }
1407
+ case "ref": {
1408
+ ctx.locations.push({
1409
+ idx: info.idx,
1410
+ refIdx: info.refIdx,
1411
+ setData: NO_OP,
1412
+ updateData: NO_OP,
1413
+ });
1414
+ ctx.cbRefs.push(info.idx);
1415
+ break;
1416
+ }
1417
+ }
1418
+ }
1419
+ }
1420
+ // -----------------------------------------------------------------------------
1421
+ // building the concrete block class
1422
+ // -----------------------------------------------------------------------------
1423
+ function buildBlock(template, ctx) {
1424
+ let B = createBlockClass(template, ctx);
1425
+ if (ctx.children.length) {
1426
+ B = class extends B {
1427
+ children;
1428
+ constructor(data, children) {
1429
+ super(data);
1430
+ this.children = children;
1431
+ }
1432
+ };
1433
+ B.prototype.beforeRemove = VMulti.prototype.beforeRemove;
1434
+ return (data, children = []) => new B(data, children);
1435
+ }
1436
+ return (data) => new B(data);
1437
+ }
1438
+ function createBlockClass(template, ctx) {
1439
+ const { refN, collectors, children, locations, cbRefs } = ctx;
1440
+ locations.sort((a, b) => a.idx - b.idx);
1441
+ const locN = locations.length;
1442
+ const childN = children.length;
1443
+ const isDynamic = refN > 0;
1444
+ // Flatten locations into parallel arrays (hot path optimization)
1445
+ const locRefIdxs = locations.map((l) => l.refIdx);
1446
+ const locSetters = locations.map((l) => l.setData);
1447
+ const locUpdaters = locations.map((l) => l.updateData);
1448
+ // Bitpack collectors into uint32 array
1449
+ // Layout: bits 0-14: idx, bits 15-29: prevIdx, bit 30: isFirstChild
1450
+ const GETTERS = [nodeGetNextSibling, nodeGetFirstChild];
1451
+ const colN = collectors.length;
1452
+ const colPacked = collectors.map((c) => (c.idx & 0x7fff) |
1453
+ ((c.prevIdx & 0x7fff) << 15) |
1454
+ ((c.getVal === nodeGetFirstChild ? 1 : 0) << 30));
1455
+ // Bitpack children locations into uint32 array
1456
+ // Layout: bits 0-14: parentRefIdx, bit 15: isOnlyChild, bits 16-30: afterRefIdx
1457
+ const childInfos = children.map((c) => (c.parentRefIdx & 0x7fff) |
1458
+ ((c.isOnlyChild ? 1 : 0) << 15) |
1459
+ (((c.afterRefIdx ?? 0) & 0x7fff) << 16));
1460
+ // these values are defined here to make them faster to lookup in the class
1461
+ // block scope
1462
+ const nodeCloneNode = nodeProto.cloneNode;
1463
+ const nodeInsertBefore = nodeProto.insertBefore;
1464
+ const elementRemove = elementProto.remove;
1465
+ class Block {
1466
+ el;
1467
+ parentEl;
1468
+ data;
1469
+ children;
1470
+ refs;
1471
+ constructor(data) {
1472
+ this.data = data;
1473
+ }
1474
+ beforeRemove() { }
1475
+ remove() {
1476
+ elementRemove.call(this.el);
1477
+ }
1478
+ firstNode() {
1479
+ return this.el;
1480
+ }
1481
+ moveBeforeDOMNode(node, parent = this.parentEl) {
1482
+ this.parentEl = parent;
1483
+ nodeInsertBefore.call(parent, this.el, node);
1484
+ }
1485
+ moveBeforeVNode(other, afterNode) {
1486
+ nodeInsertBefore.call(this.parentEl, this.el, other ? other.el : afterNode);
1487
+ }
1488
+ toString() {
1489
+ const div = document.createElement("div");
1490
+ this.mount(div, null);
1491
+ return div.innerHTML;
1492
+ }
1493
+ mount(parent, afterNode) {
1494
+ const el = nodeCloneNode.call(template, true);
1495
+ nodeInsertBefore.call(parent, el, afterNode);
1496
+ this.el = el;
1497
+ this.parentEl = parent;
1498
+ }
1499
+ patch(other, withBeforeRemove) { }
1500
+ }
1501
+ if (isDynamic) {
1502
+ Block.prototype.mount = function mount(parent, afterNode) {
1503
+ const el = nodeCloneNode.call(template, true);
1504
+ // collecting references
1505
+ const refs = new Array(refN);
1506
+ this.refs = refs;
1507
+ refs[0] = el;
1508
+ for (let i = 0; i < colN; i++) {
1509
+ const packed = colPacked[i];
1510
+ refs[packed & 0x7fff] = GETTERS[(packed >> 30) & 1].call(refs[(packed >> 15) & 0x7fff]);
1511
+ }
1512
+ // applying data to all update points
1513
+ if (locN) {
1514
+ const data = this.data;
1515
+ for (let i = 0; i < locN; i++) {
1516
+ locSetters[i].call(refs[locRefIdxs[i]], data[i]);
1517
+ }
1518
+ }
1519
+ // preparing all children (off-DOM, before inserting el into the live document)
1520
+ if (childN) {
1521
+ const children = this.children;
1522
+ for (let i = 0; i < childN; i++) {
1523
+ const child = children[i];
1524
+ if (child) {
1525
+ const info = childInfos[i];
1526
+ const afterRefIdx = (info >> 16) & 0x7fff;
1527
+ const afterNode = afterRefIdx ? refs[afterRefIdx] : null;
1528
+ child.isOnlyChild = !!(info & (1 << 15));
1529
+ child.mount(refs[info & 0x7fff], afterNode);
1530
+ }
1531
+ }
1532
+ }
1533
+ nodeInsertBefore.call(parent, el, afterNode);
1534
+ this.el = el;
1535
+ this.parentEl = parent;
1536
+ if (cbRefs.length) {
1537
+ const data = this.data;
1538
+ const refs = this.refs;
1539
+ for (let cbRef of cbRefs) {
1540
+ const fn = data[cbRef];
1541
+ fn(refs[locRefIdxs[cbRef]], null);
1542
+ }
1543
+ }
1544
+ };
1545
+ Block.prototype.patch = function patch(other, withBeforeRemove) {
1546
+ if (this === other) {
1547
+ return;
1548
+ }
1549
+ const refs = this.refs;
1550
+ // update texts/attributes/
1551
+ if (locN) {
1552
+ const data1 = this.data;
1553
+ const data2 = other.data;
1554
+ for (let i = 0; i < locN; i++) {
1555
+ const val1 = data1[i];
1556
+ const val2 = data2[i];
1557
+ if (val1 !== val2) {
1558
+ locUpdaters[i].call(refs[locRefIdxs[i]], val2, val1);
1559
+ }
1560
+ }
1561
+ this.data = data2;
1562
+ }
1563
+ // update children
1564
+ if (childN) {
1565
+ let children1 = this.children;
1566
+ const children2 = other.children;
1567
+ for (let i = 0; i < childN; i++) {
1568
+ const child1 = children1[i];
1569
+ const child2 = children2[i];
1570
+ if (child1) {
1571
+ if (child2) {
1572
+ child1.patch(child2, withBeforeRemove);
1573
+ }
1574
+ else {
1575
+ if (withBeforeRemove) {
1576
+ child1.beforeRemove();
1577
+ }
1578
+ child1.remove();
1579
+ children1[i] = undefined;
1580
+ }
1581
+ }
1582
+ else if (child2) {
1583
+ const info = childInfos[i];
1584
+ const afterRefIdx = (info >> 16) & 0x7fff;
1585
+ const afterNode = afterRefIdx ? refs[afterRefIdx] : null;
1586
+ child2.mount(refs[info & 0x7fff], afterNode);
1587
+ children1[i] = child2;
1588
+ }
1589
+ }
1590
+ }
1591
+ };
1592
+ Block.prototype.remove = function remove() {
1593
+ if (cbRefs.length) {
1594
+ const data = this.data;
1595
+ const refs = this.refs;
1596
+ for (let cbRef of cbRefs) {
1597
+ const fn = data[cbRef];
1598
+ fn(null, refs[locRefIdxs[cbRef]]);
1599
+ }
1600
+ }
1601
+ elementRemove.call(this.el);
1602
+ };
1603
+ }
1604
+ return Block;
1605
+ }
1606
+ function setText(value) {
1607
+ characterDataSetData.call(this, toText(value));
1608
+ }
1609
+
1610
+ const getDescriptor = (o, p) => Object.getOwnPropertyDescriptor(o, p);
1611
+ let nodeInsertBefore$1;
1612
+ let nodeAppendChild;
1613
+ let nodeRemoveChild$1;
1614
+ let nodeSetTextContent;
1615
+ if (typeof Node !== "undefined") {
1616
+ const nodeProto = Node.prototype;
1617
+ nodeInsertBefore$1 = nodeProto.insertBefore;
1618
+ nodeAppendChild = nodeProto.appendChild;
1619
+ nodeRemoveChild$1 = nodeProto.removeChild;
1620
+ nodeSetTextContent = getDescriptor(nodeProto, "textContent").set;
1621
+ }
1622
+ // -----------------------------------------------------------------------------
1623
+ // List Node
1624
+ // -----------------------------------------------------------------------------
1625
+ class VList {
1626
+ children;
1627
+ anchor;
1628
+ parentEl;
1629
+ isOnlyChild;
1630
+ constructor(children) {
1631
+ this.children = children;
1632
+ }
1633
+ mount(parent, afterNode) {
1634
+ const children = this.children;
1635
+ const _anchor = document.createTextNode("");
1636
+ this.anchor = _anchor;
1637
+ nodeInsertBefore$1.call(parent, _anchor, afterNode);
1638
+ const l = children.length;
1639
+ if (l) {
1640
+ const mount = children[0].mount;
1641
+ for (let i = 0; i < l; i++) {
1642
+ mount.call(children[i], parent, _anchor);
1643
+ }
1644
+ }
1645
+ this.parentEl = parent;
1646
+ }
1647
+ moveBeforeDOMNode(node, parent = this.parentEl) {
1648
+ this.parentEl = parent;
1649
+ const children = this.children;
1650
+ for (let i = 0, l = children.length; i < l; i++) {
1651
+ children[i].moveBeforeDOMNode(node, parent);
1652
+ }
1653
+ parent.insertBefore(this.anchor, node);
1654
+ }
1655
+ moveBeforeVNode(other, afterNode) {
1656
+ if (other) {
1657
+ const next = other.children[0];
1658
+ afterNode = (next ? next.firstNode() : other.anchor) || null;
1659
+ }
1660
+ const children = this.children;
1661
+ for (let i = 0, l = children.length; i < l; i++) {
1662
+ children[i].moveBeforeVNode(null, afterNode);
1663
+ }
1664
+ this.parentEl.insertBefore(this.anchor, afterNode);
1665
+ }
1666
+ patch(other, withBeforeRemove) {
1667
+ if (this === other) {
1668
+ return;
1669
+ }
1670
+ const ch1 = this.children;
1671
+ const ch2 = other.children;
1672
+ if (ch2.length === 0 && ch1.length === 0) {
1673
+ return;
1674
+ }
1675
+ this.children = ch2;
1676
+ const proto = ch2[0] || ch1[0];
1677
+ const { mount: cMount, patch: cPatch, remove: cRemove, beforeRemove, moveBeforeVNode: cMoveBefore, firstNode: cFirstNode, } = proto;
1678
+ const _anchor = this.anchor;
1679
+ const isOnlyChild = this.isOnlyChild;
1680
+ const parent = this.parentEl;
1681
+ // fast path: no new child => only remove
1682
+ if (ch2.length === 0 && isOnlyChild) {
1683
+ if (withBeforeRemove) {
1684
+ for (let i = 0, l = ch1.length; i < l; i++) {
1685
+ beforeRemove.call(ch1[i]);
1686
+ }
1687
+ }
1688
+ nodeSetTextContent.call(parent, "");
1689
+ nodeAppendChild.call(parent, _anchor);
1690
+ return;
1691
+ }
1692
+ let startIdx1 = 0;
1693
+ let startIdx2 = 0;
1694
+ let startVn1 = ch1[0];
1695
+ let startVn2 = ch2[0];
1696
+ let endIdx1 = ch1.length - 1;
1697
+ let endIdx2 = ch2.length - 1;
1698
+ let endVn1 = ch1[endIdx1];
1699
+ let endVn2 = ch2[endIdx2];
1700
+ let mapping = undefined;
1701
+ while (startIdx1 <= endIdx1 && startIdx2 <= endIdx2) {
1702
+ // -------------------------------------------------------------------
1703
+ if (startVn1 === null) {
1704
+ startVn1 = ch1[++startIdx1];
1705
+ continue;
1706
+ }
1707
+ // -------------------------------------------------------------------
1708
+ if (endVn1 === null) {
1709
+ endVn1 = ch1[--endIdx1];
1710
+ continue;
1711
+ }
1712
+ // -------------------------------------------------------------------
1713
+ let startKey1 = startVn1.key;
1714
+ let startKey2 = startVn2.key;
1715
+ if (startKey1 === startKey2) {
1716
+ cPatch.call(startVn1, startVn2, withBeforeRemove);
1717
+ ch2[startIdx2] = startVn1;
1718
+ startVn1 = ch1[++startIdx1];
1719
+ startVn2 = ch2[++startIdx2];
1720
+ continue;
1721
+ }
1722
+ // -------------------------------------------------------------------
1723
+ let endKey1 = endVn1.key;
1724
+ let endKey2 = endVn2.key;
1725
+ if (endKey1 === endKey2) {
1726
+ cPatch.call(endVn1, endVn2, withBeforeRemove);
1727
+ ch2[endIdx2] = endVn1;
1728
+ endVn1 = ch1[--endIdx1];
1729
+ endVn2 = ch2[--endIdx2];
1730
+ continue;
1731
+ }
1732
+ // -------------------------------------------------------------------
1733
+ if (startKey1 === endKey2) {
1734
+ // bnode moved right
1735
+ cPatch.call(startVn1, endVn2, withBeforeRemove);
1736
+ ch2[endIdx2] = startVn1;
1737
+ const nextChild = ch2[endIdx2 + 1];
1738
+ cMoveBefore.call(startVn1, nextChild, _anchor);
1739
+ startVn1 = ch1[++startIdx1];
1740
+ endVn2 = ch2[--endIdx2];
1741
+ continue;
1742
+ }
1743
+ // -------------------------------------------------------------------
1744
+ if (endKey1 === startKey2) {
1745
+ // bnode moved left
1746
+ cPatch.call(endVn1, startVn2, withBeforeRemove);
1747
+ ch2[startIdx2] = endVn1;
1748
+ const nextChild = ch1[startIdx1];
1749
+ cMoveBefore.call(endVn1, nextChild, _anchor);
1750
+ endVn1 = ch1[--endIdx1];
1751
+ startVn2 = ch2[++startIdx2];
1752
+ continue;
1753
+ }
1754
+ // -------------------------------------------------------------------
1755
+ mapping = mapping || createMapping(ch1, startIdx1, endIdx1);
1756
+ let idxInOld = mapping[startKey2];
1757
+ if (idxInOld === undefined) {
1758
+ cMount.call(startVn2, parent, cFirstNode.call(startVn1) || null);
1759
+ }
1760
+ else {
1761
+ const elmToMove = ch1[idxInOld];
1762
+ cMoveBefore.call(elmToMove, startVn1, null);
1763
+ cPatch.call(elmToMove, startVn2, withBeforeRemove);
1764
+ ch2[startIdx2] = elmToMove;
1765
+ ch1[idxInOld] = null;
1766
+ }
1767
+ startVn2 = ch2[++startIdx2];
1768
+ }
1769
+ // ---------------------------------------------------------------------
1770
+ if (startIdx1 <= endIdx1 || startIdx2 <= endIdx2) {
1771
+ if (startIdx1 > endIdx1) {
1772
+ const nextChild = ch2[endIdx2 + 1];
1773
+ const anchor = nextChild ? cFirstNode.call(nextChild) || null : _anchor;
1774
+ for (let i = startIdx2; i <= endIdx2; i++) {
1775
+ cMount.call(ch2[i], parent, anchor);
1776
+ }
1777
+ }
1778
+ else {
1779
+ for (let i = startIdx1; i <= endIdx1; i++) {
1780
+ let ch = ch1[i];
1781
+ if (ch) {
1782
+ if (withBeforeRemove) {
1783
+ beforeRemove.call(ch);
1784
+ }
1785
+ cRemove.call(ch);
1786
+ }
1787
+ }
1788
+ }
1789
+ }
1790
+ }
1791
+ beforeRemove() {
1792
+ const children = this.children;
1793
+ const l = children.length;
1794
+ if (l) {
1795
+ const beforeRemove = children[0].beforeRemove;
1796
+ for (let i = 0; i < l; i++) {
1797
+ beforeRemove.call(children[i]);
1798
+ }
1799
+ }
1800
+ }
1801
+ remove() {
1802
+ const { parentEl, anchor } = this;
1803
+ if (this.isOnlyChild) {
1804
+ nodeSetTextContent.call(parentEl, "");
1805
+ }
1806
+ else {
1807
+ const children = this.children;
1808
+ const l = children.length;
1809
+ if (l) {
1810
+ const remove = children[0].remove;
1811
+ for (let i = 0; i < l; i++) {
1812
+ remove.call(children[i]);
1813
+ }
1814
+ }
1815
+ nodeRemoveChild$1.call(parentEl, anchor);
1816
+ }
1817
+ }
1818
+ firstNode() {
1819
+ const child = this.children[0];
1820
+ return child ? child.firstNode() : undefined;
1821
+ }
1822
+ toString() {
1823
+ return this.children.map((c) => c.toString()).join("");
1824
+ }
1825
+ }
1826
+ function list(children) {
1827
+ return new VList(children);
1828
+ }
1829
+ function createMapping(ch1, startIdx1, endIdx2) {
1830
+ let mapping = {};
1831
+ for (let i = startIdx1; i <= endIdx2; i++) {
1832
+ mapping[ch1[i].key] = i;
1833
+ }
1834
+ return mapping;
1835
+ }
1836
+
1837
+ let nodeInsertBefore;
1838
+ let nodeRemoveChild;
1839
+ if (typeof Node !== "undefined") {
1840
+ const nodeProto = Node.prototype;
1841
+ nodeInsertBefore = nodeProto.insertBefore;
1842
+ nodeRemoveChild = nodeProto.removeChild;
1843
+ }
1844
+ class VHtml {
1845
+ html;
1846
+ parentEl;
1847
+ content = [];
1848
+ constructor(html) {
1849
+ this.html = html;
1850
+ }
1851
+ mount(parent, afterNode) {
1852
+ this.parentEl = parent;
1853
+ const template = document.createElement("template");
1854
+ template.innerHTML = this.html;
1855
+ this.content = [...template.content.childNodes];
1856
+ for (let elem of this.content) {
1857
+ nodeInsertBefore.call(parent, elem, afterNode);
1858
+ }
1859
+ if (!this.content.length) {
1860
+ const textNode = document.createTextNode("");
1861
+ this.content.push(textNode);
1862
+ nodeInsertBefore.call(parent, textNode, afterNode);
1863
+ }
1864
+ }
1865
+ moveBeforeDOMNode(node, parent = this.parentEl) {
1866
+ this.parentEl = parent;
1867
+ for (let elem of this.content) {
1868
+ nodeInsertBefore.call(parent, elem, node);
1869
+ }
1870
+ }
1871
+ moveBeforeVNode(other, afterNode) {
1872
+ const target = other ? other.content[0] : afterNode;
1873
+ this.moveBeforeDOMNode(target);
1874
+ }
1875
+ patch(other) {
1876
+ if (this === other) {
1877
+ return;
1878
+ }
1879
+ const html2 = other.html;
1880
+ if (this.html !== html2) {
1881
+ const parent = this.parentEl;
1882
+ // insert new html in front of current
1883
+ const afterNode = this.content[0];
1884
+ const template = document.createElement("template");
1885
+ template.innerHTML = html2;
1886
+ const content = [...template.content.childNodes];
1887
+ for (let elem of content) {
1888
+ nodeInsertBefore.call(parent, elem, afterNode);
1889
+ }
1890
+ if (!content.length) {
1891
+ const textNode = document.createTextNode("");
1892
+ content.push(textNode);
1893
+ nodeInsertBefore.call(parent, textNode, afterNode);
1894
+ }
1895
+ // remove current content
1896
+ this.remove();
1897
+ this.content = content;
1898
+ this.html = other.html;
1899
+ }
1900
+ }
1901
+ beforeRemove() { }
1902
+ remove() {
1903
+ const parent = this.parentEl;
1904
+ for (let elem of this.content) {
1905
+ nodeRemoveChild.call(parent, elem);
1906
+ }
1907
+ }
1908
+ firstNode() {
1909
+ return this.content[0];
1910
+ }
1911
+ toString() {
1912
+ return this.html;
1913
+ }
1914
+ }
1915
+ function html(str) {
1916
+ return new VHtml(str);
1917
+ }
1918
+
1919
+ function createCatcher(eventsSpec) {
1920
+ const n = Object.keys(eventsSpec).length;
1921
+ class VCatcher {
1922
+ child;
1923
+ handlerData;
1924
+ handlerFns = [];
1925
+ parentEl;
1926
+ afterNode = null;
1927
+ constructor(child, handlers) {
1928
+ this.child = child;
1929
+ this.handlerData = handlers;
1930
+ }
1931
+ mount(parent, afterNode) {
1932
+ this.parentEl = parent;
1933
+ this.child.mount(parent, afterNode);
1934
+ this.afterNode = document.createTextNode("");
1935
+ parent.insertBefore(this.afterNode, afterNode);
1936
+ this.wrapHandlerData();
1937
+ for (let name in eventsSpec) {
1938
+ const index = eventsSpec[name];
1939
+ const handler = createEventHandler(name);
1940
+ this.handlerFns[index] = handler;
1941
+ handler.setup.call(parent, this.handlerData[index]);
1942
+ }
1943
+ }
1944
+ wrapHandlerData() {
1945
+ for (let i = 0; i < n; i++) {
1946
+ let handler = this.handlerData[i];
1947
+ // handler = [...mods, fn, comp], so we need to replace second to last elem
1948
+ let idx = handler.length - 2;
1949
+ let origFn = handler[idx];
1950
+ const self = this;
1951
+ handler[idx] = function (ctx, ev) {
1952
+ const target = ev.target;
1953
+ let currentNode = self.child.firstNode();
1954
+ const afterNode = self.afterNode;
1955
+ while (currentNode && currentNode !== afterNode) {
1956
+ if (currentNode.contains(target)) {
1957
+ return origFn(ctx, ev);
1958
+ }
1959
+ currentNode = currentNode.nextSibling;
1960
+ }
1961
+ };
1962
+ }
1963
+ }
1964
+ moveBeforeDOMNode(node, parent = this.parentEl) {
1965
+ this.parentEl = parent;
1966
+ this.child.moveBeforeDOMNode(node, parent);
1967
+ parent.insertBefore(this.afterNode, node);
1968
+ }
1969
+ moveBeforeVNode(other, afterNode) {
1970
+ if (other) {
1971
+ // check this with @ged-odoo for use in foreach
1972
+ afterNode = other.firstNode() || afterNode;
1973
+ }
1974
+ this.child.moveBeforeVNode(other ? other.child : null, afterNode);
1975
+ this.parentEl.insertBefore(this.afterNode, afterNode);
1976
+ }
1977
+ patch(other, withBeforeRemove) {
1978
+ if (this === other) {
1979
+ return;
1980
+ }
1981
+ this.handlerData = other.handlerData;
1982
+ this.wrapHandlerData();
1983
+ for (let i = 0; i < n; i++) {
1984
+ this.handlerFns[i].update.call(this.parentEl, this.handlerData[i]);
1985
+ }
1986
+ this.child.patch(other.child, withBeforeRemove);
1987
+ }
1988
+ beforeRemove() {
1989
+ this.child.beforeRemove();
1990
+ }
1991
+ remove() {
1992
+ for (let i = 0; i < n; i++) {
1993
+ this.handlerFns[i].remove.call(this.parentEl);
1994
+ }
1995
+ this.child.remove();
1996
+ this.afterNode.remove();
1997
+ }
1998
+ firstNode() {
1999
+ return this.child.firstNode();
2000
+ }
2001
+ toString() {
2002
+ return this.child.toString();
2003
+ }
2004
+ }
2005
+ return function (child, handlers) {
2006
+ return new VCatcher(child, handlers);
2007
+ };
2008
+ }
2009
+
2010
+ function mount$1(vnode, fixture, afterNode = null) {
2011
+ vnode.mount(fixture, afterNode);
2012
+ }
2013
+ function patch(vnode1, vnode2, withBeforeRemove = false) {
2014
+ vnode1.patch(vnode2, withBeforeRemove);
2015
+ }
2016
+ function remove(vnode, withBeforeRemove = false) {
2017
+ if (withBeforeRemove) {
2018
+ vnode.beforeRemove();
2019
+ }
2020
+ vnode.remove();
2021
+ }
2022
+
2023
+ function makeChildFiber(node, parent) {
2024
+ let current = node.fiber;
2025
+ if (current) {
2026
+ cancelFibers(current.children);
2027
+ current.root = null;
2028
+ }
2029
+ return new Fiber(node, parent);
2030
+ }
2031
+ function makeRootFiber(node) {
2032
+ let current = node.fiber;
2033
+ if (current) {
2034
+ let root = current.root;
2035
+ // lock root fiber because canceling children fibers may destroy components,
2036
+ // which means any arbitrary code can be run in onWillDestroy, which may
2037
+ // trigger new renderings
2038
+ root.locked = true;
2039
+ root.setCounter(root.counter + 1 - cancelFibers(current.children));
2040
+ root.locked = false;
2041
+ current.children = [];
2042
+ current.childrenMap = {};
2043
+ current.bdom = null;
2044
+ if (fibersInError.has(current)) {
2045
+ fibersInError.delete(current);
2046
+ fibersInError.delete(root);
2047
+ current.appliedToDom = false;
2048
+ if (current instanceof RootFiber) {
2049
+ // it is possible that this fiber is a fiber that crashed while being
2050
+ // mounted, so the mounted list is possibly corrupted. We restore it to
2051
+ // its normal initial state (which is empty list or a list with a mount
2052
+ // fiber.
2053
+ current.mounted = current instanceof MountFiber ? [current] : [];
2054
+ }
2055
+ }
2056
+ return current;
2057
+ }
2058
+ const fiber = new RootFiber(node, null);
2059
+ if (node.willPatch.length) {
2060
+ fiber.willPatch.push(fiber);
2061
+ }
2062
+ if (node.patched.length) {
2063
+ fiber.patched.push(fiber);
2064
+ }
2065
+ return fiber;
2066
+ }
2067
+ function throwOnRender() {
2068
+ throw new OwlError("Attempted to render cancelled fiber");
2069
+ }
2070
+ /**
2071
+ * @returns number of not-yet rendered fibers cancelled
2072
+ */
2073
+ function cancelFibers(fibers) {
2074
+ let result = 0;
2075
+ for (let fiber of fibers) {
2076
+ let node = fiber.node;
2077
+ fiber.render = throwOnRender;
2078
+ if (node.status === 0 /* STATUS.NEW */) {
2079
+ node.cancel();
2080
+ }
2081
+ node.fiber = null;
2082
+ if (fiber.bdom) {
2083
+ // if fiber has been rendered, this means that the component props have
2084
+ // been updated. however, this fiber will not be patched to the dom, so
2085
+ // it could happen that the next render compare the current props with
2086
+ // the same props, and skip the render completely. With the next line,
2087
+ // we kindly request the component code to force a render, so it works as
2088
+ // expected.
2089
+ node.forceNextRender = true;
2090
+ }
2091
+ else {
2092
+ result++;
2093
+ }
2094
+ result += cancelFibers(fiber.children);
2095
+ }
2096
+ return result;
2097
+ }
2098
+ class Fiber {
2099
+ node;
2100
+ bdom = null;
2101
+ root; // A Fiber that has been replaced by another has no root
2102
+ parent;
2103
+ children = [];
2104
+ appliedToDom = false;
2105
+ deep = false;
2106
+ childrenMap = {};
2107
+ constructor(node, parent) {
2108
+ this.node = node;
2109
+ this.parent = parent;
2110
+ if (parent) {
2111
+ this.deep = parent.deep;
2112
+ const root = parent.root;
2113
+ root.setCounter(root.counter + 1);
2114
+ this.root = root;
2115
+ parent.children.push(this);
2116
+ }
2117
+ else {
2118
+ this.root = this;
2119
+ }
2120
+ }
2121
+ render() {
2122
+ // if some parent has a fiber => register in followup
2123
+ let prev = this.root.node;
2124
+ let scheduler = prev.app.scheduler;
2125
+ let current = prev.parent;
2126
+ while (current) {
2127
+ if (current.fiber) {
2128
+ let root = current.fiber.root;
2129
+ if (root.counter === 0 && prev.parentKey in current.fiber.childrenMap) {
2130
+ current = root.node;
2131
+ }
2132
+ else {
2133
+ scheduler.delayedRenders.push(this);
2134
+ return;
2135
+ }
2136
+ }
2137
+ prev = current;
2138
+ current = current.parent;
2139
+ }
2140
+ // there are no current rendering from above => we can render
2141
+ this._render();
2142
+ }
2143
+ _render() {
2144
+ const node = this.node;
2145
+ const root = this.root;
2146
+ if (root) {
2147
+ // todo: should use updateComputation somewhere else.
2148
+ const c = getCurrentComputation();
2149
+ removeSources(node.signalComputation);
2150
+ setComputation(node.signalComputation);
2151
+ try {
2152
+ this.bdom = true;
2153
+ this.bdom = node.renderFn();
2154
+ }
2155
+ catch (e) {
2156
+ node.app.handleError({ node, error: e });
2157
+ }
2158
+ setComputation(c);
2159
+ root.setCounter(root.counter - 1);
2160
+ }
2161
+ }
2162
+ }
2163
+ class RootFiber extends Fiber {
2164
+ counter = 1;
2165
+ // only add stuff in this if they have registered some hooks
2166
+ willPatch = [];
2167
+ patched = [];
2168
+ mounted = [];
2169
+ // A fiber is typically locked when it is completing and the patch has not, or is being applied.
2170
+ // i.e.: render triggered in onWillUnmount or in willPatch will be delayed
2171
+ locked = false;
2172
+ complete() {
2173
+ const node = this.node;
2174
+ this.locked = true;
2175
+ let current = undefined;
2176
+ let mountedFibers = this.mounted;
2177
+ try {
2178
+ // Step 1: calling all willPatch lifecycle hooks
2179
+ for (current of this.willPatch) {
2180
+ // because of the asynchronous nature of the rendering, some parts of the
2181
+ // UI may have been rendered, then deleted in a followup rendering, and we
2182
+ // do not want to call onWillPatch in that case.
2183
+ let node = current.node;
2184
+ if (node.fiber === current) {
2185
+ const component = node.component;
2186
+ for (let cb of node.willPatch) {
2187
+ cb.call(component);
2188
+ }
2189
+ }
2190
+ }
2191
+ current = undefined;
2192
+ // Step 2: patching the dom
2193
+ node._patch();
2194
+ this.locked = false;
2195
+ // Step 4: calling all mounted lifecycle hooks
2196
+ while ((current = mountedFibers.pop())) {
2197
+ current = current;
2198
+ if (current.appliedToDom) {
2199
+ for (let cb of current.node.mounted) {
2200
+ cb();
2201
+ }
2202
+ }
2203
+ }
2204
+ // Step 5: calling all patched hooks
2205
+ let patchedFibers = this.patched;
2206
+ while ((current = patchedFibers.pop())) {
2207
+ current = current;
2208
+ if (current.appliedToDom) {
2209
+ for (let cb of current.node.patched) {
2210
+ cb();
2211
+ }
2212
+ }
2213
+ }
2214
+ }
2215
+ catch (e) {
2216
+ // if mountedFibers is not empty, this means that a crash occured while
2217
+ // calling the mounted hooks of some component. So, there may still be
2218
+ // some component that have been mounted, but for which the mounted hooks
2219
+ // have not been called. Here, we remove the willUnmount hooks for these
2220
+ // specific component to prevent a worse situation (willUnmount being
2221
+ // called even though mounted has not been called)
2222
+ for (let fiber of mountedFibers) {
2223
+ fiber.node.willUnmount = [];
2224
+ }
2225
+ this.locked = false;
2226
+ node.app.handleError({ fiber: current || this, error: e });
2227
+ }
2228
+ }
2229
+ setCounter(newValue) {
2230
+ this.counter = newValue;
2231
+ if (newValue === 0) {
2232
+ this.node.app.scheduler.flush();
2233
+ }
2234
+ }
2235
+ }
2236
+ class MountFiber extends RootFiber {
2237
+ target;
2238
+ position;
2239
+ constructor(node, target, options = {}) {
2240
+ super(node, null);
2241
+ this.target = target;
2242
+ this.position = options.position || "last-child";
2243
+ }
2244
+ complete() {
2245
+ let current = this;
2246
+ try {
2247
+ const node = this.node;
2248
+ node.children = this.childrenMap;
2249
+ node.app.constructor.validateTarget(this.target);
2250
+ if (node.bdom) {
2251
+ // this is a complicated situation: if we mount a fiber with an existing
2252
+ // bdom, this means that this same fiber was already completed, mounted,
2253
+ // but a crash occurred in some mounted hook. Then, it was handled and
2254
+ // the new rendering is being applied.
2255
+ node.updateDom();
2256
+ }
2257
+ else {
2258
+ node.bdom = this.bdom;
2259
+ if (this.position === "last-child" || this.target.childNodes.length === 0) {
2260
+ mount$1(node.bdom, this.target);
2261
+ }
2262
+ else {
2263
+ const firstChild = this.target.childNodes[0];
2264
+ mount$1(node.bdom, this.target, firstChild);
2265
+ }
2266
+ }
2267
+ // unregistering the fiber before mounted since it can do another render
2268
+ // and that the current rendering is obviously completed
2269
+ node.fiber = null;
2270
+ node.status = 1 /* STATUS.MOUNTED */;
2271
+ this.appliedToDom = true;
2272
+ let mountedFibers = this.mounted;
2273
+ while ((current = mountedFibers.pop())) {
2274
+ if (current.appliedToDom) {
2275
+ for (let cb of current.node.mounted) {
2276
+ cb();
2277
+ }
2278
+ }
2279
+ }
2280
+ }
2281
+ catch (e) {
2282
+ this.node.app.handleError({ fiber: current, error: e });
2283
+ }
2284
+ }
2285
+ }
2286
+
2287
+ class ComponentNode {
2288
+ el;
2289
+ app;
2290
+ fiber = null;
2291
+ component;
2292
+ bdom = null;
2293
+ status = 0 /* STATUS.NEW */;
2294
+ forceNextRender = false;
2295
+ parentKey;
2296
+ props;
2297
+ defaultProps = {};
2298
+ renderFn;
2299
+ parent;
2300
+ children = Object.create(null);
2301
+ willStart = [];
2302
+ willUpdateProps = [];
2303
+ willUnmount = [];
2304
+ mounted = [];
2305
+ willPatch = [];
2306
+ patched = [];
2307
+ willDestroy = [];
2308
+ signalComputation;
2309
+ computations = [];
2310
+ pluginManager;
2311
+ constructor(C, props, app, parent, parentKey) {
2312
+ this.app = app;
2313
+ this.parent = parent;
2314
+ this.parentKey = parentKey;
2315
+ this.pluginManager = parent ? parent.pluginManager : app.pluginManager;
2316
+ this.signalComputation = createComputation(() => this.render(false), false, ComputationState.EXECUTED);
2317
+ this.props = props;
2318
+ contextStack.push({
2319
+ type: "component",
2320
+ app,
2321
+ componentName: C.name,
2322
+ node: this,
2323
+ get status() {
2324
+ return this.node.status;
2325
+ },
2326
+ });
2327
+ const previousComputation = getCurrentComputation();
2328
+ setComputation(undefined);
2329
+ this.component = new C(this);
2330
+ const ctx = { this: this.component, __owl__: this };
2331
+ this.renderFn = app.getTemplate(C.template).bind(this.component, ctx, this);
2332
+ this.component.setup();
2333
+ setComputation(previousComputation);
2334
+ contextStack.length = 0; // clear context stack
2335
+ }
2336
+ mountComponent(target, options) {
2337
+ const fiber = new MountFiber(this, target, options);
2338
+ this.app.scheduler.addFiber(fiber);
2339
+ let prev = getCurrentComputation();
2340
+ this.initiateRender(fiber);
2341
+ // only useful if the component is a root, and a willstart function just
2342
+ // crashed synchonously. In that case, it is possible that the previous
2343
+ // computation has not been properly restored
2344
+ setComputation(prev);
2345
+ }
2346
+ async initiateRender(fiber) {
2347
+ this.fiber = fiber;
2348
+ if (this.mounted.length) {
2349
+ fiber.root.mounted.push(fiber);
2350
+ }
2351
+ const component = this.component;
2352
+ let prev = getCurrentComputation();
2353
+ setComputation(undefined);
2354
+ try {
2355
+ let promises = this.willStart.map((f) => f.call(component));
2356
+ setComputation(prev);
2357
+ await Promise.all(promises);
2358
+ }
2359
+ catch (e) {
2360
+ this.app.handleError({ node: this, error: e });
2361
+ return;
2362
+ }
2363
+ if (this.status === 0 /* STATUS.NEW */ && this.fiber === fiber) {
2364
+ fiber.render();
2365
+ }
2366
+ }
2367
+ async render(deep) {
2368
+ if (this.status >= 2 /* STATUS.CANCELLED */) {
2369
+ return;
2370
+ }
2371
+ let current = this.fiber;
2372
+ if (current && (current.root.locked || current.bdom === true)) {
2373
+ await Promise.resolve();
2374
+ // situation may have changed after the microtask tick
2375
+ current = this.fiber;
2376
+ }
2377
+ if (current) {
2378
+ if (!current.bdom && !fibersInError.has(current)) {
2379
+ if (deep) {
2380
+ // we want the render from this point on to be with deep=true
2381
+ current.deep = deep;
2382
+ }
2383
+ return;
2384
+ }
2385
+ // if current rendering was with deep=true, we want this one to be the same
2386
+ deep = deep || current.deep;
2387
+ }
2388
+ else if (!this.bdom) {
2389
+ return;
2390
+ }
2391
+ const fiber = makeRootFiber(this);
2392
+ fiber.deep = deep;
2393
+ this.fiber = fiber;
2394
+ this.app.scheduler.addFiber(fiber);
2395
+ await Promise.resolve();
2396
+ if (this.status >= 2 /* STATUS.CANCELLED */) {
2397
+ return;
2398
+ }
2399
+ // We only want to actually render the component if the following two
2400
+ // conditions are true:
2401
+ // * this.fiber: it could be null, in which case the render has been cancelled
2402
+ // * (current || !fiber.parent): if current is not null, this means that the
2403
+ // render function was called when a render was already occurring. In this
2404
+ // case, the pending rendering was cancelled, and the fiber needs to be
2405
+ // rendered to complete the work. If current is null, we check that the
2406
+ // fiber has no parent. If that is the case, the fiber was downgraded from
2407
+ // a root fiber to a child fiber in the previous microtick, because it was
2408
+ // embedded in a rendering coming from above, so the fiber will be rendered
2409
+ // in the next microtick anyway, so we should not render it again.
2410
+ if (this.fiber === fiber && (current || !fiber.parent)) {
2411
+ fiber.render();
2412
+ }
2413
+ }
2414
+ cancel() {
2415
+ this._cancel();
2416
+ delete this.parent.children[this.parentKey];
2417
+ this.app.scheduler.scheduleDestroy(this);
2418
+ }
2419
+ _cancel() {
2420
+ this.status = 2 /* STATUS.CANCELLED */;
2421
+ const children = this.children;
2422
+ for (let childKey in children) {
2423
+ children[childKey]._cancel();
2424
+ }
2425
+ }
2426
+ destroy() {
2427
+ let shouldRemove = this.status === 1 /* STATUS.MOUNTED */;
2428
+ this._destroy();
2429
+ if (shouldRemove) {
2430
+ this.bdom.remove();
2431
+ }
2432
+ }
2433
+ _destroy() {
2434
+ const component = this.component;
2435
+ if (this.status === 1 /* STATUS.MOUNTED */) {
2436
+ for (let cb of this.willUnmount) {
2437
+ cb.call(component);
2438
+ }
2439
+ }
2440
+ for (let childKey in this.children) {
2441
+ this.children[childKey]._destroy();
2442
+ }
2443
+ if (this.willDestroy.length) {
2444
+ try {
2445
+ for (let cb of this.willDestroy) {
2446
+ cb.call(component);
2447
+ }
2448
+ }
2449
+ catch (e) {
2450
+ this.app.handleError({ error: e, node: this });
2451
+ }
2452
+ }
2453
+ for (const computation of this.computations) {
2454
+ disposeComputation(computation);
2455
+ }
2456
+ disposeComputation(this.signalComputation);
2457
+ this.status = 3 /* STATUS.DESTROYED */;
2458
+ }
2459
+ async updateAndRender(props, parentFiber) {
2460
+ props = Object.assign({}, props);
2461
+ for (const key in this.defaultProps) {
2462
+ if (props[key] === undefined) {
2463
+ props[key] = this.defaultProps[key];
2464
+ }
2465
+ }
2466
+ // update
2467
+ const fiber = makeChildFiber(this, parentFiber);
2468
+ this.fiber = fiber;
2469
+ const component = this.component;
2470
+ let prev = getCurrentComputation();
2471
+ setComputation(undefined);
2472
+ let promises = this.willUpdateProps.map((f) => f.call(component, props));
2473
+ setComputation(prev);
2474
+ await Promise.all(promises);
2475
+ if (fiber !== this.fiber) {
2476
+ return;
2477
+ }
2478
+ this.props = props;
2479
+ fiber.render();
2480
+ const parentRoot = parentFiber.root;
2481
+ if (this.willPatch.length) {
2482
+ parentRoot.willPatch.push(fiber);
2483
+ }
2484
+ if (this.patched.length) {
2485
+ parentRoot.patched.push(fiber);
2486
+ }
2487
+ }
2488
+ /**
2489
+ * Finds a child that has dom that is not yet updated, and update it. This
2490
+ * method is meant to be used only in the context of repatching the dom after
2491
+ * a mounted hook failed and was handled.
2492
+ */
2493
+ updateDom() {
2494
+ if (!this.fiber) {
2495
+ return;
2496
+ }
2497
+ if (this.bdom === this.fiber.bdom) {
2498
+ // If the error was handled by some child component, we need to find it to
2499
+ // apply its change
2500
+ for (let k in this.children) {
2501
+ const child = this.children[k];
2502
+ child.updateDom();
2503
+ }
2504
+ }
2505
+ else {
2506
+ // if we get here, this is the component that handled the error and rerendered
2507
+ // itself, so we can simply patch the dom
2508
+ this.bdom.patch(this.fiber.bdom, false);
2509
+ this.fiber.appliedToDom = true;
2510
+ this.fiber = null;
2511
+ }
2512
+ }
2513
+ // ---------------------------------------------------------------------------
2514
+ // Block DOM methods
2515
+ // ---------------------------------------------------------------------------
2516
+ firstNode() {
2517
+ const bdom = this.bdom;
2518
+ return bdom ? bdom.firstNode() : undefined;
2519
+ }
2520
+ mount(parent, anchor) {
2521
+ const bdom = this.fiber.bdom;
2522
+ this.bdom = bdom;
2523
+ bdom.mount(parent, anchor);
2524
+ this.status = 1 /* STATUS.MOUNTED */;
2525
+ this.fiber.appliedToDom = true;
2526
+ this.children = this.fiber.childrenMap;
2527
+ this.fiber = null;
2528
+ }
2529
+ moveBeforeDOMNode(node, parent) {
2530
+ this.bdom.moveBeforeDOMNode(node, parent);
2531
+ }
2532
+ moveBeforeVNode(other, afterNode) {
2533
+ this.bdom.moveBeforeVNode(other ? other.bdom : null, afterNode);
2534
+ }
2535
+ patch() {
2536
+ if (this.fiber && this.fiber.parent) {
2537
+ // we only patch here renderings coming from above. renderings initiated
2538
+ // by the component will be patched independently in the appropriate
2539
+ // fiber.complete
2540
+ this._patch();
2541
+ }
2542
+ }
2543
+ _patch() {
2544
+ let hasChildren = false;
2545
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
2546
+ for (let _k in this.children) {
2547
+ hasChildren = true;
2548
+ break;
2549
+ }
2550
+ const fiber = this.fiber;
2551
+ this.children = fiber.childrenMap;
2552
+ this.bdom.patch(fiber.bdom, hasChildren);
2553
+ fiber.appliedToDom = true;
2554
+ this.fiber = null;
2555
+ }
2556
+ beforeRemove() {
2557
+ this._destroy();
2558
+ }
2559
+ remove() {
2560
+ this.bdom.remove();
2561
+ }
2562
+ }
2563
+
2564
+ function effect(fn) {
2565
+ const computation = createComputation(() => {
2566
+ // In case the cleanup read an atom.
2567
+ // todo: test it
2568
+ setComputation(undefined);
2569
+ unsubscribeEffect(computation);
2570
+ setComputation(computation);
2571
+ return fn();
2572
+ }, false);
2573
+ getCurrentComputation()?.observers.add(computation);
2574
+ updateComputation(computation);
2575
+ // Remove sources and unsubscribe
2576
+ return function cleanupEffect() {
2577
+ // In case the cleanup read an atom.
2578
+ // todo: test it
2579
+ const previousComputation = getCurrentComputation();
2580
+ setComputation(undefined);
2581
+ unsubscribeEffect(computation);
2582
+ setComputation(previousComputation);
2583
+ };
2584
+ }
2585
+ function unsubscribeEffect(effect) {
2586
+ removeSources(effect);
2587
+ cleanupEffect(effect);
2588
+ for (const childEffect of effect.observers) {
2589
+ // Consider it executed to avoid it's re-execution
2590
+ // todo: make a test for it
2591
+ childEffect.state = ComputationState.EXECUTED;
2592
+ removeSources(childEffect);
2593
+ unsubscribeEffect(childEffect);
2594
+ }
2595
+ effect.observers.clear();
2596
+ }
2597
+ function cleanupEffect(effect) {
2598
+ // the computation.value of an effect is a cleanup function
2599
+ const cleanupFn = effect.value;
2600
+ if (cleanupFn && typeof cleanupFn === "function") {
2601
+ cleanupFn();
2602
+ effect.value = undefined;
2603
+ }
2604
+ }
2605
+
2606
+ class Plugin {
2607
+ static _shadowId;
2608
+ static get id() {
2609
+ return this._shadowId ?? this.name;
2610
+ }
2611
+ static set id(shadowId) {
2612
+ this._shadowId = shadowId;
2613
+ }
2614
+ __owl__;
2615
+ constructor(manager) {
2616
+ this.__owl__ = manager;
2617
+ }
2618
+ setup() { }
2619
+ }
2620
+ class PluginManager {
2621
+ app;
2622
+ config;
2623
+ onDestroyCb = [];
2624
+ computations = [];
2625
+ plugins;
2626
+ status = 0 /* STATUS.NEW */;
2627
+ constructor(app, options = {}) {
2628
+ this.app = app;
2629
+ this.config = options.config ?? {};
2630
+ if (options.parent) {
2631
+ const parent = options.parent;
2632
+ parent.onDestroyCb.push(() => this.destroy());
2633
+ this.plugins = Object.create(parent.plugins);
2634
+ }
2635
+ else {
2636
+ this.plugins = {};
2637
+ }
2638
+ }
2639
+ destroy() {
2640
+ const cbs = this.onDestroyCb;
2641
+ while (cbs.length) {
2642
+ cbs.pop()();
2643
+ }
2644
+ for (const computation of this.computations) {
2645
+ disposeComputation(computation);
2646
+ }
2647
+ this.status = 3 /* STATUS.DESTROYED */;
2648
+ }
2649
+ getPluginById(id) {
2650
+ return this.plugins[id] || null;
2651
+ }
2652
+ getPlugin(pluginConstructor) {
2653
+ return this.getPluginById(pluginConstructor.id);
2654
+ }
2655
+ startPlugin(pluginConstructor) {
2656
+ if (!pluginConstructor.id) {
2657
+ throw new OwlError(`Plugin "${pluginConstructor.name}" has no id`);
2658
+ }
2659
+ if (this.plugins.hasOwnProperty(pluginConstructor.id)) {
2660
+ const existingPluginType = this.getPluginById(pluginConstructor.id).constructor;
2661
+ if (existingPluginType !== pluginConstructor) {
2662
+ throw new OwlError(`Trying to start a plugin with the same id as an other plugin (id: '${pluginConstructor.id}', existing plugin: '${existingPluginType.name}', starting plugin: '${pluginConstructor.name}')`);
2663
+ }
2664
+ return null;
2665
+ }
2666
+ const plugin = new pluginConstructor(this);
2667
+ this.plugins[pluginConstructor.id] = plugin;
2668
+ plugin.setup();
2669
+ return plugin;
2670
+ }
2671
+ startPlugins(pluginConstructors) {
2672
+ contextStack.push({
2673
+ type: "plugin",
2674
+ app: this.app,
2675
+ manager: this,
2676
+ get status() {
2677
+ return this.manager.status;
2678
+ },
2679
+ });
2680
+ try {
2681
+ for (const pluginConstructor of pluginConstructors) {
2682
+ this.startPlugin(pluginConstructor);
2683
+ }
2684
+ }
2685
+ finally {
2686
+ contextStack.pop();
2687
+ }
2688
+ this.status = 1 /* STATUS.MOUNTED */;
2689
+ }
2690
+ }
2691
+ function startPlugins(manager, plugins) {
2692
+ if (Array.isArray(plugins)) {
2693
+ manager.startPlugins(plugins);
2694
+ }
2695
+ else {
2696
+ manager.onDestroyCb.push(effect(() => {
2697
+ const pluginItems = plugins.items();
2698
+ untrack(() => manager.startPlugins(pluginItems));
2699
+ }));
2700
+ }
2701
+ }
2702
+
2703
+ // Special key to subscribe to, to be notified of key creation/deletion
2704
+ const KEYCHANGES = Symbol("Key changes");
2705
+ const objectToString = Object.prototype.toString;
2706
+ const objectHasOwnProperty = Object.prototype.hasOwnProperty;
2707
+ /**
2708
+ * Checks whether a given value can be made into a proxy object.
2709
+ *
2710
+ * @param value the value to check
2711
+ * @returns whether the value can be made proxy
2712
+ */
2713
+ function canBeMadeReactive(value) {
2714
+ if (typeof value !== "object" || value === null) {
2715
+ return false;
2716
+ }
2717
+ const raw = toRaw(value);
2718
+ if (Array.isArray(raw) || raw instanceof Set || raw instanceof Map || raw instanceof WeakMap) {
2719
+ return true;
2720
+ }
2721
+ return objectToString.call(raw) === "[object Object]";
2722
+ }
2723
+ /**
2724
+ * Creates a proxy from the given object/callback if possible and returns it,
2725
+ * returns the original object otherwise.
2726
+ *
2727
+ * @param value the value make proxy
2728
+ * @returns a proxy for the given object when possible, the original otherwise
2729
+ */
2730
+ function possiblyReactive(val, atom) {
2731
+ return !atom && canBeMadeReactive(val) ? proxy(val) : val;
2732
+ }
2733
+ const skipped = new WeakSet();
2734
+ /**
2735
+ * Mark an object or array so that it is ignored by the reactivity system
2736
+ *
2737
+ * @param value the value to mark
2738
+ * @returns the object itself
2739
+ */
2740
+ function markRaw(value) {
2741
+ skipped.add(value);
2742
+ return value;
2743
+ }
2744
+ /**
2745
+ * Given a proxy objet, return the raw (non proxy) underlying object
2746
+ *
2747
+ * @param value a proxy value
2748
+ * @returns the underlying value
2749
+ */
2750
+ function toRaw(value) {
2751
+ return targets.has(value) ? targets.get(value) : value;
2752
+ }
2753
+ const targetToKeysToAtomItem = new WeakMap();
2754
+ function getTargetKeyAtom(target, key) {
2755
+ let keyToAtomItem = targetToKeysToAtomItem.get(target);
2756
+ if (!keyToAtomItem) {
2757
+ keyToAtomItem = new Map();
2758
+ targetToKeysToAtomItem.set(target, keyToAtomItem);
2759
+ }
2760
+ let atom = keyToAtomItem.get(key);
2761
+ if (!atom) {
2762
+ atom = {
2763
+ value: undefined,
2764
+ observers: new Set(),
2765
+ };
2766
+ keyToAtomItem.set(key, atom);
2767
+ }
2768
+ return atom;
2769
+ }
2770
+ /**
2771
+ * Observes a given key on a target with an callback. The callback will be
2772
+ * called when the given key changes on the target.
2773
+ *
2774
+ * @param target the target whose key should be observed
2775
+ * @param key the key to observe (or Symbol(KEYCHANGES) for key creation
2776
+ * or deletion)
2777
+ * @param callback the function to call when the key changes
2778
+ */
2779
+ function onReadTargetKey(target, key, atom) {
2780
+ onReadAtom(atom ?? getTargetKeyAtom(target, key));
2781
+ }
2782
+ /**
2783
+ * Notify Reactives that are observing a given target that a key has changed on
2784
+ * the target.
2785
+ *
2786
+ * @param target target whose Reactives should be notified that the target was
2787
+ * changed.
2788
+ * @param key the key that changed (or Symbol `KEYCHANGES` if a key was created
2789
+ * or deleted)
2790
+ */
2791
+ function onWriteTargetKey(target, key, atom) {
2792
+ if (!atom) {
2793
+ const keyToAtomItem = targetToKeysToAtomItem.get(target);
2794
+ if (!keyToAtomItem) {
2795
+ return;
2796
+ }
2797
+ if (!keyToAtomItem.has(key)) {
2798
+ return;
2799
+ }
2800
+ atom = keyToAtomItem.get(key);
2801
+ }
2802
+ onWriteAtom(atom);
2803
+ }
2804
+ // Maps proxy objects to the underlying target
2805
+ const targets = new WeakMap();
2806
+ const proxyCache = new WeakMap();
2807
+ function proxifyTarget(target, atom) {
2808
+ if (!canBeMadeReactive(target)) {
2809
+ throw new OwlError(`Cannot make the given value reactive`);
2810
+ }
2811
+ if (skipped.has(target)) {
2812
+ return target;
2813
+ }
2814
+ if (targets.has(target)) {
2815
+ // target is reactive, create a reactive on the underlying object instead
2816
+ return target;
2817
+ }
2818
+ const reactive = proxyCache.get(target);
2819
+ if (reactive) {
2820
+ return reactive;
2821
+ }
2822
+ let handler;
2823
+ if (target instanceof Map) {
2824
+ handler = collectionsProxyHandler(target, "Map", atom);
2825
+ }
2826
+ else if (target instanceof Set) {
2827
+ handler = collectionsProxyHandler(target, "Set", atom);
2828
+ }
2829
+ else if (target instanceof WeakMap) {
2830
+ handler = collectionsProxyHandler(target, "WeakMap", atom);
2831
+ }
2832
+ else {
2833
+ handler = basicProxyHandler(atom);
2834
+ }
2835
+ const proxy = new Proxy(target, handler);
2836
+ proxyCache.set(target, proxy);
2837
+ targets.set(proxy, target);
2838
+ return proxy;
2839
+ }
2840
+ /**
2841
+ * Creates a reactive proxy for an object. Reading data on the proxy object
2842
+ * subscribes to changes to the data. Writing data on the object will cause the
2843
+ * notify callback to be called if there are suscriptions to that data. Nested
2844
+ * objects and arrays are automatically made reactive as well.
2845
+ *
2846
+ * Whenever you are notified of a change, all subscriptions are cleared, and if
2847
+ * you would like to be notified of any further changes, you should go read
2848
+ * the underlying data again. We assume that if you don't go read it again after
2849
+ * being notified, it means that you are no longer interested in that data.
2850
+ *
2851
+ * Subscriptions:
2852
+ * + Reading a property on an object will subscribe you to changes in the value
2853
+ * of that property.
2854
+ * + Accessing an object's keys (eg with Object.keys or with `for..in`) will
2855
+ * subscribe you to the creation/deletion of keys. Checking the presence of a
2856
+ * key on the object with 'in' has the same effect.
2857
+ * - getOwnPropertyDescriptor does not currently subscribe you to the property.
2858
+ * This is a choice that was made because changing a key's value will trigger
2859
+ * this trap and we do not want to subscribe by writes. This also means that
2860
+ * Object.hasOwnProperty doesn't subscribe as it goes through this trap.
2861
+ *
2862
+ * @param target the object for which to create a proxy proxy
2863
+ * @param callback the function to call when an observed property of the
2864
+ * proxy has changed
2865
+ * @returns a proxy that tracks changes to it
2866
+ */
2867
+ function proxy(target) {
2868
+ return proxifyTarget(target, null);
2869
+ }
2870
+ /**
2871
+ * Creates a basic proxy handler for regular objects and arrays.
2872
+ *
2873
+ * @param callback @see proxy
2874
+ * @returns a proxy handler object
2875
+ */
2876
+ function basicProxyHandler(atom) {
2877
+ return {
2878
+ get(target, key, receiver) {
2879
+ onReadTargetKey(target, key, atom);
2880
+ const value = Reflect.get(target, key, receiver);
2881
+ // Fast path: signal-based proxies and primitive values don't need wrapping
2882
+ if (atom || typeof value !== "object" || value === null) {
2883
+ return value;
2884
+ }
2885
+ if (!canBeMadeReactive(value)) {
2886
+ return value;
2887
+ }
2888
+ // non-writable non-configurable properties cannot be made proxy
2889
+ const desc = Object.getOwnPropertyDescriptor(target, key);
2890
+ if (desc && !desc.writable && !desc.configurable) {
2891
+ return value;
2892
+ }
2893
+ return proxifyTarget(value, null);
2894
+ },
2895
+ set(target, key, value, receiver) {
2896
+ const hadKey = objectHasOwnProperty.call(target, key);
2897
+ const originalValue = Reflect.get(target, key, receiver);
2898
+ const ret = Reflect.set(target, key, toRaw(value), receiver);
2899
+ if (!hadKey && objectHasOwnProperty.call(target, key)) {
2900
+ onWriteTargetKey(target, KEYCHANGES, atom);
2901
+ }
2902
+ // While Array length may trigger the set trap, it's not actually set by this
2903
+ // method but is updated behind the scenes, and the trap is not called with the
2904
+ // new value. We disable the "same-value-optimization" for it because of that.
2905
+ if (originalValue !== Reflect.get(target, key, receiver) ||
2906
+ (key === "length" && Array.isArray(target))) {
2907
+ onWriteTargetKey(target, key, atom);
2908
+ }
2909
+ return ret;
2910
+ },
2911
+ deleteProperty(target, key) {
2912
+ const ret = Reflect.deleteProperty(target, key);
2913
+ // TODO: only notify when something was actually deleted
2914
+ onWriteTargetKey(target, KEYCHANGES, atom);
2915
+ onWriteTargetKey(target, key, atom);
2916
+ return ret;
2917
+ },
2918
+ ownKeys(target) {
2919
+ onReadTargetKey(target, KEYCHANGES, atom);
2920
+ return Reflect.ownKeys(target);
2921
+ },
2922
+ has(target, key) {
2923
+ // TODO: this observes all key changes instead of only the presence of the argument key
2924
+ // observing the key itself would observe value changes instead of presence changes
2925
+ // so we may need a finer grained system to distinguish observing value vs presence.
2926
+ onReadTargetKey(target, KEYCHANGES, atom);
2927
+ return Reflect.has(target, key);
2928
+ },
2929
+ };
2930
+ }
2931
+ /**
2932
+ * Creates a function that will observe the key that is passed to it when called
2933
+ * and delegates to the underlying method.
2934
+ *
2935
+ * @param methodName name of the method to delegate to
2936
+ * @param target @see proxy
2937
+ * @param callback @see proxy
2938
+ */
2939
+ function makeKeyObserver(methodName, target, atom) {
2940
+ return (key) => {
2941
+ key = toRaw(key);
2942
+ onReadTargetKey(target, key, atom);
2943
+ return possiblyReactive(target[methodName](key), atom);
2944
+ };
2945
+ }
2946
+ /**
2947
+ * Creates an iterable that will delegate to the underlying iteration method and
2948
+ * observe keys as necessary.
2949
+ *
2950
+ * @param methodName name of the method to delegate to
2951
+ * @param target @see proxy
2952
+ * @param callback @see proxy
2953
+ */
2954
+ function makeIteratorObserver(methodName, target, atom) {
2955
+ return function* () {
2956
+ onReadTargetKey(target, KEYCHANGES, atom);
2957
+ const keys = target.keys();
2958
+ for (const item of target[methodName]()) {
2959
+ const key = keys.next().value;
2960
+ onReadTargetKey(target, key, atom);
2961
+ yield possiblyReactive(item, atom);
2962
+ }
2963
+ };
2964
+ }
2965
+ /**
2966
+ * Creates a forEach function that will delegate to forEach on the underlying
2967
+ * collection while observing key changes, and keys as they're iterated over,
2968
+ * and making the passed keys/values proxy.
2969
+ *
2970
+ * @param target @see proxy
2971
+ * @param callback @see proxy
2972
+ */
2973
+ function makeForEachObserver(target, atom) {
2974
+ return function forEach(forEachCb, thisArg) {
2975
+ onReadTargetKey(target, KEYCHANGES, atom);
2976
+ target.forEach(function (val, key, targetObj) {
2977
+ onReadTargetKey(target, key, atom);
2978
+ forEachCb.call(thisArg, possiblyReactive(val, atom), possiblyReactive(key, atom), possiblyReactive(targetObj, atom));
2979
+ }, thisArg);
2980
+ };
2981
+ }
2982
+ /**
2983
+ * Creates a function that will delegate to an underlying method, and check if
2984
+ * that method has modified the presence or value of a key, and notify the
2985
+ * proxys appropriately.
2986
+ *
2987
+ * @param setterName name of the method to delegate to
2988
+ * @param getterName name of the method which should be used to retrieve the
2989
+ * value before calling the delegate method for comparison purposes
2990
+ * @param target @see proxy
2991
+ */
2992
+ function delegateAndNotify(setterName, getterName, target, atom) {
2993
+ return (key, value) => {
2994
+ key = toRaw(key);
2995
+ const hadKey = target.has(key);
2996
+ const originalValue = target[getterName](key);
2997
+ const ret = target[setterName](key, value);
2998
+ const hasKey = target.has(key);
2999
+ if (hadKey !== hasKey) {
3000
+ onWriteTargetKey(target, KEYCHANGES, atom);
3001
+ }
3002
+ if (originalValue !== target[getterName](key)) {
3003
+ onWriteTargetKey(target, key, atom);
3004
+ }
3005
+ return ret;
3006
+ };
3007
+ }
3008
+ /**
3009
+ * Creates a function that will clear the underlying collection and notify that
3010
+ * the keys of the collection have changed.
3011
+ *
3012
+ * @param target @see proxy
3013
+ */
3014
+ function makeClearNotifier(target, atom) {
3015
+ return () => {
3016
+ const allKeys = [...target.keys()];
3017
+ target.clear();
3018
+ onWriteTargetKey(target, KEYCHANGES, atom);
3019
+ for (const key of allKeys) {
3020
+ onWriteTargetKey(target, key, atom);
3021
+ }
3022
+ };
3023
+ }
3024
+ /**
3025
+ * Maps raw type of an object to an object containing functions that can be used
3026
+ * to build an appropritate proxy handler for that raw type. Eg: when making a
3027
+ * proxy set, calling the has method should mark the key that is being
3028
+ * retrieved as observed, and calling the add or delete method should notify the
3029
+ * proxys that the key which is being added or deleted has been modified.
3030
+ */
3031
+ const rawTypeToFuncHandlers = {
3032
+ Set: (target, atom) => ({
3033
+ has: makeKeyObserver("has", target, atom),
3034
+ add: delegateAndNotify("add", "has", target, atom),
3035
+ delete: delegateAndNotify("delete", "has", target, atom),
3036
+ keys: makeIteratorObserver("keys", target, atom),
3037
+ values: makeIteratorObserver("values", target, atom),
3038
+ entries: makeIteratorObserver("entries", target, atom),
3039
+ [Symbol.iterator]: makeIteratorObserver(Symbol.iterator, target, atom),
3040
+ forEach: makeForEachObserver(target, atom),
3041
+ clear: makeClearNotifier(target, atom),
3042
+ get size() {
3043
+ onReadTargetKey(target, KEYCHANGES, atom);
3044
+ return target.size;
3045
+ },
3046
+ }),
3047
+ Map: (target, atom) => ({
3048
+ has: makeKeyObserver("has", target, atom),
3049
+ get: makeKeyObserver("get", target, atom),
3050
+ set: delegateAndNotify("set", "get", target, atom),
3051
+ delete: delegateAndNotify("delete", "has", target, atom),
3052
+ keys: makeIteratorObserver("keys", target, atom),
3053
+ values: makeIteratorObserver("values", target, atom),
3054
+ entries: makeIteratorObserver("entries", target, atom),
3055
+ [Symbol.iterator]: makeIteratorObserver(Symbol.iterator, target, atom),
3056
+ forEach: makeForEachObserver(target, atom),
3057
+ clear: makeClearNotifier(target, atom),
3058
+ get size() {
3059
+ onReadTargetKey(target, KEYCHANGES, atom);
3060
+ return target.size;
3061
+ },
3062
+ }),
3063
+ WeakMap: (target, atom) => ({
3064
+ has: makeKeyObserver("has", target, atom),
3065
+ get: makeKeyObserver("get", target, atom),
3066
+ set: delegateAndNotify("set", "get", target, atom),
3067
+ delete: delegateAndNotify("delete", "has", target, atom),
3068
+ }),
3069
+ };
3070
+ /**
3071
+ * Creates a proxy handler for collections (Set/Map/WeakMap)
3072
+ *
3073
+ * @param callback @see proxy
3074
+ * @param target @see proxy
3075
+ * @returns a proxy handler object
3076
+ */
3077
+ function collectionsProxyHandler(target, targetRawType, atom) {
3078
+ // TODO: if performance is an issue we can create the special handlers lazily when each
3079
+ // property is read.
3080
+ const specialHandlers = rawTypeToFuncHandlers[targetRawType](target, atom);
3081
+ return Object.assign(basicProxyHandler(atom), {
3082
+ // FIXME: probably broken when part of prototype chain since we ignore the receiver
3083
+ get(target, key) {
3084
+ if (objectHasOwnProperty.call(specialHandlers, key)) {
3085
+ return specialHandlers[key];
3086
+ }
3087
+ onReadTargetKey(target, key, atom);
3088
+ return possiblyReactive(target[key], atom);
3089
+ },
3090
+ });
3091
+ }
3092
+
3093
+ // -----------------------------------------------------------------------------
3094
+ // Scheduler
3095
+ // -----------------------------------------------------------------------------
3096
+ let requestAnimationFrame;
3097
+ if (typeof window !== "undefined") {
3098
+ requestAnimationFrame = window.requestAnimationFrame.bind(window);
3099
+ }
3100
+ class Scheduler {
3101
+ // capture the value of requestAnimationFrame as soon as possible, to avoid
3102
+ // interactions with other code, such as test frameworks that override them
3103
+ static requestAnimationFrame = requestAnimationFrame;
3104
+ tasks = new Set();
3105
+ requestAnimationFrame;
3106
+ frame = 0;
3107
+ delayedRenders = [];
3108
+ cancelledNodes = new Set();
3109
+ processing = false;
3110
+ constructor() {
3111
+ this.requestAnimationFrame = Scheduler.requestAnimationFrame;
3112
+ }
3113
+ addFiber(fiber) {
3114
+ this.tasks.add(fiber.root);
3115
+ }
3116
+ scheduleDestroy(node) {
3117
+ this.cancelledNodes.add(node);
3118
+ if (this.frame === 0) {
3119
+ this.frame = this.requestAnimationFrame(() => this.processTasks());
3120
+ }
3121
+ }
3122
+ /**
3123
+ * Process all current tasks. This only applies to the fibers that are ready.
3124
+ * Other tasks are left unchanged.
3125
+ */
3126
+ flush() {
3127
+ if (this.delayedRenders.length) {
3128
+ let renders = this.delayedRenders;
3129
+ this.delayedRenders = [];
3130
+ for (let f of renders) {
3131
+ if (f.root && f.node.status !== 3 /* STATUS.DESTROYED */ && f.node.fiber === f) {
3132
+ f.render();
3133
+ }
3134
+ }
3135
+ }
3136
+ if (this.frame === 0) {
3137
+ this.frame = this.requestAnimationFrame(() => this.processTasks());
3138
+ }
3139
+ }
3140
+ processTasks() {
3141
+ if (this.processing) {
3142
+ return;
3143
+ }
3144
+ this.processing = true;
3145
+ this.frame = 0;
3146
+ for (let node of this.cancelledNodes) {
3147
+ node._destroy();
3148
+ }
3149
+ this.cancelledNodes.clear();
3150
+ for (let task of this.tasks) {
3151
+ this.processFiber(task);
3152
+ }
3153
+ for (let task of this.tasks) {
3154
+ if (task.node.status === 3 /* STATUS.DESTROYED */) {
3155
+ this.tasks.delete(task);
3156
+ }
3157
+ }
3158
+ this.processing = false;
3159
+ }
3160
+ processFiber(fiber) {
3161
+ if (fiber.root !== fiber) {
3162
+ this.tasks.delete(fiber);
3163
+ return;
3164
+ }
3165
+ const hasError = fibersInError.has(fiber);
3166
+ if (hasError && fiber.counter !== 0) {
3167
+ this.tasks.delete(fiber);
3168
+ return;
3169
+ }
3170
+ if (fiber.node.status === 3 /* STATUS.DESTROYED */) {
3171
+ this.tasks.delete(fiber);
3172
+ return;
3173
+ }
3174
+ if (fiber.counter === 0) {
3175
+ if (!hasError) {
3176
+ fiber.complete();
3177
+ }
3178
+ // at this point, the fiber should have been applied to the DOM, so we can
3179
+ // remove it from the task list. If it is not the case, it means that there
3180
+ // was an error and an error handler triggered a new rendering that recycled
3181
+ // the fiber, so in that case, we actually want to keep the fiber around,
3182
+ // otherwise it will just be ignored.
3183
+ if (fiber.appliedToDom) {
3184
+ this.tasks.delete(fiber);
3185
+ }
3186
+ }
3187
+ }
3188
+ }
3189
+
3190
+ /**
3191
+ * Parses an XML string into an XML document, throwing errors on parser errors
3192
+ * instead of returning an XML document containing the parseerror.
3193
+ *
3194
+ * @param xml the string to parse
3195
+ * @returns an XML document corresponding to the content of the string
3196
+ */
3197
+ function parseXML(xml) {
3198
+ const parser = new DOMParser();
3199
+ const doc = parser.parseFromString(xml, "text/xml");
3200
+ if (doc.getElementsByTagName("parsererror").length) {
3201
+ let msg = "Invalid XML in template.";
3202
+ const parsererrorText = doc.getElementsByTagName("parsererror")[0].textContent;
3203
+ if (parsererrorText) {
3204
+ msg += "\nThe parser has produced the following error message:\n" + parsererrorText;
3205
+ const re = /\d+/g;
3206
+ const firstMatch = re.exec(parsererrorText);
3207
+ if (firstMatch) {
3208
+ const lineNumber = Number(firstMatch[0]);
3209
+ const line = xml.split("\n")[lineNumber - 1];
3210
+ const secondMatch = re.exec(parsererrorText);
3211
+ if (line && secondMatch) {
3212
+ const columnIndex = Number(secondMatch[0]) - 1;
3213
+ if (line[columnIndex]) {
3214
+ msg +=
3215
+ `\nThe error might be located at xml line ${lineNumber} column ${columnIndex}\n` +
3216
+ `${line}\n${"-".repeat(columnIndex - 1)}^`;
3217
+ }
3218
+ }
3219
+ }
3220
+ }
3221
+ throw new OwlError(msg);
3222
+ }
3223
+ return doc;
3224
+ }
3225
+
3226
+ class Component {
3227
+ static template = "";
3228
+ __owl__;
3229
+ constructor(node) {
3230
+ this.__owl__ = node;
3231
+ }
3232
+ setup() { }
3233
+ }
3234
+
3235
+ const ObjectCreate = Object.create;
3236
+ /**
3237
+ * This file contains utility functions that will be injected in each template,
3238
+ * to perform various useful tasks in the compiled code.
3239
+ */
3240
+ function withDefault(value, defaultValue) {
3241
+ return value === undefined || value === null || value === false ? defaultValue : value;
3242
+ }
3243
+ function callSlot(ctx, parent, key, name, dynamic, extra, defaultContent) {
3244
+ key = key + "__slot_" + name;
3245
+ const slots = ctx.__owl__.props.slots || {};
3246
+ const { __render, __ctx, __scope } = slots[name] || {};
3247
+ const slotScope = ObjectCreate(__ctx || {});
3248
+ if (__scope) {
3249
+ slotScope[__scope] = extra;
3250
+ }
3251
+ const slotBDom = __render ? __render(slotScope, parent, key) : null;
3252
+ if (defaultContent) {
3253
+ let child1 = undefined;
3254
+ let child2 = undefined;
3255
+ if (slotBDom) {
3256
+ child1 = dynamic ? toggler(name, slotBDom) : slotBDom;
3257
+ }
3258
+ else {
3259
+ child2 = defaultContent(ctx, parent, key);
3260
+ }
3261
+ return multi([child1, child2]);
3262
+ }
3263
+ return slotBDom || text("");
3264
+ }
3265
+ function withKey(elem, k) {
3266
+ elem.key = k;
3267
+ return elem;
3268
+ }
3269
+ function prepareList(collection) {
3270
+ let keys;
3271
+ let values;
3272
+ if (Array.isArray(collection)) {
3273
+ keys = collection;
3274
+ values = collection;
3275
+ }
3276
+ else if (collection instanceof Map) {
3277
+ keys = [...collection.keys()];
3278
+ values = [...collection.values()];
3279
+ }
3280
+ else if (Symbol.iterator in Object(collection)) {
3281
+ keys = [...collection];
3282
+ values = keys;
3283
+ }
3284
+ else if (collection && typeof collection === "object") {
3285
+ values = Object.values(collection);
3286
+ keys = Object.keys(collection);
3287
+ }
3288
+ else {
3289
+ throw new OwlError(`Invalid loop expression: "${collection}" is not iterable`);
3290
+ }
3291
+ const n = values.length;
3292
+ return [keys, values, n, new Array(n)];
3293
+ }
3294
+ function toNumber(val) {
3295
+ const n = parseFloat(val);
3296
+ return isNaN(n) ? val : n;
3297
+ }
3298
+ function shallowEqual(l1, l2) {
3299
+ for (let i = 0, l = l1.length; i < l; i++) {
3300
+ if (l1[i] !== l2[i]) {
3301
+ return false;
3302
+ }
3303
+ }
3304
+ return true;
3305
+ }
3306
+ class LazyValue {
3307
+ fn;
3308
+ ctx;
3309
+ component;
3310
+ node;
3311
+ key;
3312
+ constructor(fn, ctx, component, node, key) {
3313
+ this.fn = fn;
3314
+ this.ctx = ctx;
3315
+ this.component = component;
3316
+ this.node = node;
3317
+ this.key = key;
3318
+ }
3319
+ evaluate() {
3320
+ return this.fn.call(this.component, this.ctx, this.node, this.key);
3321
+ }
3322
+ toString() {
3323
+ return this.evaluate().toString();
3324
+ }
3325
+ }
3326
+ /*
3327
+ * Safely outputs `value` as a block depending on the nature of `value`
3328
+ */
3329
+ function safeOutput(value, defaultValue) {
3330
+ if (value === undefined || value === null) {
3331
+ return defaultValue ? toggler("default", defaultValue) : toggler("undefined", text(""));
3332
+ }
3333
+ let safeKey;
3334
+ let block;
3335
+ if (value instanceof Markup) {
3336
+ safeKey = `string_safe`;
3337
+ block = html(value);
3338
+ }
3339
+ else if (value instanceof LazyValue) {
3340
+ safeKey = `lazy_value`;
3341
+ block = value.evaluate();
3342
+ }
3343
+ else {
3344
+ safeKey = "string_unsafe";
3345
+ block = text(value);
3346
+ }
3347
+ return toggler(safeKey, block);
3348
+ }
3349
+ function createRef(ref) {
3350
+ if (!ref) {
3351
+ throw new OwlError(`Ref is undefined or null`);
3352
+ }
3353
+ let add;
3354
+ let remove;
3355
+ if (ref.add && ref.delete) {
3356
+ add = ref.add.bind(ref);
3357
+ remove = ref.delete.bind(ref);
3358
+ }
3359
+ else if (ref.set) {
3360
+ add = ref.set.bind(ref);
3361
+ remove = () => ref.set(null);
3362
+ }
3363
+ else {
3364
+ throw new OwlError(`Ref should implement either a 'set' function or 'add' and 'delete' functions`);
3365
+ }
3366
+ return (el, previousEl) => {
3367
+ if (previousEl) {
3368
+ remove(previousEl);
3369
+ }
3370
+ if (el) {
3371
+ add(el);
3372
+ }
3373
+ };
3374
+ }
3375
+ function callHandler(fn, ctx, ev) {
3376
+ if (typeof fn !== "function") {
3377
+ throw new OwlError(`Invalid handler expression: the \`t-on\` expression should evaluate to a function, but got '${typeof fn}'. ` +
3378
+ `Did you mean to use an arrow function? (e.g. \`t-on-click="() => expr"\`)`);
3379
+ }
3380
+ fn.call(ctx["this"], ev);
3381
+ }
3382
+ function modelExpr(value) {
3383
+ if (typeof value !== "function" || typeof value.set !== "function") {
3384
+ throw new OwlError(`Invalid t-model expression: expression should evaluate to a function with a 'set' method defined on it`);
3385
+ }
3386
+ return value;
3387
+ }
3388
+ function createComponent(app, name, isStatic, hasSlotsProp, hasDynamicPropList, propList) {
3389
+ const isDynamic = !isStatic;
3390
+ let arePropsDifferent;
3391
+ const hasNoProp = propList.length === 0;
3392
+ if (hasSlotsProp) {
3393
+ arePropsDifferent = (_1, _2) => true;
3394
+ }
3395
+ else if (hasDynamicPropList) {
3396
+ arePropsDifferent = function (props1, props2) {
3397
+ for (let k in props1) {
3398
+ if (props1[k] !== props2[k]) {
3399
+ return true;
3400
+ }
3401
+ }
3402
+ return Object.keys(props1).length !== Object.keys(props2).length;
3403
+ };
3404
+ }
3405
+ else if (hasNoProp) {
3406
+ arePropsDifferent = (_1, _2) => false;
3407
+ }
3408
+ else {
3409
+ arePropsDifferent = function (props1, props2) {
3410
+ for (let p of propList) {
3411
+ if (props1[p] !== props2[p]) {
3412
+ return true;
3413
+ }
3414
+ }
3415
+ return false;
3416
+ };
3417
+ }
3418
+ const updateAndRender = ComponentNode.prototype.updateAndRender;
3419
+ const initiateRender = ComponentNode.prototype.initiateRender;
3420
+ return (props, key, ctx, parent, C) => {
3421
+ let children = ctx.children;
3422
+ let node = children[key];
3423
+ if (isDynamic && node && node.component.constructor !== C) {
3424
+ node = undefined;
3425
+ }
3426
+ const parentFiber = ctx.fiber;
3427
+ if (node) {
3428
+ if (arePropsDifferent(node.props, props) || parentFiber.deep || node.forceNextRender) {
3429
+ node.forceNextRender = false;
3430
+ updateAndRender.call(node, props, parentFiber);
3431
+ }
3432
+ }
3433
+ else {
3434
+ // new component
3435
+ if (isStatic) {
3436
+ const components = parent.constructor.components;
3437
+ if (!components) {
3438
+ throw new OwlError(`Cannot find the definition of component "${name}", missing static components key in parent`);
3439
+ }
3440
+ C = components[name];
3441
+ if (!C) {
3442
+ throw new OwlError(`Cannot find the definition of component "${name}"`);
3443
+ }
3444
+ else if (!(C.prototype instanceof Component)) {
3445
+ throw new OwlError(`"${name}" is not a Component. It must inherit from the Component class`);
3446
+ }
3447
+ }
3448
+ node = new ComponentNode(C, props, app, ctx, key);
3449
+ children[key] = node;
3450
+ initiateRender.call(node, new Fiber(node, parentFiber));
3451
+ }
3452
+ parentFiber.childrenMap[key] = node;
3453
+ return node;
3454
+ };
3455
+ }
3456
+ function callTemplate(subTemplate, owner, app, ctx, parent, key) {
3457
+ const template = app.getTemplate(subTemplate);
3458
+ return toggler(subTemplate, template.call(owner, ctx, parent, key + subTemplate));
3459
+ }
3460
+ const helpers = {
3461
+ withDefault,
3462
+ zero: Symbol("zero"),
3463
+ callSlot,
3464
+ withKey,
3465
+ prepareList,
3466
+ shallowEqual,
3467
+ toNumber,
3468
+ LazyValue,
3469
+ safeOutput,
3470
+ createCatcher,
3471
+ markRaw,
3472
+ OwlError,
3473
+ createRef,
3474
+ modelExpr,
3475
+ createComponent,
3476
+ callTemplate,
3477
+ callHandler,
3478
+ };
3479
+
3480
+ const bdom = { text, createBlock, list, multi, html, toggler, comment };
3481
+ class TemplateSet {
3482
+ static registerTemplate(name, fn) {
3483
+ globalTemplates[name] = fn;
3484
+ }
3485
+ dev;
3486
+ rawTemplates = Object.create(globalTemplates);
3487
+ templates = {};
3488
+ getRawTemplate;
3489
+ translateFn;
3490
+ translatableAttributes;
3491
+ customDirectives;
3492
+ runtimeUtils;
3493
+ hasGlobalValues;
3494
+ constructor(config = {}) {
3495
+ this.dev = config.dev || false;
3496
+ this.translateFn = config.translateFn;
3497
+ this.translatableAttributes = config.translatableAttributes;
3498
+ if (config.templates) {
3499
+ if (config.templates instanceof Document || typeof config.templates === "string") {
3500
+ this.addTemplates(config.templates);
3501
+ }
3502
+ else {
3503
+ for (const name in config.templates) {
3504
+ this.addTemplate(name, config.templates[name]);
3505
+ }
3506
+ }
3507
+ }
3508
+ this.getRawTemplate = config.getTemplate;
3509
+ this.customDirectives = config.customDirectives || {};
3510
+ this.runtimeUtils = { ...helpers, __globals__: config.globalValues || {} };
3511
+ this.hasGlobalValues = Boolean(config.globalValues && Object.keys(config.globalValues).length);
3512
+ }
3513
+ addTemplate(name, template) {
3514
+ if (name in this.rawTemplates) {
3515
+ // this check can be expensive, just silently ignore double definitions outside dev mode
3516
+ if (!this.dev) {
3517
+ return;
3518
+ }
3519
+ const rawTemplate = this.rawTemplates[name];
3520
+ const currentAsString = typeof rawTemplate === "string"
3521
+ ? rawTemplate
3522
+ : rawTemplate instanceof Element
3523
+ ? rawTemplate.outerHTML
3524
+ : rawTemplate.toString();
3525
+ const newAsString = typeof template === "string" ? template : template.outerHTML;
3526
+ if (currentAsString === newAsString) {
3527
+ return;
3528
+ }
3529
+ throw new OwlError(`Template ${name} already defined with different content`);
3530
+ }
3531
+ this.rawTemplates[name] = template;
3532
+ }
3533
+ addTemplates(xml) {
3534
+ if (!xml) {
3535
+ // empty string
3536
+ return;
3537
+ }
3538
+ xml = xml instanceof Document ? xml : parseXML(xml);
3539
+ for (const template of xml.querySelectorAll("[t-name]")) {
3540
+ const name = template.getAttribute("t-name");
3541
+ this.addTemplate(name, template);
3542
+ }
3543
+ }
3544
+ getTemplate(name) {
3545
+ const cacheKey = name;
3546
+ if (!(cacheKey in this.templates)) {
3547
+ const rawTemplate = this.getRawTemplate?.(name) || this.rawTemplates[name];
3548
+ if (rawTemplate === undefined) {
3549
+ let extraInfo = "";
3550
+ try {
3551
+ const { componentName } = getContext("component");
3552
+ extraInfo = ` (for component "${componentName}")`;
3553
+ }
3554
+ catch { }
3555
+ throw new OwlError(`Missing template: "${name}"${extraInfo}`);
3556
+ }
3557
+ const isFn = typeof rawTemplate === "function" && !(rawTemplate instanceof Element);
3558
+ const templateFn = isFn ? rawTemplate : this._compileTemplate(name, rawTemplate);
3559
+ // first add a function to lazily get the template, in case there is a
3560
+ // recursive call to the template name
3561
+ const templates = this.templates;
3562
+ this.templates[cacheKey] = function (context, parent) {
3563
+ return templates[cacheKey].call(this, context, parent);
3564
+ };
3565
+ const template = templateFn(this, bdom, this.runtimeUtils);
3566
+ this.templates[cacheKey] = template;
3567
+ }
3568
+ return this.templates[cacheKey];
3569
+ }
3570
+ _compileTemplate(name, template) {
3571
+ throw new OwlError(`Unable to compile a template. Please use owl full build instead`);
3572
+ }
3573
+ }
3574
+ // -----------------------------------------------------------------------------
3575
+ // xml tag helper
3576
+ // -----------------------------------------------------------------------------
3577
+ const globalTemplates = {};
3578
+ function xml(...args) {
3579
+ const name = `__template__${xml.nextId++}`;
3580
+ const value = String.raw(...args);
3581
+ globalTemplates[name] = value;
3582
+ return name;
3583
+ }
3584
+ xml.nextId = 1;
3585
+
3586
+ let hasBeenLogged = false;
3587
+ const apps = new Set();
3588
+ if (typeof window !== "undefined") {
3589
+ window.__OWL_DEVTOOLS__ ||= { apps, Fiber, RootFiber, toRaw, proxy };
3590
+ }
3591
+ class App extends TemplateSet {
3592
+ static validateTarget = validateTarget;
3593
+ static apps = apps;
3594
+ static version = version;
3595
+ name;
3596
+ scheduler = new Scheduler();
3597
+ roots = new Set();
3598
+ pluginManager;
3599
+ constructor(config = {}) {
3600
+ super(config);
3601
+ this.name = config.name || "";
3602
+ apps.add(this);
3603
+ this.pluginManager = new PluginManager(this, { config: config.config });
3604
+ if (config.plugins) {
3605
+ startPlugins(this.pluginManager, config.plugins);
3606
+ }
3607
+ if (config.test) {
3608
+ this.dev = true;
3609
+ }
3610
+ if (this.dev && !config.test && !hasBeenLogged) {
3611
+ console.info(`Owl is running in 'dev' mode.`);
3612
+ hasBeenLogged = true;
3613
+ }
3614
+ }
3615
+ createRoot(Root, config = {}) {
3616
+ const props = config.props || {};
3617
+ let resolve;
3618
+ let reject;
3619
+ const promise = new Promise((res, rej) => {
3620
+ resolve = res;
3621
+ reject = rej;
3622
+ });
3623
+ const restore = saveContext();
3624
+ let node;
3625
+ let error = null;
3626
+ try {
3627
+ node = new ComponentNode(Root, props, this, null, null);
3628
+ }
3629
+ catch (e) {
3630
+ error = e;
3631
+ reject(e);
3632
+ }
3633
+ finally {
3634
+ restore();
3635
+ }
3636
+ const root = {
3637
+ node: node,
3638
+ promise,
3639
+ mount: (target, options) => {
3640
+ if (error) {
3641
+ return promise;
3642
+ }
3643
+ App.validateTarget(target);
3644
+ this.mountNode(node, target, resolve, reject, options);
3645
+ return promise;
3646
+ },
3647
+ destroy: () => {
3648
+ this.roots.delete(root);
3649
+ node.destroy();
3650
+ this.scheduler.processTasks();
3651
+ },
3652
+ };
3653
+ this.roots.add(root);
3654
+ return root;
3655
+ }
3656
+ mountNode(node, target, resolve, reject, options) {
3657
+ // Manually add the last resort error handler on the node
3658
+ let handlers = nodeErrorHandlers.get(node);
3659
+ if (!handlers) {
3660
+ handlers = [];
3661
+ nodeErrorHandlers.set(node, handlers);
3662
+ }
3663
+ handlers.unshift((e, finalize) => {
3664
+ const finalError = finalize();
3665
+ reject(finalError);
3666
+ });
3667
+ // manually set a onMounted callback.
3668
+ // that way, we are independant from the current node.
3669
+ node.mounted.push(() => {
3670
+ resolve(node.component);
3671
+ handlers.shift();
3672
+ });
3673
+ node.mountComponent(target, options);
3674
+ }
3675
+ destroy() {
3676
+ for (let root of this.roots) {
3677
+ root.destroy();
3678
+ }
3679
+ this.pluginManager.destroy();
3680
+ this.scheduler.processTasks();
3681
+ apps.delete(this);
3682
+ }
3683
+ handleError(...args) {
3684
+ return handleError(...args);
3685
+ }
3686
+ }
3687
+ async function mount(C, target, config = {}) {
3688
+ const app = new App(config);
3689
+ const root = app.createRoot(C, config);
3690
+ return root.mount(target, config);
3691
+ }
3692
+
3693
+ const mainEventHandler = (data, ev, currentTarget) => {
3694
+ const { data: _data, modifiers } = filterOutModifiersFromData(data);
3695
+ data = _data;
3696
+ let stopped = false;
3697
+ if (modifiers.length) {
3698
+ let selfMode = false;
3699
+ const isSelf = ev.target === currentTarget;
3700
+ for (const mod of modifiers) {
3701
+ switch (mod) {
3702
+ case "self":
3703
+ selfMode = true;
3704
+ if (isSelf) {
3705
+ continue;
3706
+ }
3707
+ else {
3708
+ return stopped;
3709
+ }
3710
+ case "prevent":
3711
+ if ((selfMode && isSelf) || !selfMode)
3712
+ ev.preventDefault();
3713
+ continue;
3714
+ case "stop":
3715
+ if ((selfMode && isSelf) || !selfMode)
3716
+ ev.stopPropagation();
3717
+ stopped = true;
3718
+ continue;
3719
+ }
3720
+ }
3721
+ }
3722
+ // If handler is empty, the array slot 0 will also be empty, and data will not have the property 0
3723
+ // We check this rather than data[0] being truthy (or typeof function) so that it crashes
3724
+ // as expected when there is a handler expression that evaluates to a falsy value
3725
+ if (Object.hasOwnProperty.call(data, 0)) {
3726
+ const handler = data[0];
3727
+ if (typeof handler !== "function") {
3728
+ throw new OwlError(`Invalid handler (expected a function, received: '${handler}')`);
3729
+ }
3730
+ let node = data[1] ? data[1].__owl__ : null;
3731
+ if (node ? node.status === 1 /* STATUS.MOUNTED */ : true) {
3732
+ handler(data[1], ev);
3733
+ }
3734
+ }
3735
+ return stopped;
3736
+ };
3737
+
3738
+ // -----------------------------------------------------------------------------
3739
+ // hooks
3740
+ // -----------------------------------------------------------------------------
3741
+ function decorate(node, f, hookName) {
3742
+ const result = f.bind(node.component);
3743
+ if (node.app.dev) {
3744
+ const suffix = f.name ? ` <${f.name}>` : "";
3745
+ Reflect.defineProperty(result, "name", {
3746
+ value: hookName + suffix,
3747
+ });
3748
+ }
3749
+ return result;
3750
+ }
3751
+ function onWillStart(fn) {
3752
+ const { node } = getContext("component");
3753
+ node.willStart.push(decorate(node, fn, "onWillStart"));
3754
+ }
3755
+ function onWillUpdateProps(fn) {
3756
+ const { node } = getContext("component");
3757
+ node.willUpdateProps.push(decorate(node, fn, "onWillUpdateProps"));
3758
+ }
3759
+ function onMounted(fn) {
3760
+ const { node } = getContext("component");
3761
+ node.mounted.push(decorate(node, fn, "onMounted"));
3762
+ }
3763
+ function onWillPatch(fn) {
3764
+ const { node } = getContext("component");
3765
+ node.willPatch.unshift(decorate(node, fn, "onWillPatch"));
3766
+ }
3767
+ function onPatched(fn) {
3768
+ const { node } = getContext("component");
3769
+ node.patched.push(decorate(node, fn, "onPatched"));
3770
+ }
3771
+ function onWillUnmount(fn) {
3772
+ const { node } = getContext("component");
3773
+ node.willUnmount.unshift(decorate(node, fn, "onWillUnmount"));
3774
+ }
3775
+ function onWillDestroy(fn) {
3776
+ const context = getContext();
3777
+ if (context.type === "component") {
3778
+ context.node.willDestroy.unshift(decorate(context.node, fn, "onWillDestroy"));
3779
+ }
3780
+ else {
3781
+ context.manager.onDestroyCb.push(fn);
3782
+ }
3783
+ }
3784
+ function onError(callback) {
3785
+ const { node } = getContext("component");
3786
+ let handlers = nodeErrorHandlers.get(node);
3787
+ if (!handlers) {
3788
+ handlers = [];
3789
+ nodeErrorHandlers.set(node, handlers);
3790
+ }
3791
+ handlers.push(callback.bind(node.component));
3792
+ }
3793
+
3794
+ function computed(getter, options = {}) {
3795
+ const computation = createComputation(() => {
3796
+ const newValue = getter();
3797
+ if (!Object.is(computation.value, newValue)) {
3798
+ onWriteAtom(computation);
3799
+ }
3800
+ return newValue;
3801
+ }, true);
3802
+ function readComputed() {
3803
+ if (computation.state !== ComputationState.EXECUTED) {
3804
+ updateComputation(computation);
3805
+ }
3806
+ onReadAtom(computation);
3807
+ return computation.value;
3808
+ }
3809
+ readComputed[atomSymbol] = computation;
3810
+ readComputed.set = options.set ?? (() => { });
3811
+ const context = contextStack.at(-1);
3812
+ if (context) {
3813
+ if (context.type === "component") {
3814
+ context.node.computations.push(computation);
3815
+ }
3816
+ else if (context.type === "plugin") {
3817
+ context.manager.computations.push(computation);
3818
+ }
3819
+ }
3820
+ return readComputed;
3821
+ }
3822
+
3823
+ function buildSignal(value, set) {
3824
+ const atom = {
3825
+ type: "signal",
3826
+ value,
3827
+ observers: new Set(),
3828
+ };
3829
+ let readValue = set(atom);
3830
+ const readSignal = () => {
3831
+ onReadAtom(atom);
3832
+ return readValue;
3833
+ };
3834
+ readSignal[atomSymbol] = atom;
3835
+ readSignal.set = function writeSignal(newValue) {
3836
+ if (Object.is(atom.value, newValue)) {
3837
+ return;
3838
+ }
3839
+ atom.value = newValue;
3840
+ readValue = set(atom);
3841
+ onWriteAtom(atom);
3842
+ };
3843
+ return readSignal;
3844
+ }
3845
+ function invalidateSignal(signal) {
3846
+ if (typeof signal !== "function" || signal[atomSymbol]?.type !== "signal") {
3847
+ throw new OwlError(`Value is not a signal (${signal})`);
3848
+ }
3849
+ onWriteAtom(signal[atomSymbol]);
3850
+ }
3851
+ function signalArray(initialValue) {
3852
+ return buildSignal(initialValue, (atom) => proxifyTarget(atom.value, atom));
3853
+ }
3854
+ function signalObject(initialValue) {
3855
+ return buildSignal(initialValue, (atom) => proxifyTarget(atom.value, atom));
3856
+ }
3857
+ function signalMap(initialValue) {
3858
+ return buildSignal(initialValue, (atom) => proxifyTarget(atom.value, atom));
3859
+ }
3860
+ function signalSet(initialValue) {
3861
+ return buildSignal(initialValue, (atom) => proxifyTarget(atom.value, atom));
3862
+ }
3863
+ function signal(value) {
3864
+ return buildSignal(value, (atom) => atom.value);
3865
+ }
3866
+ signal.invalidate = invalidateSignal;
3867
+ signal.Array = signalArray;
3868
+ signal.Map = signalMap;
3869
+ signal.Object = signalObject;
3870
+ signal.Set = signalSet;
3871
+
3872
+ function assertType(value, validation, errorMessage = "Value does not match the type") {
3873
+ const issues = validateType(value, validation);
3874
+ if (issues.length) {
3875
+ const issueStrings = JSON.stringify(issues, (key, value) => {
3876
+ if (typeof value === "function") {
3877
+ return value.name;
3878
+ }
3879
+ return value;
3880
+ }, 2);
3881
+ throw new OwlError(`${errorMessage}\n${issueStrings}`);
3882
+ }
3883
+ }
3884
+ function createContext(issues, value, path, parent) {
3885
+ return {
3886
+ issueDepth: 0,
3887
+ path,
3888
+ value,
3889
+ get isValid() {
3890
+ return !issues.length;
3891
+ },
3892
+ addIssue(issue) {
3893
+ issues.push({
3894
+ received: this.value,
3895
+ path: this.path,
3896
+ ...issue,
3897
+ });
3898
+ },
3899
+ mergeIssues(newIssues) {
3900
+ issues.push(...newIssues);
3901
+ },
3902
+ validate(type) {
3903
+ type(this);
3904
+ if (!this.isValid && parent) {
3905
+ parent.issueDepth = this.issueDepth + 1;
3906
+ }
3907
+ },
3908
+ withIssues(issues) {
3909
+ return createContext(issues, this.value, this.path, this);
3910
+ },
3911
+ withKey(key) {
3912
+ return createContext(issues, this.value[key], this.path.concat(key), this);
3913
+ },
3914
+ };
3915
+ }
3916
+ function validateType(value, validation) {
3917
+ const issues = [];
3918
+ validation(createContext(issues, value, []));
3919
+ return issues;
3920
+ }
3921
+
3922
+ class Resource {
3923
+ _items = signal.Array([]);
3924
+ _name;
3925
+ _validation;
3926
+ constructor(options = {}) {
3927
+ this._name = options.name;
3928
+ this._validation = options.validation;
3929
+ }
3930
+ items = computed(() => {
3931
+ return this._items()
3932
+ .sort((el1, el2) => el1[0] - el2[0])
3933
+ .map((elem) => elem[1]);
3934
+ });
3935
+ add(item, options = {}) {
3936
+ if (this._validation) {
3937
+ const info = this._name ? ` (resource '${this._name}')` : "";
3938
+ assertType(item, this._validation, `Resource item does not match the type${info}`);
3939
+ }
3940
+ this._items().push([options.sequence ?? 50, item]);
3941
+ return this;
3942
+ }
3943
+ delete(item) {
3944
+ const items = this._items().filter(([seq, val]) => val !== item);
3945
+ this._items.set(items);
3946
+ return this;
3947
+ }
3948
+ has(item) {
3949
+ return this._items().some(([s, value]) => value === item);
3950
+ }
3951
+ }
3952
+ function useResource(r, elements) {
3953
+ for (let elem of elements) {
3954
+ r.add(elem);
3955
+ }
3956
+ onWillDestroy(() => {
3957
+ for (let elem of elements) {
3958
+ r.delete(elem);
3959
+ }
3960
+ });
3961
+ }
3962
+
3963
+ class Registry {
3964
+ _map = signal.Object(Object.create(null));
3965
+ _name;
3966
+ _validation;
3967
+ constructor(options = {}) {
3968
+ this._name = options.name || "registry";
3969
+ this._validation = options.validation;
3970
+ }
3971
+ entries = computed(() => {
3972
+ const entries = Object.entries(this._map())
3973
+ .sort((el1, el2) => el1[1][0] - el2[1][0])
3974
+ .map(([str, elem]) => [str, elem[1]]);
3975
+ return entries;
3976
+ });
3977
+ items = computed(() => this.entries().map((e) => e[1]));
3978
+ addById(item, options = {}) {
3979
+ if (!item.id) {
3980
+ throw new OwlError(`Item should have an id key (registry '${this._name}')`);
3981
+ }
3982
+ return this.add(item.id, item, { sequence: options.sequence ?? 50 });
3983
+ }
3984
+ add(key, value, options = {}) {
3985
+ if (this._validation) {
3986
+ const info = this._name ? ` (registry '${this._name}', key: '${key}')` : ` (key: '${key}')`;
3987
+ assertType(value, this._validation, `Registry entry does not match the type${info}`);
3988
+ }
3989
+ this._map()[key] = [options.sequence ?? 50, value];
3990
+ return this;
3991
+ }
3992
+ get(key, defaultValue) {
3993
+ const hasKey = key in this._map();
3994
+ if (!hasKey && arguments.length < 2) {
3995
+ throw new Error(`KeyNotFoundError: Cannot find key "${key}" (registry '${this._name}')`);
3996
+ }
3997
+ return hasKey ? this._map()[key][1] : defaultValue;
3998
+ }
3999
+ delete(key) {
4000
+ delete this._map()[key];
4001
+ }
4002
+ has(key) {
4003
+ return key in this._map();
4004
+ }
4005
+ }
4006
+
4007
+ const anyType = function validateAny() { };
4008
+ const booleanType = function validateBoolean(context) {
4009
+ if (typeof context.value !== "boolean") {
4010
+ context.addIssue({ message: "value is not a boolean" });
4011
+ }
4012
+ };
4013
+ const numberType = function validateNumber(context) {
4014
+ if (typeof context.value !== "number") {
4015
+ context.addIssue({ message: "value is not a number" });
4016
+ }
4017
+ };
4018
+ const stringType = function validateString(context) {
4019
+ if (typeof context.value !== "string") {
4020
+ context.addIssue({ message: "value is not a string" });
4021
+ }
4022
+ };
4023
+ function arrayType(elementType) {
4024
+ return function validateArray(context) {
4025
+ if (!Array.isArray(context.value)) {
4026
+ context.addIssue({ message: "value is not an array" });
4027
+ return;
4028
+ }
4029
+ if (!elementType) {
4030
+ return;
4031
+ }
4032
+ for (let index = 0; index < context.value.length; index++) {
4033
+ context.withKey(index).validate(elementType);
4034
+ }
4035
+ };
4036
+ }
4037
+ function constructorType(constructor) {
4038
+ return function validateConstructor(context) {
4039
+ if (!(typeof context.value === "function") ||
4040
+ !(context.value === constructor || context.value.prototype instanceof constructor)) {
4041
+ context.addIssue({ message: `value is not '${constructor.name}' or an extension` });
4042
+ }
4043
+ };
4044
+ }
4045
+ function customValidator(type, validator, errorMessage = "value does not match custom validation") {
4046
+ return function validateCustom(context) {
4047
+ context.validate(type);
4048
+ if (!context.isValid) {
4049
+ return;
4050
+ }
4051
+ if (!validator(context.value)) {
4052
+ context.addIssue({ message: errorMessage });
4053
+ }
4054
+ };
4055
+ }
4056
+ function functionType(parameters = [], result = undefined) {
4057
+ return function validateFunction(context) {
4058
+ if (typeof context.value !== "function") {
4059
+ context.addIssue({ message: "value is not a function" });
4060
+ }
4061
+ };
4062
+ }
4063
+ function instanceType(constructor) {
4064
+ return function validateInstanceType(context) {
4065
+ if (!(context.value instanceof constructor)) {
4066
+ context.addIssue({ message: `value is not an instance of '${constructor.name}'` });
4067
+ }
4068
+ };
4069
+ }
4070
+ function intersection(types) {
4071
+ return function validateIntersection(context) {
4072
+ for (const type of types) {
4073
+ context.validate(type);
4074
+ }
4075
+ };
4076
+ }
4077
+ function literalType(literal) {
4078
+ return function validateLiteral(context) {
4079
+ if (context.value !== literal) {
4080
+ context.addIssue({
4081
+ message: `value is not equal to ${typeof literal === "string" ? `'${literal}'` : literal}`,
4082
+ });
4083
+ }
4084
+ };
4085
+ }
4086
+ function literalSelection(literals) {
4087
+ return union(literals.map(literalType));
4088
+ }
4089
+ function validateObject(context, schema, isStrict) {
4090
+ if (typeof context.value !== "object" || Array.isArray(context.value) || context.value === null) {
4091
+ context.addIssue({ message: "value is not an object" });
4092
+ return;
4093
+ }
4094
+ if (!schema) {
4095
+ return;
4096
+ }
4097
+ const isShape = !Array.isArray(schema);
4098
+ let shape = schema;
4099
+ if (Array.isArray(schema)) {
4100
+ shape = {};
4101
+ for (const key of schema) {
4102
+ shape[key] = null;
4103
+ }
4104
+ }
4105
+ const missingKeys = [];
4106
+ for (const key in shape) {
4107
+ const property = key.endsWith("?") ? key.slice(0, -1) : key;
4108
+ if (context.value[property] === undefined) {
4109
+ if (!key.endsWith("?")) {
4110
+ missingKeys.push(property);
4111
+ }
4112
+ continue;
4113
+ }
4114
+ if (isShape) {
4115
+ context.withKey(property).validate(shape[key]);
4116
+ }
4117
+ }
4118
+ if (missingKeys.length) {
4119
+ context.addIssue({
4120
+ message: "object value has missing keys",
4121
+ missingKeys,
4122
+ });
4123
+ }
4124
+ if (isStrict) {
4125
+ const unknownKeys = [];
4126
+ for (const key in context.value) {
4127
+ if (!(key in shape) && !(`${key}?` in shape)) {
4128
+ unknownKeys.push(key);
4129
+ }
4130
+ }
4131
+ if (unknownKeys.length) {
4132
+ context.addIssue({
4133
+ message: "object value has unknown keys",
4134
+ unknownKeys,
4135
+ });
4136
+ }
4137
+ }
4138
+ }
4139
+ function objectType(schema = {}) {
4140
+ return function validateLooseObject(context) {
4141
+ validateObject(context, schema, false);
4142
+ };
4143
+ }
4144
+ function strictObjectType(schema) {
4145
+ return function validateStrictObject(context) {
4146
+ validateObject(context, schema, true);
4147
+ };
4148
+ }
4149
+ function promiseType(type) {
4150
+ return function validatePromise(context) {
4151
+ if (!(context.value instanceof Promise)) {
4152
+ context.addIssue({ message: "value is not a promise" });
4153
+ }
4154
+ };
4155
+ }
4156
+ function recordType(valueType) {
4157
+ return function validateRecord(context) {
4158
+ if (typeof context.value !== "object" ||
4159
+ Array.isArray(context.value) ||
4160
+ context.value === null) {
4161
+ context.addIssue({ message: "value is not an object" });
4162
+ return;
4163
+ }
4164
+ if (!valueType) {
4165
+ return;
4166
+ }
4167
+ for (const key in context.value) {
4168
+ context.withKey(key).validate(valueType);
4169
+ }
4170
+ };
4171
+ }
4172
+ function tuple(types) {
4173
+ return function validateTuple(context) {
4174
+ if (!Array.isArray(context.value)) {
4175
+ context.addIssue({ message: "value is not an array" });
4176
+ return;
4177
+ }
4178
+ if (context.value.length !== types.length) {
4179
+ context.addIssue({ message: "tuple value does not have the correct length" });
4180
+ return;
4181
+ }
4182
+ for (let index = 0; index < types.length; index++) {
4183
+ context.withKey(index).validate(types[index]);
4184
+ }
4185
+ };
4186
+ }
4187
+ function union(types) {
4188
+ return function validateUnion(context) {
4189
+ let firstIssueIndex = 0;
4190
+ const subIssues = [];
4191
+ for (const type of types) {
4192
+ const subContext = context.withIssues(subIssues);
4193
+ subContext.validate(type);
4194
+ if (subIssues.length === firstIssueIndex || subContext.issueDepth > 0) {
4195
+ context.mergeIssues(subIssues.slice(firstIssueIndex));
4196
+ return;
4197
+ }
4198
+ firstIssueIndex = subIssues.length;
4199
+ }
4200
+ context.addIssue({
4201
+ message: "value does not match union type",
4202
+ subIssues,
4203
+ });
4204
+ };
4205
+ }
4206
+ function reactiveValueType(type) {
4207
+ return function validateReactiveValue(context) {
4208
+ if (typeof context.value !== "function" || !context.value[atomSymbol]) {
4209
+ context.addIssue({ message: "value is not a reactive value" });
4210
+ }
4211
+ };
4212
+ }
4213
+ function ref(type) {
4214
+ return union([literalType(null), instanceType(type)]);
4215
+ }
4216
+ const types = {
4217
+ and: intersection,
4218
+ any: anyType,
4219
+ array: arrayType,
4220
+ boolean: booleanType,
4221
+ constructor: constructorType,
4222
+ customValidator: customValidator,
4223
+ function: functionType,
4224
+ instanceOf: instanceType,
4225
+ literal: literalType,
4226
+ number: numberType,
4227
+ object: objectType,
4228
+ or: union,
4229
+ promise: promiseType,
4230
+ record: recordType,
4231
+ ref,
4232
+ selection: literalSelection,
4233
+ signal: reactiveValueType,
4234
+ strictObject: strictObjectType,
4235
+ string: stringType,
4236
+ tuple: tuple,
4237
+ };
4238
+
4239
+ function validateObjectWithDefaults(schema, defaultValues) {
4240
+ const keys = Array.isArray(schema) ? schema : Object.keys(schema);
4241
+ const mandatoryDefaultedKeys = keys.filter((key) => !key.endsWith("?") && key in defaultValues);
4242
+ return (context) => {
4243
+ if (mandatoryDefaultedKeys.length) {
4244
+ context.addIssue({
4245
+ message: "props have default values on mandatory keys",
4246
+ keys: mandatoryDefaultedKeys,
4247
+ });
4248
+ }
4249
+ context.validate(types.object(schema));
4250
+ };
4251
+ }
4252
+ function props(type, defaults) {
4253
+ const { node, app, componentName } = getContext("component");
4254
+ Object.assign(node.defaultProps, defaults);
4255
+ function getProp(key) {
4256
+ if (node.props[key] === undefined && defaults) {
4257
+ return defaults[key];
4258
+ }
4259
+ return node.props[key];
4260
+ }
4261
+ const result = Object.create(null);
4262
+ function applyPropGetters(keys) {
4263
+ for (const key of keys) {
4264
+ Reflect.defineProperty(result, key, {
4265
+ enumerable: true,
4266
+ get: getProp.bind(null, key),
4267
+ });
4268
+ }
4269
+ }
4270
+ if (type) {
4271
+ const keys = (Array.isArray(type) ? type : Object.keys(type)).map((key) => key.endsWith("?") ? key.slice(0, -1) : key);
4272
+ applyPropGetters(keys);
4273
+ if (app.dev) {
4274
+ const validation = defaults ? validateObjectWithDefaults(type, defaults) : types.object(type);
4275
+ assertType(node.props, validation, `Invalid component props (${componentName})`);
4276
+ node.willUpdateProps.push((np) => {
4277
+ assertType(np, validation, `Invalid component props (${componentName})`);
4278
+ });
4279
+ }
4280
+ }
4281
+ else {
4282
+ const getKeys = (props) => {
4283
+ const keys = [];
4284
+ for (const k in props) {
4285
+ if (k.charCodeAt(0) !== 1) {
4286
+ keys.push(k);
4287
+ }
4288
+ }
4289
+ if (defaults) {
4290
+ for (const k in defaults) {
4291
+ if (!(k in props)) {
4292
+ keys.push(k);
4293
+ }
4294
+ }
4295
+ }
4296
+ return keys;
4297
+ };
4298
+ let keys = getKeys(node.props);
4299
+ applyPropGetters(keys);
4300
+ node.willUpdateProps.push((np) => {
4301
+ for (const key of keys) {
4302
+ Reflect.deleteProperty(result, key);
4303
+ }
4304
+ keys = getKeys(np);
4305
+ applyPropGetters(keys);
4306
+ });
4307
+ }
4308
+ return result;
4309
+ }
4310
+
4311
+ function status(entity) {
4312
+ switch (entity.__owl__.status) {
4313
+ case 0 /* STATUS.NEW */:
4314
+ return "new";
4315
+ case 2 /* STATUS.CANCELLED */:
4316
+ return "cancelled";
4317
+ case 1 /* STATUS.MOUNTED */:
4318
+ return entity instanceof Plugin ? "started" : "mounted";
4319
+ case 3 /* STATUS.DESTROYED */:
4320
+ return "destroyed";
4321
+ }
4322
+ }
4323
+
4324
+ // -----------------------------------------------------------------------------
4325
+ // useEffect
4326
+ // -----------------------------------------------------------------------------
4327
+ /**
4328
+ * This hook will run a callback when a component is mounted and patched, and
4329
+ * will run a cleanup function before patching and before unmounting the
4330
+ * the component.
4331
+ *
4332
+ * @template T
4333
+ * @param {Effect<T>} effect the effect to run on component mount and/or patch
4334
+ * @param {()=>[...T]} [computeDependencies=()=>[NaN]] a callback to compute
4335
+ * dependencies that will decide if the effect needs to be cleaned up and
4336
+ * run again. If the dependencies did not change, the effect will not run
4337
+ * again. The default value returns an array containing only NaN because
4338
+ * NaN !== NaN, which will cause the effect to rerun on every patch.
4339
+ */
4340
+ function useEffect(fn) {
4341
+ onWillDestroy(effect(fn));
4342
+ }
4343
+ // -----------------------------------------------------------------------------
4344
+ // useListener
4345
+ // -----------------------------------------------------------------------------
4346
+ /**
4347
+ * When a component needs to listen to DOM Events on element(s) that are not
4348
+ * part of his hierarchy, we can use the `useListener` hook.
4349
+ * It will immediately add the listener, and remove it whenever the plugin or
4350
+ * component is destroyed.
4351
+ *
4352
+ * Example:
4353
+ * a menu needs to listen to the click on window to be closed automatically
4354
+ *
4355
+ * Usage:
4356
+ * in the constructor of the OWL component that needs to be notified,
4357
+ * `useListener(window, 'click', () => this._doSomething());`
4358
+ * */
4359
+ function useListener(target, eventName, handler, eventParams) {
4360
+ if (typeof target === "function") {
4361
+ // this is a ref
4362
+ useEffect(() => {
4363
+ const el = target();
4364
+ if (el) {
4365
+ el.addEventListener(eventName, handler, eventParams);
4366
+ return () => el.removeEventListener(eventName, handler, eventParams);
4367
+ }
4368
+ return;
4369
+ });
4370
+ }
4371
+ else {
4372
+ target.addEventListener(eventName, handler, eventParams);
4373
+ onWillDestroy(() => target.removeEventListener(eventName, handler, eventParams));
4374
+ }
4375
+ }
4376
+ // -----------------------------------------------------------------------------
4377
+ // useApp
4378
+ // -----------------------------------------------------------------------------
4379
+ function useApp() {
4380
+ return getContext().app;
4381
+ }
4382
+
4383
+ function plugin(pluginType) {
4384
+ const context = getContext();
4385
+ const manager = context.type === "component" ? context.node.pluginManager : context.manager;
4386
+ let plugin = manager.getPluginById(pluginType.id);
4387
+ if (!plugin) {
4388
+ if (context.type === "plugin") {
4389
+ plugin = manager.startPlugin(pluginType);
4390
+ }
4391
+ else {
4392
+ throw new OwlError(`Unknown plugin "${pluginType.id}"`);
4393
+ }
4394
+ }
4395
+ return plugin;
4396
+ }
4397
+ function config(name, type) {
4398
+ const { app, manager } = getContext("plugin");
4399
+ if (app.dev && type) {
4400
+ assertType(manager.config, types.object({ [name]: type }), "Config does not match the type");
4401
+ }
4402
+ return manager.config[name.endsWith("?") ? name.slice(0, -1) : name];
4403
+ }
4404
+ function providePlugins(pluginConstructors, config) {
4405
+ const { node } = getContext("component");
4406
+ const manager = new PluginManager(node.app, { parent: node.pluginManager, config });
4407
+ node.pluginManager = manager;
4408
+ onWillDestroy(() => manager.destroy());
4409
+ startPlugins(manager, pluginConstructors);
4410
+ }
4411
+
4412
+ config$1.shouldNormalizeDom = false;
4413
+ config$1.mainEventHandler = mainEventHandler;
4414
+ const blockDom = {
4415
+ config: config$1,
4416
+ // bdom entry points
4417
+ mount: mount$1,
4418
+ patch,
4419
+ remove,
4420
+ // bdom block types
4421
+ list,
4422
+ multi,
4423
+ text,
4424
+ toggler,
4425
+ createBlock,
4426
+ html,
4427
+ comment,
4428
+ };
4429
+ const __info__ = {
4430
+ version: App.version,
4431
+ };
4432
+
4433
+ exports.App = App;
4434
+ exports.Component = Component;
4435
+ exports.EventBus = EventBus;
4436
+ exports.OwlError = OwlError;
4437
+ exports.Plugin = Plugin;
4438
+ exports.Registry = Registry;
4439
+ exports.Resource = Resource;
4440
+ exports.__info__ = __info__;
4441
+ exports.assertType = assertType;
4442
+ exports.batched = batched;
4443
+ exports.blockDom = blockDom;
4444
+ exports.computed = computed;
4445
+ exports.config = config;
4446
+ exports.effect = effect;
4447
+ exports.htmlEscape = htmlEscape;
4448
+ exports.markRaw = markRaw;
4449
+ exports.markup = markup;
4450
+ exports.mount = mount;
4451
+ exports.onError = onError;
4452
+ exports.onMounted = onMounted;
4453
+ exports.onPatched = onPatched;
4454
+ exports.onWillDestroy = onWillDestroy;
4455
+ exports.onWillPatch = onWillPatch;
4456
+ exports.onWillStart = onWillStart;
4457
+ exports.onWillUnmount = onWillUnmount;
4458
+ exports.onWillUpdateProps = onWillUpdateProps;
4459
+ exports.plugin = plugin;
4460
+ exports.props = props;
4461
+ exports.providePlugins = providePlugins;
4462
+ exports.proxy = proxy;
4463
+ exports.signal = signal;
4464
+ exports.status = status;
4465
+ exports.toRaw = toRaw;
4466
+ exports.types = types;
4467
+ exports.untrack = untrack;
4468
+ exports.useApp = useApp;
4469
+ exports.useContext = useContext;
4470
+ exports.useEffect = useEffect;
4471
+ exports.useListener = useListener;
4472
+ exports.useResource = useResource;
4473
+ exports.validateType = validateType;
4474
+ exports.whenReady = whenReady;
4475
+ exports.xml = xml;
4476
+
4477
+
4478
+ __info__.date = '2026-04-02T10:48:47.408Z';
4479
+ __info__.hash = 'd172095';
4480
+ __info__.url = 'https://github.com/odoo/owl';