@odoo/owl 2.1.3 → 2.2.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/owl-devtools.zip +0 -0
- package/dist/owl.cjs.js +145 -81
- package/dist/owl.es.js +145 -81
- package/dist/owl.iife.js +145 -81
- package/dist/owl.iife.min.js +1 -1
- package/dist/types/compiler/code_generator.d.ts +1 -0
- package/dist/types/owl.d.ts +18 -7
- package/dist/types/runtime/app.d.ts +3 -0
- package/dist/types/runtime/component_node.d.ts +2 -0
- package/dist/types/runtime/hooks.d.ts +8 -5
- package/dist/types/runtime/scheduler.d.ts +4 -0
- package/dist/types/runtime/status.d.ts +3 -2
- package/dist/types/runtime/template_helpers.d.ts +1 -1
- package/dist/types/version.d.ts +1 -1
- package/package.json +1 -1
package/dist/owl-devtools.zip
CHANGED
|
Binary file
|
package/dist/owl.cjs.js
CHANGED
|
@@ -126,14 +126,16 @@ function handleError(params) {
|
|
|
126
126
|
}
|
|
127
127
|
const node = "node" in params ? params.node : params.fiber.node;
|
|
128
128
|
const fiber = "fiber" in params ? params.fiber : node.fiber;
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
129
|
+
if (fiber) {
|
|
130
|
+
// resets the fibers on components if possible. This is important so that
|
|
131
|
+
// new renderings can be properly included in the initial one, if any.
|
|
132
|
+
let current = fiber;
|
|
133
|
+
do {
|
|
134
|
+
current.node.fiber = current;
|
|
135
|
+
current = current.parent;
|
|
136
|
+
} while (current);
|
|
137
|
+
fibersInError.set(fiber.root, error);
|
|
138
|
+
}
|
|
137
139
|
const handled = _handleError(node, error);
|
|
138
140
|
if (!handled) {
|
|
139
141
|
console.warn(`[Owl] Unhandled error. Destroying the root component`);
|
|
@@ -179,11 +181,21 @@ function createAttrUpdater(attr) {
|
|
|
179
181
|
}
|
|
180
182
|
function attrsSetter(attrs) {
|
|
181
183
|
if (isArray(attrs)) {
|
|
182
|
-
|
|
184
|
+
if (attrs[0] === "class") {
|
|
185
|
+
setClass.call(this, attrs[1]);
|
|
186
|
+
}
|
|
187
|
+
else {
|
|
188
|
+
setAttribute.call(this, attrs[0], attrs[1]);
|
|
189
|
+
}
|
|
183
190
|
}
|
|
184
191
|
else {
|
|
185
192
|
for (let k in attrs) {
|
|
186
|
-
|
|
193
|
+
if (k === "class") {
|
|
194
|
+
setClass.call(this, attrs[k]);
|
|
195
|
+
}
|
|
196
|
+
else {
|
|
197
|
+
setAttribute.call(this, k, attrs[k]);
|
|
198
|
+
}
|
|
187
199
|
}
|
|
188
200
|
}
|
|
189
201
|
}
|
|
@@ -195,7 +207,12 @@ function attrsUpdater(attrs, oldAttrs) {
|
|
|
195
207
|
if (val === oldAttrs[1]) {
|
|
196
208
|
return;
|
|
197
209
|
}
|
|
198
|
-
|
|
210
|
+
if (name === "class") {
|
|
211
|
+
updateClass.call(this, val, oldAttrs[1]);
|
|
212
|
+
}
|
|
213
|
+
else {
|
|
214
|
+
setAttribute.call(this, name, val);
|
|
215
|
+
}
|
|
199
216
|
}
|
|
200
217
|
else {
|
|
201
218
|
removeAttribute.call(this, oldAttrs[0]);
|
|
@@ -205,13 +222,23 @@ function attrsUpdater(attrs, oldAttrs) {
|
|
|
205
222
|
else {
|
|
206
223
|
for (let k in oldAttrs) {
|
|
207
224
|
if (!(k in attrs)) {
|
|
208
|
-
|
|
225
|
+
if (k === "class") {
|
|
226
|
+
updateClass.call(this, "", oldAttrs[k]);
|
|
227
|
+
}
|
|
228
|
+
else {
|
|
229
|
+
removeAttribute.call(this, k);
|
|
230
|
+
}
|
|
209
231
|
}
|
|
210
232
|
}
|
|
211
233
|
for (let k in attrs) {
|
|
212
234
|
const val = attrs[k];
|
|
213
235
|
if (val !== oldAttrs[k]) {
|
|
214
|
-
|
|
236
|
+
if (k === "class") {
|
|
237
|
+
updateClass.call(this, val, oldAttrs[k]);
|
|
238
|
+
}
|
|
239
|
+
else {
|
|
240
|
+
setAttribute.call(this, k, val);
|
|
241
|
+
}
|
|
215
242
|
}
|
|
216
243
|
}
|
|
217
244
|
}
|
|
@@ -290,20 +317,13 @@ function updateClass(val, oldVal) {
|
|
|
290
317
|
* @returns a batched version of the original callback
|
|
291
318
|
*/
|
|
292
319
|
function batched(callback) {
|
|
293
|
-
let
|
|
294
|
-
return async () => {
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
// wait for all calls in this microtick to fall through before resetting "called"
|
|
301
|
-
// so that only the first call to the batched function calls the original callback.
|
|
302
|
-
// Schedule this before calling the callback so that calls to the batched function
|
|
303
|
-
// within the callback will proceed only after resetting called to false, and have
|
|
304
|
-
// a chance to execute the callback again
|
|
305
|
-
Promise.resolve().then(() => (called = false));
|
|
306
|
-
callback();
|
|
320
|
+
let scheduled = false;
|
|
321
|
+
return async (...args) => {
|
|
322
|
+
if (!scheduled) {
|
|
323
|
+
scheduled = true;
|
|
324
|
+
await Promise.resolve();
|
|
325
|
+
scheduled = false;
|
|
326
|
+
callback(...args);
|
|
307
327
|
}
|
|
308
328
|
};
|
|
309
329
|
}
|
|
@@ -1636,8 +1656,7 @@ function cancelFibers(fibers) {
|
|
|
1636
1656
|
let node = fiber.node;
|
|
1637
1657
|
fiber.render = throwOnRender;
|
|
1638
1658
|
if (node.status === 0 /* NEW */) {
|
|
1639
|
-
node.
|
|
1640
|
-
delete node.parent.children[node.parentKey];
|
|
1659
|
+
node.cancel();
|
|
1641
1660
|
}
|
|
1642
1661
|
node.fiber = null;
|
|
1643
1662
|
if (fiber.bdom) {
|
|
@@ -2364,6 +2383,9 @@ class ComponentNode {
|
|
|
2364
2383
|
}
|
|
2365
2384
|
}
|
|
2366
2385
|
async render(deep) {
|
|
2386
|
+
if (this.status >= 2 /* CANCELLED */) {
|
|
2387
|
+
return;
|
|
2388
|
+
}
|
|
2367
2389
|
let current = this.fiber;
|
|
2368
2390
|
if (current && (current.root.locked || current.bdom === true)) {
|
|
2369
2391
|
await Promise.resolve();
|
|
@@ -2389,7 +2411,7 @@ class ComponentNode {
|
|
|
2389
2411
|
this.fiber = fiber;
|
|
2390
2412
|
this.app.scheduler.addFiber(fiber);
|
|
2391
2413
|
await Promise.resolve();
|
|
2392
|
-
if (this.status
|
|
2414
|
+
if (this.status >= 2 /* CANCELLED */) {
|
|
2393
2415
|
return;
|
|
2394
2416
|
}
|
|
2395
2417
|
// We only want to actually render the component if the following two
|
|
@@ -2407,6 +2429,18 @@ class ComponentNode {
|
|
|
2407
2429
|
fiber.render();
|
|
2408
2430
|
}
|
|
2409
2431
|
}
|
|
2432
|
+
cancel() {
|
|
2433
|
+
this._cancel();
|
|
2434
|
+
delete this.parent.children[this.parentKey];
|
|
2435
|
+
this.app.scheduler.scheduleDestroy(this);
|
|
2436
|
+
}
|
|
2437
|
+
_cancel() {
|
|
2438
|
+
this.status = 2 /* CANCELLED */;
|
|
2439
|
+
const children = this.children;
|
|
2440
|
+
for (let childKey in children) {
|
|
2441
|
+
children[childKey]._cancel();
|
|
2442
|
+
}
|
|
2443
|
+
}
|
|
2410
2444
|
destroy() {
|
|
2411
2445
|
let shouldRemove = this.status === 1 /* MOUNTED */;
|
|
2412
2446
|
this._destroy();
|
|
@@ -2434,7 +2468,7 @@ class ComponentNode {
|
|
|
2434
2468
|
this.app.handleError({ error: e, node: this });
|
|
2435
2469
|
}
|
|
2436
2470
|
}
|
|
2437
|
-
this.status =
|
|
2471
|
+
this.status = 3 /* DESTROYED */;
|
|
2438
2472
|
}
|
|
2439
2473
|
async updateAndRender(props, parentFiber) {
|
|
2440
2474
|
this.nextProps = props;
|
|
@@ -2967,12 +3001,22 @@ function prepareList(collection) {
|
|
|
2967
3001
|
keys = collection;
|
|
2968
3002
|
values = collection;
|
|
2969
3003
|
}
|
|
2970
|
-
else if (collection) {
|
|
2971
|
-
|
|
2972
|
-
|
|
3004
|
+
else if (collection instanceof Map) {
|
|
3005
|
+
keys = [...collection.keys()];
|
|
3006
|
+
values = [...collection.values()];
|
|
3007
|
+
}
|
|
3008
|
+
else if (collection && typeof collection === "object") {
|
|
3009
|
+
if (Symbol.iterator in collection) {
|
|
3010
|
+
keys = [...collection];
|
|
3011
|
+
values = keys;
|
|
3012
|
+
}
|
|
3013
|
+
else {
|
|
3014
|
+
values = Object.keys(collection);
|
|
3015
|
+
keys = Object.values(collection);
|
|
3016
|
+
}
|
|
2973
3017
|
}
|
|
2974
3018
|
else {
|
|
2975
|
-
throw new OwlError(
|
|
3019
|
+
throw new OwlError(`Invalid loop expression: "${collection}" is not iterable`);
|
|
2976
3020
|
}
|
|
2977
3021
|
const n = values.length;
|
|
2978
3022
|
return [keys, values, n, new Array(n)];
|
|
@@ -3879,6 +3923,10 @@ class CodeGenerator {
|
|
|
3879
3923
|
})
|
|
3880
3924
|
.join("");
|
|
3881
3925
|
}
|
|
3926
|
+
translate(str) {
|
|
3927
|
+
const match = translationRE.exec(str);
|
|
3928
|
+
return match[1] + this.translateFn(match[2]) + match[3];
|
|
3929
|
+
}
|
|
3882
3930
|
/**
|
|
3883
3931
|
* @returns the newly created block name, if any
|
|
3884
3932
|
*/
|
|
@@ -3956,8 +4004,7 @@ class CodeGenerator {
|
|
|
3956
4004
|
let { block, forceNewBlock } = ctx;
|
|
3957
4005
|
let value = ast.value;
|
|
3958
4006
|
if (value && ctx.translate !== false) {
|
|
3959
|
-
|
|
3960
|
-
value = match[1] + this.translateFn(match[2]) + match[3];
|
|
4007
|
+
value = this.translate(value);
|
|
3961
4008
|
}
|
|
3962
4009
|
if (!ctx.inPreTag) {
|
|
3963
4010
|
value = value.replace(whitespaceRE, " ");
|
|
@@ -4498,11 +4545,12 @@ class CodeGenerator {
|
|
|
4498
4545
|
else {
|
|
4499
4546
|
let value;
|
|
4500
4547
|
if (ast.defaultValue) {
|
|
4548
|
+
const defaultValue = ctx.translate ? this.translate(ast.defaultValue) : ast.defaultValue;
|
|
4501
4549
|
if (ast.value) {
|
|
4502
|
-
value = `withDefault(${expr}, \`${
|
|
4550
|
+
value = `withDefault(${expr}, \`${defaultValue}\`)`;
|
|
4503
4551
|
}
|
|
4504
4552
|
else {
|
|
4505
|
-
value = `\`${
|
|
4553
|
+
value = `\`${defaultValue}\``;
|
|
4506
4554
|
}
|
|
4507
4555
|
}
|
|
4508
4556
|
else {
|
|
@@ -4795,10 +4843,10 @@ function parseNode(node, ctx) {
|
|
|
4795
4843
|
parseTCall(node, ctx) ||
|
|
4796
4844
|
parseTCallBlock(node) ||
|
|
4797
4845
|
parseTEscNode(node, ctx) ||
|
|
4846
|
+
parseTOutNode(node, ctx) ||
|
|
4798
4847
|
parseTKey(node, ctx) ||
|
|
4799
4848
|
parseTTranslation(node, ctx) ||
|
|
4800
4849
|
parseTSlot(node, ctx) ||
|
|
4801
|
-
parseTOutNode(node, ctx) ||
|
|
4802
4850
|
parseComponent(node, ctx) ||
|
|
4803
4851
|
parseDOMNode(node, ctx) ||
|
|
4804
4852
|
parseTSetNode(node, ctx) ||
|
|
@@ -4883,10 +4931,10 @@ function parseDOMNode(node, ctx) {
|
|
|
4883
4931
|
let model = null;
|
|
4884
4932
|
for (let attr of nodeAttrsNames) {
|
|
4885
4933
|
const value = node.getAttribute(attr);
|
|
4886
|
-
if (attr
|
|
4887
|
-
|
|
4888
|
-
|
|
4889
|
-
|
|
4934
|
+
if (attr === "t-on" || attr === "t-on-") {
|
|
4935
|
+
throw new OwlError("Missing event name with t-on directive");
|
|
4936
|
+
}
|
|
4937
|
+
if (attr.startsWith("t-on-")) {
|
|
4890
4938
|
on = on || {};
|
|
4891
4939
|
on[attr.slice(5)] = value;
|
|
4892
4940
|
}
|
|
@@ -4911,10 +4959,8 @@ function parseDOMNode(node, ctx) {
|
|
|
4911
4959
|
const typeAttr = node.getAttribute("type");
|
|
4912
4960
|
const isInput = tagName === "input";
|
|
4913
4961
|
const isSelect = tagName === "select";
|
|
4914
|
-
const isTextarea = tagName === "textarea";
|
|
4915
4962
|
const isCheckboxInput = isInput && typeAttr === "checkbox";
|
|
4916
4963
|
const isRadioInput = isInput && typeAttr === "radio";
|
|
4917
|
-
const isOtherInput = isInput && !isCheckboxInput && !isRadioInput;
|
|
4918
4964
|
const hasLazyMod = attr.includes(".lazy");
|
|
4919
4965
|
const hasNumberMod = attr.includes(".number");
|
|
4920
4966
|
const hasTrimMod = attr.includes(".trim");
|
|
@@ -4926,8 +4972,8 @@ function parseDOMNode(node, ctx) {
|
|
|
4926
4972
|
specialInitTargetAttr: isRadioInput ? "checked" : null,
|
|
4927
4973
|
eventType,
|
|
4928
4974
|
hasDynamicChildren: false,
|
|
4929
|
-
shouldTrim: hasTrimMod
|
|
4930
|
-
shouldNumberize: hasNumberMod
|
|
4975
|
+
shouldTrim: hasTrimMod,
|
|
4976
|
+
shouldNumberize: hasNumberMod,
|
|
4931
4977
|
};
|
|
4932
4978
|
if (isSelect) {
|
|
4933
4979
|
// don't pollute the original ctx
|
|
@@ -4990,9 +5036,6 @@ function parseTEscNode(node, ctx) {
|
|
|
4990
5036
|
content: [tesc],
|
|
4991
5037
|
};
|
|
4992
5038
|
}
|
|
4993
|
-
if (ast.type === 11 /* TComponent */) {
|
|
4994
|
-
throw new OwlError("t-esc is not supported on Component nodes");
|
|
4995
|
-
}
|
|
4996
5039
|
return tesc;
|
|
4997
5040
|
}
|
|
4998
5041
|
// -----------------------------------------------------------------------------
|
|
@@ -5434,19 +5477,21 @@ function normalizeTIf(el) {
|
|
|
5434
5477
|
*
|
|
5435
5478
|
* @param el the element containing the tree that should be normalized
|
|
5436
5479
|
*/
|
|
5437
|
-
function
|
|
5438
|
-
const
|
|
5439
|
-
|
|
5440
|
-
|
|
5441
|
-
|
|
5442
|
-
|
|
5443
|
-
|
|
5444
|
-
|
|
5445
|
-
|
|
5446
|
-
|
|
5447
|
-
|
|
5480
|
+
function normalizeTEscTOut(el) {
|
|
5481
|
+
for (const d of ["t-esc", "t-out"]) {
|
|
5482
|
+
const elements = [...el.querySelectorAll(`[${d}]`)].filter((el) => el.tagName[0] === el.tagName[0].toUpperCase() || el.hasAttribute("t-component"));
|
|
5483
|
+
for (const el of elements) {
|
|
5484
|
+
if (el.childNodes.length) {
|
|
5485
|
+
throw new OwlError(`Cannot have ${d} on a component that already has content`);
|
|
5486
|
+
}
|
|
5487
|
+
const value = el.getAttribute(d);
|
|
5488
|
+
el.removeAttribute(d);
|
|
5489
|
+
const t = el.ownerDocument.createElement("t");
|
|
5490
|
+
if (value != null) {
|
|
5491
|
+
t.setAttribute(d, value);
|
|
5492
|
+
}
|
|
5493
|
+
el.appendChild(t);
|
|
5448
5494
|
}
|
|
5449
|
-
el.appendChild(t);
|
|
5450
5495
|
}
|
|
5451
5496
|
}
|
|
5452
5497
|
/**
|
|
@@ -5457,7 +5502,7 @@ function normalizeTEsc(el) {
|
|
|
5457
5502
|
*/
|
|
5458
5503
|
function normalizeXML(el) {
|
|
5459
5504
|
normalizeTIf(el);
|
|
5460
|
-
|
|
5505
|
+
normalizeTEscTOut(el);
|
|
5461
5506
|
}
|
|
5462
5507
|
/**
|
|
5463
5508
|
* Parses an XML string into an XML document, throwing errors on parser errors
|
|
@@ -5510,7 +5555,7 @@ function compile(template, options = {}) {
|
|
|
5510
5555
|
}
|
|
5511
5556
|
|
|
5512
5557
|
// do not modify manually. This file is generated by the release script.
|
|
5513
|
-
const version = "2.
|
|
5558
|
+
const version = "2.2";
|
|
5514
5559
|
|
|
5515
5560
|
// -----------------------------------------------------------------------------
|
|
5516
5561
|
// Scheduler
|
|
@@ -5520,11 +5565,18 @@ class Scheduler {
|
|
|
5520
5565
|
this.tasks = new Set();
|
|
5521
5566
|
this.frame = 0;
|
|
5522
5567
|
this.delayedRenders = [];
|
|
5568
|
+
this.cancelledNodes = new Set();
|
|
5523
5569
|
this.requestAnimationFrame = Scheduler.requestAnimationFrame;
|
|
5524
5570
|
}
|
|
5525
5571
|
addFiber(fiber) {
|
|
5526
5572
|
this.tasks.add(fiber.root);
|
|
5527
5573
|
}
|
|
5574
|
+
scheduleDestroy(node) {
|
|
5575
|
+
this.cancelledNodes.add(node);
|
|
5576
|
+
if (this.frame === 0) {
|
|
5577
|
+
this.frame = this.requestAnimationFrame(() => this.processTasks());
|
|
5578
|
+
}
|
|
5579
|
+
}
|
|
5528
5580
|
/**
|
|
5529
5581
|
* Process all current tasks. This only applies to the fibers that are ready.
|
|
5530
5582
|
* Other tasks are left unchanged.
|
|
@@ -5534,21 +5586,28 @@ class Scheduler {
|
|
|
5534
5586
|
let renders = this.delayedRenders;
|
|
5535
5587
|
this.delayedRenders = [];
|
|
5536
5588
|
for (let f of renders) {
|
|
5537
|
-
if (f.root && f.node.status !==
|
|
5589
|
+
if (f.root && f.node.status !== 3 /* DESTROYED */ && f.node.fiber === f) {
|
|
5538
5590
|
f.render();
|
|
5539
5591
|
}
|
|
5540
5592
|
}
|
|
5541
5593
|
}
|
|
5542
5594
|
if (this.frame === 0) {
|
|
5543
|
-
this.frame = this.requestAnimationFrame(() =>
|
|
5544
|
-
|
|
5545
|
-
|
|
5546
|
-
|
|
5547
|
-
|
|
5548
|
-
|
|
5549
|
-
|
|
5550
|
-
|
|
5551
|
-
|
|
5595
|
+
this.frame = this.requestAnimationFrame(() => this.processTasks());
|
|
5596
|
+
}
|
|
5597
|
+
}
|
|
5598
|
+
processTasks() {
|
|
5599
|
+
this.frame = 0;
|
|
5600
|
+
for (let node of this.cancelledNodes) {
|
|
5601
|
+
node._destroy();
|
|
5602
|
+
}
|
|
5603
|
+
this.cancelledNodes.clear();
|
|
5604
|
+
for (let task of this.tasks) {
|
|
5605
|
+
this.processFiber(task);
|
|
5606
|
+
}
|
|
5607
|
+
for (let task of this.tasks) {
|
|
5608
|
+
if (task.node.status === 3 /* DESTROYED */) {
|
|
5609
|
+
this.tasks.delete(task);
|
|
5610
|
+
}
|
|
5552
5611
|
}
|
|
5553
5612
|
}
|
|
5554
5613
|
processFiber(fiber) {
|
|
@@ -5561,7 +5620,7 @@ class Scheduler {
|
|
|
5561
5620
|
this.tasks.delete(fiber);
|
|
5562
5621
|
return;
|
|
5563
5622
|
}
|
|
5564
|
-
if (fiber.node.status ===
|
|
5623
|
+
if (fiber.node.status === 3 /* DESTROYED */) {
|
|
5565
5624
|
this.tasks.delete(fiber);
|
|
5566
5625
|
return;
|
|
5567
5626
|
}
|
|
@@ -5589,6 +5648,8 @@ window.__OWL_DEVTOOLS__ || (window.__OWL_DEVTOOLS__ = {
|
|
|
5589
5648
|
apps: new Set(),
|
|
5590
5649
|
Fiber: Fiber,
|
|
5591
5650
|
RootFiber: RootFiber,
|
|
5651
|
+
toRaw: toRaw,
|
|
5652
|
+
reactive: reactive,
|
|
5592
5653
|
});
|
|
5593
5654
|
class App extends TemplateSet {
|
|
5594
5655
|
constructor(Root, config = {}) {
|
|
@@ -5783,9 +5844,11 @@ function status(component) {
|
|
|
5783
5844
|
switch (component.__owl__.status) {
|
|
5784
5845
|
case 0 /* NEW */:
|
|
5785
5846
|
return "new";
|
|
5847
|
+
case 2 /* CANCELLED */:
|
|
5848
|
+
return "cancelled";
|
|
5786
5849
|
case 1 /* MOUNTED */:
|
|
5787
5850
|
return "mounted";
|
|
5788
|
-
case
|
|
5851
|
+
case 3 /* DESTROYED */:
|
|
5789
5852
|
return "destroyed";
|
|
5790
5853
|
}
|
|
5791
5854
|
}
|
|
@@ -5841,8 +5904,9 @@ function useChildSubEnv(envExtension) {
|
|
|
5841
5904
|
* will run a cleanup function before patching and before unmounting the
|
|
5842
5905
|
* the component.
|
|
5843
5906
|
*
|
|
5844
|
-
* @
|
|
5845
|
-
* @param {
|
|
5907
|
+
* @template T
|
|
5908
|
+
* @param {Effect<T>} effect the effect to run on component mount and/or patch
|
|
5909
|
+
* @param {()=>T} [computeDependencies=()=>[NaN]] a callback to compute
|
|
5846
5910
|
* dependencies that will decide if the effect needs to be cleaned up and
|
|
5847
5911
|
* run again. If the dependencies did not change, the effect will not run
|
|
5848
5912
|
* again. The default value returns an array containing only NaN because
|
|
@@ -5958,6 +6022,6 @@ exports.whenReady = whenReady;
|
|
|
5958
6022
|
exports.xml = xml;
|
|
5959
6023
|
|
|
5960
6024
|
|
|
5961
|
-
__info__.date = '2023-
|
|
5962
|
-
__info__.hash = '
|
|
6025
|
+
__info__.date = '2023-07-19T13:22:24.480Z';
|
|
6026
|
+
__info__.hash = '2e07799';
|
|
5963
6027
|
__info__.url = 'https://github.com/odoo/owl';
|