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