@odoo/owl 2.0.0-beta-11 → 2.0.0-beta-15
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.cjs.js +146 -140
- package/dist/owl.es.js +146 -141
- package/dist/owl.iife.js +146 -140
- package/dist/owl.iife.min.js +1 -1
- package/dist/types/compiler/code_generator.d.ts +3 -2
- package/dist/types/compiler/inline_expressions.d.ts +0 -22
- package/dist/types/owl.d.ts +5 -2
- package/dist/types/runtime/component_node.d.ts +0 -1
- package/dist/types/runtime/error_handling.d.ts +3 -0
- package/dist/types/runtime/index.d.ts +1 -0
- package/dist/types/runtime/template_helpers.d.ts +2 -0
- package/package.json +1 -2
package/dist/owl.es.js
CHANGED
|
@@ -77,6 +77,68 @@ function toggler(key, child) {
|
|
|
77
77
|
return new VToggler(key, child);
|
|
78
78
|
}
|
|
79
79
|
|
|
80
|
+
// Custom error class that wraps error that happen in the owl lifecycle
|
|
81
|
+
class OwlError extends Error {
|
|
82
|
+
}
|
|
83
|
+
// Maps fibers to thrown errors
|
|
84
|
+
const fibersInError = new WeakMap();
|
|
85
|
+
const nodeErrorHandlers = new WeakMap();
|
|
86
|
+
function _handleError(node, error) {
|
|
87
|
+
if (!node) {
|
|
88
|
+
return false;
|
|
89
|
+
}
|
|
90
|
+
const fiber = node.fiber;
|
|
91
|
+
if (fiber) {
|
|
92
|
+
fibersInError.set(fiber, error);
|
|
93
|
+
}
|
|
94
|
+
const errorHandlers = nodeErrorHandlers.get(node);
|
|
95
|
+
if (errorHandlers) {
|
|
96
|
+
let handled = false;
|
|
97
|
+
// execute in the opposite order
|
|
98
|
+
for (let i = errorHandlers.length - 1; i >= 0; i--) {
|
|
99
|
+
try {
|
|
100
|
+
errorHandlers[i](error);
|
|
101
|
+
handled = true;
|
|
102
|
+
break;
|
|
103
|
+
}
|
|
104
|
+
catch (e) {
|
|
105
|
+
error = e;
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
if (handled) {
|
|
109
|
+
return true;
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
return _handleError(node.parent, error);
|
|
113
|
+
}
|
|
114
|
+
function handleError(params) {
|
|
115
|
+
let { error } = params;
|
|
116
|
+
// Wrap error if it wasn't wrapped by wrapError (ie when not in dev mode)
|
|
117
|
+
if (!(error instanceof OwlError)) {
|
|
118
|
+
error = Object.assign(new OwlError("An error occured in the owl lifecycle"), { cause: error });
|
|
119
|
+
}
|
|
120
|
+
const node = "node" in params ? params.node : params.fiber.node;
|
|
121
|
+
const fiber = "fiber" in params ? params.fiber : node.fiber;
|
|
122
|
+
// resets the fibers on components if possible. This is important so that
|
|
123
|
+
// new renderings can be properly included in the initial one, if any.
|
|
124
|
+
let current = fiber;
|
|
125
|
+
do {
|
|
126
|
+
current.node.fiber = current;
|
|
127
|
+
current = current.parent;
|
|
128
|
+
} while (current);
|
|
129
|
+
fibersInError.set(fiber.root, error);
|
|
130
|
+
const handled = _handleError(node, error);
|
|
131
|
+
if (!handled) {
|
|
132
|
+
console.warn(`[Owl] Unhandled error. Destroying the root component`);
|
|
133
|
+
try {
|
|
134
|
+
node.app.destroy();
|
|
135
|
+
}
|
|
136
|
+
catch (e) {
|
|
137
|
+
console.error(e);
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
|
|
80
142
|
const { setAttribute: elemSetAttribute, removeAttribute } = Element.prototype;
|
|
81
143
|
const tokenList = DOMTokenList.prototype;
|
|
82
144
|
const tokenListAdd = tokenList.add;
|
|
@@ -214,7 +276,7 @@ function updateClass(val, oldVal) {
|
|
|
214
276
|
function makePropSetter(name) {
|
|
215
277
|
return function setProp(value) {
|
|
216
278
|
// support 0, fallback to empty string for other falsy values
|
|
217
|
-
this[name] = value === 0 ? 0 : value
|
|
279
|
+
this[name] = value === 0 ? 0 : value ? value.valueOf() : "";
|
|
218
280
|
};
|
|
219
281
|
}
|
|
220
282
|
function isProp(tag, key) {
|
|
@@ -698,7 +760,7 @@ function buildTree(node, parent = null, domParentTree = null) {
|
|
|
698
760
|
};
|
|
699
761
|
}
|
|
700
762
|
}
|
|
701
|
-
throw new
|
|
763
|
+
throw new OwlError("boom");
|
|
702
764
|
}
|
|
703
765
|
function addRef(tree) {
|
|
704
766
|
tree.isRef = true;
|
|
@@ -1382,61 +1444,6 @@ function remove(vnode, withBeforeRemove = false) {
|
|
|
1382
1444
|
vnode.remove();
|
|
1383
1445
|
}
|
|
1384
1446
|
|
|
1385
|
-
// Maps fibers to thrown errors
|
|
1386
|
-
const fibersInError = new WeakMap();
|
|
1387
|
-
const nodeErrorHandlers = new WeakMap();
|
|
1388
|
-
function _handleError(node, error) {
|
|
1389
|
-
if (!node) {
|
|
1390
|
-
return false;
|
|
1391
|
-
}
|
|
1392
|
-
const fiber = node.fiber;
|
|
1393
|
-
if (fiber) {
|
|
1394
|
-
fibersInError.set(fiber, error);
|
|
1395
|
-
}
|
|
1396
|
-
const errorHandlers = nodeErrorHandlers.get(node);
|
|
1397
|
-
if (errorHandlers) {
|
|
1398
|
-
let handled = false;
|
|
1399
|
-
// execute in the opposite order
|
|
1400
|
-
for (let i = errorHandlers.length - 1; i >= 0; i--) {
|
|
1401
|
-
try {
|
|
1402
|
-
errorHandlers[i](error);
|
|
1403
|
-
handled = true;
|
|
1404
|
-
break;
|
|
1405
|
-
}
|
|
1406
|
-
catch (e) {
|
|
1407
|
-
error = e;
|
|
1408
|
-
}
|
|
1409
|
-
}
|
|
1410
|
-
if (handled) {
|
|
1411
|
-
return true;
|
|
1412
|
-
}
|
|
1413
|
-
}
|
|
1414
|
-
return _handleError(node.parent, error);
|
|
1415
|
-
}
|
|
1416
|
-
function handleError(params) {
|
|
1417
|
-
const error = params.error;
|
|
1418
|
-
const node = "node" in params ? params.node : params.fiber.node;
|
|
1419
|
-
const fiber = "fiber" in params ? params.fiber : node.fiber;
|
|
1420
|
-
// resets the fibers on components if possible. This is important so that
|
|
1421
|
-
// new renderings can be properly included in the initial one, if any.
|
|
1422
|
-
let current = fiber;
|
|
1423
|
-
do {
|
|
1424
|
-
current.node.fiber = current;
|
|
1425
|
-
current = current.parent;
|
|
1426
|
-
} while (current);
|
|
1427
|
-
fibersInError.set(fiber.root, error);
|
|
1428
|
-
const handled = _handleError(node, error);
|
|
1429
|
-
if (!handled) {
|
|
1430
|
-
console.warn(`[Owl] Unhandled error. Destroying the root component`);
|
|
1431
|
-
try {
|
|
1432
|
-
node.app.destroy();
|
|
1433
|
-
}
|
|
1434
|
-
catch (e) {
|
|
1435
|
-
console.error(e);
|
|
1436
|
-
}
|
|
1437
|
-
}
|
|
1438
|
-
}
|
|
1439
|
-
|
|
1440
1447
|
function makeChildFiber(node, parent) {
|
|
1441
1448
|
let current = node.fiber;
|
|
1442
1449
|
if (current) {
|
|
@@ -1475,7 +1482,7 @@ function makeRootFiber(node) {
|
|
|
1475
1482
|
return fiber;
|
|
1476
1483
|
}
|
|
1477
1484
|
function throwOnRender() {
|
|
1478
|
-
throw new
|
|
1485
|
+
throw new OwlError("Attempted to render cancelled fiber");
|
|
1479
1486
|
}
|
|
1480
1487
|
/**
|
|
1481
1488
|
* @returns number of not-yet rendered fibers cancelled
|
|
@@ -1852,7 +1859,7 @@ const reactiveCache = new WeakMap();
|
|
|
1852
1859
|
*/
|
|
1853
1860
|
function reactive(target, callback = () => { }) {
|
|
1854
1861
|
if (!canBeMadeReactive(target)) {
|
|
1855
|
-
throw new
|
|
1862
|
+
throw new OwlError(`Cannot make the given value reactive`);
|
|
1856
1863
|
}
|
|
1857
1864
|
if (SKIP in target) {
|
|
1858
1865
|
return target;
|
|
@@ -2121,10 +2128,10 @@ function batched(callback) {
|
|
|
2121
2128
|
}
|
|
2122
2129
|
function validateTarget(target) {
|
|
2123
2130
|
if (!(target instanceof HTMLElement)) {
|
|
2124
|
-
throw new
|
|
2131
|
+
throw new OwlError("Cannot mount component: the target is not a valid DOM element");
|
|
2125
2132
|
}
|
|
2126
2133
|
if (!document.body.contains(target)) {
|
|
2127
|
-
throw new
|
|
2134
|
+
throw new OwlError("Cannot mount a component on a detached dom node");
|
|
2128
2135
|
}
|
|
2129
2136
|
}
|
|
2130
2137
|
class EventBus extends EventTarget {
|
|
@@ -2145,7 +2152,7 @@ function whenReady(fn) {
|
|
|
2145
2152
|
async function loadFile(url) {
|
|
2146
2153
|
const result = await fetch(url);
|
|
2147
2154
|
if (!result.ok) {
|
|
2148
|
-
throw new
|
|
2155
|
+
throw new OwlError("Error while fetching xml templates");
|
|
2149
2156
|
}
|
|
2150
2157
|
return await result.text();
|
|
2151
2158
|
}
|
|
@@ -2167,7 +2174,7 @@ function markup(value) {
|
|
|
2167
2174
|
let currentNode = null;
|
|
2168
2175
|
function getCurrent() {
|
|
2169
2176
|
if (!currentNode) {
|
|
2170
|
-
throw new
|
|
2177
|
+
throw new OwlError("No active component (a hook function should only be called in 'setup')");
|
|
2171
2178
|
}
|
|
2172
2179
|
return currentNode;
|
|
2173
2180
|
}
|
|
@@ -2229,7 +2236,6 @@ class ComponentNode {
|
|
|
2229
2236
|
this.parent = parent;
|
|
2230
2237
|
this.props = props;
|
|
2231
2238
|
this.parentKey = parentKey;
|
|
2232
|
-
this.level = parent ? parent.level + 1 : 0;
|
|
2233
2239
|
const defaultProps = C.defaultProps;
|
|
2234
2240
|
props = Object.assign({}, props);
|
|
2235
2241
|
if (defaultProps) {
|
|
@@ -2462,17 +2468,24 @@ class ComponentNode {
|
|
|
2462
2468
|
|
|
2463
2469
|
const TIMEOUT = Symbol("timeout");
|
|
2464
2470
|
function wrapError(fn, hookName) {
|
|
2465
|
-
const error = new
|
|
2466
|
-
const timeoutError = new
|
|
2471
|
+
const error = new OwlError(`The following error occurred in ${hookName}: `);
|
|
2472
|
+
const timeoutError = new OwlError(`${hookName}'s promise hasn't resolved after 3 seconds`);
|
|
2467
2473
|
const node = getCurrent();
|
|
2468
2474
|
return (...args) => {
|
|
2475
|
+
const onError = (cause) => {
|
|
2476
|
+
if (cause instanceof Error) {
|
|
2477
|
+
error.cause = cause;
|
|
2478
|
+
error.message += `"${cause.message}"`;
|
|
2479
|
+
}
|
|
2480
|
+
throw error;
|
|
2481
|
+
};
|
|
2469
2482
|
try {
|
|
2470
2483
|
const result = fn(...args);
|
|
2471
2484
|
if (result instanceof Promise) {
|
|
2472
2485
|
if (hookName === "onWillStart" || hookName === "onWillUpdateProps") {
|
|
2473
2486
|
const fiber = node.fiber;
|
|
2474
2487
|
Promise.race([
|
|
2475
|
-
result,
|
|
2488
|
+
result.catch(() => { }),
|
|
2476
2489
|
new Promise((resolve) => setTimeout(() => resolve(TIMEOUT), 3000)),
|
|
2477
2490
|
]).then((res) => {
|
|
2478
2491
|
if (res === TIMEOUT && node.fiber === fiber) {
|
|
@@ -2480,21 +2493,12 @@ function wrapError(fn, hookName) {
|
|
|
2480
2493
|
}
|
|
2481
2494
|
});
|
|
2482
2495
|
}
|
|
2483
|
-
return result.catch(
|
|
2484
|
-
error.cause = cause;
|
|
2485
|
-
if (cause instanceof Error) {
|
|
2486
|
-
error.message += `"${cause.message}"`;
|
|
2487
|
-
}
|
|
2488
|
-
throw error;
|
|
2489
|
-
});
|
|
2496
|
+
return result.catch(onError);
|
|
2490
2497
|
}
|
|
2491
2498
|
return result;
|
|
2492
2499
|
}
|
|
2493
2500
|
catch (cause) {
|
|
2494
|
-
|
|
2495
|
-
error.message += `"${cause.message}"`;
|
|
2496
|
-
}
|
|
2497
|
-
throw error;
|
|
2501
|
+
onError(cause);
|
|
2498
2502
|
}
|
|
2499
2503
|
};
|
|
2500
2504
|
}
|
|
@@ -2598,7 +2602,7 @@ class VPortal extends VText {
|
|
|
2598
2602
|
}
|
|
2599
2603
|
this.target = el && el.querySelector(this.selector);
|
|
2600
2604
|
if (!this.target) {
|
|
2601
|
-
throw new
|
|
2605
|
+
throw new OwlError("invalid portal target");
|
|
2602
2606
|
}
|
|
2603
2607
|
}
|
|
2604
2608
|
this.realBDom.mount(this.target, null);
|
|
@@ -2692,7 +2696,7 @@ function toSchema(spec) {
|
|
|
2692
2696
|
function validate(obj, spec) {
|
|
2693
2697
|
let errors = validateSchema(obj, spec);
|
|
2694
2698
|
if (errors.length) {
|
|
2695
|
-
throw new
|
|
2699
|
+
throw new OwlError("Invalid object: " + errors.join(", "));
|
|
2696
2700
|
}
|
|
2697
2701
|
}
|
|
2698
2702
|
/**
|
|
@@ -2845,7 +2849,7 @@ function prepareList(collection) {
|
|
|
2845
2849
|
keys = Object.values(collection);
|
|
2846
2850
|
}
|
|
2847
2851
|
else {
|
|
2848
|
-
throw new
|
|
2852
|
+
throw new OwlError("Invalid loop expression");
|
|
2849
2853
|
}
|
|
2850
2854
|
const n = values.length;
|
|
2851
2855
|
return [keys, values, n, new Array(n)];
|
|
@@ -2951,7 +2955,7 @@ function multiRefSetter(refs, name) {
|
|
|
2951
2955
|
if (el) {
|
|
2952
2956
|
count++;
|
|
2953
2957
|
if (count > 1) {
|
|
2954
|
-
throw new
|
|
2958
|
+
throw new OwlError("Cannot have 2 elements with same ref name at the same time");
|
|
2955
2959
|
}
|
|
2956
2960
|
}
|
|
2957
2961
|
if (count === 0 || el) {
|
|
@@ -2988,13 +2992,13 @@ function validateProps(name, props, parent) {
|
|
|
2988
2992
|
: name in schema && !("*" in schema) && !isOptional(schema[name]);
|
|
2989
2993
|
for (let p in defaultProps) {
|
|
2990
2994
|
if (isMandatory(p)) {
|
|
2991
|
-
throw new
|
|
2995
|
+
throw new OwlError(`A default value cannot be defined for a mandatory prop (name: '${p}', component: ${ComponentClass.name})`);
|
|
2992
2996
|
}
|
|
2993
2997
|
}
|
|
2994
2998
|
}
|
|
2995
2999
|
const errors = validateSchema(props, schema);
|
|
2996
3000
|
if (errors.length) {
|
|
2997
|
-
throw new
|
|
3001
|
+
throw new OwlError(`Invalid props for component '${ComponentClass.name}': ` + errors.join(", "));
|
|
2998
3002
|
}
|
|
2999
3003
|
}
|
|
3000
3004
|
const helpers = {
|
|
@@ -3015,6 +3019,7 @@ const helpers = {
|
|
|
3015
3019
|
bind,
|
|
3016
3020
|
createCatcher,
|
|
3017
3021
|
markRaw,
|
|
3022
|
+
OwlError,
|
|
3018
3023
|
};
|
|
3019
3024
|
|
|
3020
3025
|
const bdom = { text, createBlock, list, multi, html, toggler, comment };
|
|
@@ -3042,7 +3047,7 @@ function parseXML$1(xml) {
|
|
|
3042
3047
|
}
|
|
3043
3048
|
}
|
|
3044
3049
|
}
|
|
3045
|
-
throw new
|
|
3050
|
+
throw new OwlError(msg);
|
|
3046
3051
|
}
|
|
3047
3052
|
return doc;
|
|
3048
3053
|
}
|
|
@@ -3073,7 +3078,7 @@ class TemplateSet {
|
|
|
3073
3078
|
if (currentAsString === newAsString) {
|
|
3074
3079
|
return;
|
|
3075
3080
|
}
|
|
3076
|
-
throw new
|
|
3081
|
+
throw new OwlError(`Template ${name} already defined with different content`);
|
|
3077
3082
|
}
|
|
3078
3083
|
this.rawTemplates[name] = template;
|
|
3079
3084
|
}
|
|
@@ -3098,7 +3103,7 @@ class TemplateSet {
|
|
|
3098
3103
|
extraInfo = ` (for component "${componentName}")`;
|
|
3099
3104
|
}
|
|
3100
3105
|
catch { }
|
|
3101
|
-
throw new
|
|
3106
|
+
throw new OwlError(`Missing template: "${name}"${extraInfo}`);
|
|
3102
3107
|
}
|
|
3103
3108
|
const isFn = typeof rawTemplate === "function" && !(rawTemplate instanceof Element);
|
|
3104
3109
|
const templateFn = isFn ? rawTemplate : this._compileTemplate(name, rawTemplate);
|
|
@@ -3114,7 +3119,7 @@ class TemplateSet {
|
|
|
3114
3119
|
return this.templates[name];
|
|
3115
3120
|
}
|
|
3116
3121
|
_compileTemplate(name, template) {
|
|
3117
|
-
throw new
|
|
3122
|
+
throw new OwlError(`Unable to compile a template. Please use owl full build instead`);
|
|
3118
3123
|
}
|
|
3119
3124
|
callTemplate(owner, subTemplate, ctx, parent, key) {
|
|
3120
3125
|
const template = this.getTemplate(subTemplate);
|
|
@@ -3196,14 +3201,14 @@ let tokenizeString = function (expr) {
|
|
|
3196
3201
|
i++;
|
|
3197
3202
|
cur = expr[i];
|
|
3198
3203
|
if (!cur) {
|
|
3199
|
-
throw new
|
|
3204
|
+
throw new OwlError("Invalid expression");
|
|
3200
3205
|
}
|
|
3201
3206
|
s += cur;
|
|
3202
3207
|
}
|
|
3203
3208
|
i++;
|
|
3204
3209
|
}
|
|
3205
3210
|
if (expr[i] !== start) {
|
|
3206
|
-
throw new
|
|
3211
|
+
throw new OwlError("Invalid expression");
|
|
3207
3212
|
}
|
|
3208
3213
|
s += start;
|
|
3209
3214
|
if (start === "`") {
|
|
@@ -3310,7 +3315,7 @@ function tokenize(expr) {
|
|
|
3310
3315
|
error = e; // Silence all errors and throw a generic error below
|
|
3311
3316
|
}
|
|
3312
3317
|
if (current.length || error) {
|
|
3313
|
-
throw new
|
|
3318
|
+
throw new OwlError(`Tokenizer error: could not tokenize \`${expr}\``);
|
|
3314
3319
|
}
|
|
3315
3320
|
return result;
|
|
3316
3321
|
}
|
|
@@ -3674,8 +3679,8 @@ class CodeGenerator {
|
|
|
3674
3679
|
define(varName, expr) {
|
|
3675
3680
|
this.addLine(`const ${varName} = ${expr};`);
|
|
3676
3681
|
}
|
|
3677
|
-
insertAnchor(block) {
|
|
3678
|
-
const tag = `block-child-${
|
|
3682
|
+
insertAnchor(block, index = block.children.length) {
|
|
3683
|
+
const tag = `block-child-${index}`;
|
|
3679
3684
|
const anchor = xmlDoc.createElement(tag);
|
|
3680
3685
|
block.insert(anchor);
|
|
3681
3686
|
}
|
|
@@ -3861,7 +3866,7 @@ class CodeGenerator {
|
|
|
3861
3866
|
.slice(1)
|
|
3862
3867
|
.map((m) => {
|
|
3863
3868
|
if (!MODS.has(m)) {
|
|
3864
|
-
throw new
|
|
3869
|
+
throw new OwlError(`Unknown event modifier: '${m}'`);
|
|
3865
3870
|
}
|
|
3866
3871
|
return `"${m}"`;
|
|
3867
3872
|
});
|
|
@@ -3903,13 +3908,18 @@ class CodeGenerator {
|
|
|
3903
3908
|
attrs["block-attribute-" + idx] = attrName;
|
|
3904
3909
|
}
|
|
3905
3910
|
else if (key.startsWith("t-att")) {
|
|
3911
|
+
attrName = key === "t-att" ? null : key.slice(6);
|
|
3906
3912
|
expr = compileExpr(ast.attrs[key]);
|
|
3913
|
+
if (attrName && isProp(ast.tag, attrName)) {
|
|
3914
|
+
// we force a new string or new boolean to bypass the equality check in blockdom when patching same value
|
|
3915
|
+
const C = attrName === "value" ? "String" : "Boolean";
|
|
3916
|
+
expr = `new ${C}(${expr})`;
|
|
3917
|
+
}
|
|
3907
3918
|
const idx = block.insertData(expr, "attr");
|
|
3908
3919
|
if (key === "t-att") {
|
|
3909
3920
|
attrs[`block-attributes`] = String(idx);
|
|
3910
3921
|
}
|
|
3911
3922
|
else {
|
|
3912
|
-
attrName = key.slice(6);
|
|
3913
3923
|
attrs[`block-attribute-${idx}`] = attrName;
|
|
3914
3924
|
}
|
|
3915
3925
|
}
|
|
@@ -4086,9 +4096,18 @@ class CodeGenerator {
|
|
|
4086
4096
|
}
|
|
4087
4097
|
this.insertBlock(blockStr, block, ctx);
|
|
4088
4098
|
}
|
|
4099
|
+
compileTIfBranch(content, block, ctx) {
|
|
4100
|
+
this.target.indentLevel++;
|
|
4101
|
+
let childN = block.children.length;
|
|
4102
|
+
this.compileAST(content, createContext(ctx, { block, index: ctx.index }));
|
|
4103
|
+
if (block.children.length > childN) {
|
|
4104
|
+
// we have some content => need to insert an anchor at correct index
|
|
4105
|
+
this.insertAnchor(block, childN);
|
|
4106
|
+
}
|
|
4107
|
+
this.target.indentLevel--;
|
|
4108
|
+
}
|
|
4089
4109
|
compileTIf(ast, ctx, nextNode) {
|
|
4090
|
-
let { block, forceNewBlock
|
|
4091
|
-
let currentIndex = index;
|
|
4110
|
+
let { block, forceNewBlock } = ctx;
|
|
4092
4111
|
const codeIdx = this.target.code.length;
|
|
4093
4112
|
const isNewBlock = !block || (block.type !== "multi" && forceNewBlock);
|
|
4094
4113
|
if (block) {
|
|
@@ -4098,28 +4117,16 @@ class CodeGenerator {
|
|
|
4098
4117
|
block = this.createBlock(block, "multi", ctx);
|
|
4099
4118
|
}
|
|
4100
4119
|
this.addLine(`if (${compileExpr(ast.condition)}) {`);
|
|
4101
|
-
this.
|
|
4102
|
-
this.insertAnchor(block);
|
|
4103
|
-
const subCtx = createContext(ctx, { block, index: currentIndex });
|
|
4104
|
-
this.compileAST(ast.content, subCtx);
|
|
4105
|
-
this.target.indentLevel--;
|
|
4120
|
+
this.compileTIfBranch(ast.content, block, ctx);
|
|
4106
4121
|
if (ast.tElif) {
|
|
4107
4122
|
for (let clause of ast.tElif) {
|
|
4108
4123
|
this.addLine(`} else if (${compileExpr(clause.condition)}) {`);
|
|
4109
|
-
this.
|
|
4110
|
-
this.insertAnchor(block);
|
|
4111
|
-
const subCtx = createContext(ctx, { block, index: currentIndex });
|
|
4112
|
-
this.compileAST(clause.content, subCtx);
|
|
4113
|
-
this.target.indentLevel--;
|
|
4124
|
+
this.compileTIfBranch(clause.content, block, ctx);
|
|
4114
4125
|
}
|
|
4115
4126
|
}
|
|
4116
4127
|
if (ast.tElse) {
|
|
4117
4128
|
this.addLine(`} else {`);
|
|
4118
|
-
this.
|
|
4119
|
-
this.insertAnchor(block);
|
|
4120
|
-
const subCtx = createContext(ctx, { block, index: currentIndex });
|
|
4121
|
-
this.compileAST(ast.tElse, subCtx);
|
|
4122
|
-
this.target.indentLevel--;
|
|
4129
|
+
this.compileTIfBranch(ast.tElse, block, ctx);
|
|
4123
4130
|
}
|
|
4124
4131
|
this.addLine("}");
|
|
4125
4132
|
if (isNewBlock) {
|
|
@@ -4180,7 +4187,8 @@ class CodeGenerator {
|
|
|
4180
4187
|
this.define(`key${this.target.loopLevel}`, ast.key ? compileExpr(ast.key) : loopVar);
|
|
4181
4188
|
if (this.dev) {
|
|
4182
4189
|
// Throw error on duplicate keys in dev mode
|
|
4183
|
-
this.
|
|
4190
|
+
this.helpers.add("OwlError");
|
|
4191
|
+
this.addLine(`if (keys${block.id}.has(key${this.target.loopLevel})) { throw new OwlError(\`Got duplicate key in t-foreach: \${key${this.target.loopLevel}}\`)}`);
|
|
4184
4192
|
this.addLine(`keys${block.id}.add(key${this.target.loopLevel});`);
|
|
4185
4193
|
}
|
|
4186
4194
|
let id;
|
|
@@ -4394,7 +4402,7 @@ class CodeGenerator {
|
|
|
4394
4402
|
value = `bind(ctx, ${value || undefined})`;
|
|
4395
4403
|
}
|
|
4396
4404
|
else {
|
|
4397
|
-
throw new
|
|
4405
|
+
throw new OwlError("Invalid prop suffix");
|
|
4398
4406
|
}
|
|
4399
4407
|
}
|
|
4400
4408
|
name = /^[a-z_]+$/i.test(name) ? name : `'${name}'`;
|
|
@@ -4587,9 +4595,6 @@ class CodeGenerator {
|
|
|
4587
4595
|
}
|
|
4588
4596
|
}
|
|
4589
4597
|
|
|
4590
|
-
// -----------------------------------------------------------------------------
|
|
4591
|
-
// AST Type definition
|
|
4592
|
-
// -----------------------------------------------------------------------------
|
|
4593
4598
|
// -----------------------------------------------------------------------------
|
|
4594
4599
|
// Parser
|
|
4595
4600
|
// -----------------------------------------------------------------------------
|
|
@@ -4698,7 +4703,7 @@ function parseDOMNode(node, ctx) {
|
|
|
4698
4703
|
return null;
|
|
4699
4704
|
}
|
|
4700
4705
|
if (tagName.startsWith("block-")) {
|
|
4701
|
-
throw new
|
|
4706
|
+
throw new OwlError(`Invalid tag name: '${tagName}'`);
|
|
4702
4707
|
}
|
|
4703
4708
|
ctx = Object.assign({}, ctx);
|
|
4704
4709
|
if (tagName === "pre") {
|
|
@@ -4717,14 +4722,14 @@ function parseDOMNode(node, ctx) {
|
|
|
4717
4722
|
const value = node.getAttribute(attr);
|
|
4718
4723
|
if (attr.startsWith("t-on")) {
|
|
4719
4724
|
if (attr === "t-on") {
|
|
4720
|
-
throw new
|
|
4725
|
+
throw new OwlError("Missing event name with t-on directive");
|
|
4721
4726
|
}
|
|
4722
4727
|
on = on || {};
|
|
4723
4728
|
on[attr.slice(5)] = value;
|
|
4724
4729
|
}
|
|
4725
4730
|
else if (attr.startsWith("t-model")) {
|
|
4726
4731
|
if (!["input", "select", "textarea"].includes(tagName)) {
|
|
4727
|
-
throw new
|
|
4732
|
+
throw new OwlError("The t-model directive only works with <input>, <textarea> and <select>");
|
|
4728
4733
|
}
|
|
4729
4734
|
let baseExpr, expr;
|
|
4730
4735
|
if (hasDotAtTheEnd.test(value)) {
|
|
@@ -4738,7 +4743,7 @@ function parseDOMNode(node, ctx) {
|
|
|
4738
4743
|
expr = value.slice(index + 1, -1);
|
|
4739
4744
|
}
|
|
4740
4745
|
else {
|
|
4741
|
-
throw new
|
|
4746
|
+
throw new OwlError(`Invalid t-model expression: "${value}" (it should be assignable)`);
|
|
4742
4747
|
}
|
|
4743
4748
|
const typeAttr = node.getAttribute("type");
|
|
4744
4749
|
const isInput = tagName === "input";
|
|
@@ -4768,11 +4773,11 @@ function parseDOMNode(node, ctx) {
|
|
|
4768
4773
|
}
|
|
4769
4774
|
}
|
|
4770
4775
|
else if (attr.startsWith("block-")) {
|
|
4771
|
-
throw new
|
|
4776
|
+
throw new OwlError(`Invalid attribute: '${attr}'`);
|
|
4772
4777
|
}
|
|
4773
4778
|
else if (attr !== "t-name") {
|
|
4774
4779
|
if (attr.startsWith("t-") && !attr.startsWith("t-att")) {
|
|
4775
|
-
throw new
|
|
4780
|
+
throw new OwlError(`Unknown QWeb directive: '${attr}'`);
|
|
4776
4781
|
}
|
|
4777
4782
|
const tModel = ctx.tModelInfo;
|
|
4778
4783
|
if (tModel && ["t-att-value", "t-attf-value"].includes(attr)) {
|
|
@@ -4823,7 +4828,7 @@ function parseTEscNode(node, ctx) {
|
|
|
4823
4828
|
};
|
|
4824
4829
|
}
|
|
4825
4830
|
if (ast.type === 11 /* TComponent */) {
|
|
4826
|
-
throw new
|
|
4831
|
+
throw new OwlError("t-esc is not supported on Component nodes");
|
|
4827
4832
|
}
|
|
4828
4833
|
return tesc;
|
|
4829
4834
|
}
|
|
@@ -4871,7 +4876,7 @@ function parseTForEach(node, ctx) {
|
|
|
4871
4876
|
node.removeAttribute("t-as");
|
|
4872
4877
|
const key = node.getAttribute("t-key");
|
|
4873
4878
|
if (!key) {
|
|
4874
|
-
throw new
|
|
4879
|
+
throw new OwlError(`"Directive t-foreach should always be used with a t-key!" (expression: t-foreach="${collection}" t-as="${elem}")`);
|
|
4875
4880
|
}
|
|
4876
4881
|
node.removeAttribute("t-key");
|
|
4877
4882
|
const memo = node.getAttribute("t-memo") || "";
|
|
@@ -5031,7 +5036,7 @@ function parseComponent(node, ctx) {
|
|
|
5031
5036
|
const firstLetter = name[0];
|
|
5032
5037
|
let isDynamic = node.hasAttribute("t-component");
|
|
5033
5038
|
if (isDynamic && name !== "t") {
|
|
5034
|
-
throw new
|
|
5039
|
+
throw new OwlError(`Directive 't-component' can only be used on <t> nodes (used on a <${name}>)`);
|
|
5035
5040
|
}
|
|
5036
5041
|
if (!(firstLetter === firstLetter.toUpperCase() || isDynamic)) {
|
|
5037
5042
|
return null;
|
|
@@ -5055,7 +5060,7 @@ function parseComponent(node, ctx) {
|
|
|
5055
5060
|
}
|
|
5056
5061
|
else {
|
|
5057
5062
|
const message = directiveErrorMap.get(name.split("-").slice(0, 2).join("-"));
|
|
5058
|
-
throw new
|
|
5063
|
+
throw new OwlError(message || `unsupported directive on Component: ${name}`);
|
|
5059
5064
|
}
|
|
5060
5065
|
}
|
|
5061
5066
|
else {
|
|
@@ -5070,7 +5075,7 @@ function parseComponent(node, ctx) {
|
|
|
5070
5075
|
const slotNodes = Array.from(clone.querySelectorAll("[t-set-slot]"));
|
|
5071
5076
|
for (let slotNode of slotNodes) {
|
|
5072
5077
|
if (slotNode.tagName !== "t") {
|
|
5073
|
-
throw new
|
|
5078
|
+
throw new OwlError(`Directive 't-set-slot' can only be used on <t> nodes (used on a <${slotNode.tagName}>)`);
|
|
5074
5079
|
}
|
|
5075
5080
|
const name = slotNode.getAttribute("t-set-slot");
|
|
5076
5081
|
// check if this is defined in a sub component (in which case it should
|
|
@@ -5235,25 +5240,25 @@ function normalizeTIf(el) {
|
|
|
5235
5240
|
let nattr = (name) => +!!node.getAttribute(name);
|
|
5236
5241
|
if (prevElem && (pattr("t-if") || pattr("t-elif"))) {
|
|
5237
5242
|
if (pattr("t-foreach")) {
|
|
5238
|
-
throw new
|
|
5243
|
+
throw new OwlError("t-if cannot stay at the same level as t-foreach when using t-elif or t-else");
|
|
5239
5244
|
}
|
|
5240
5245
|
if (["t-if", "t-elif", "t-else"].map(nattr).reduce(function (a, b) {
|
|
5241
5246
|
return a + b;
|
|
5242
5247
|
}) > 1) {
|
|
5243
|
-
throw new
|
|
5248
|
+
throw new OwlError("Only one conditional branching directive is allowed per node");
|
|
5244
5249
|
}
|
|
5245
5250
|
// All text (with only spaces) and comment nodes (nodeType 8) between
|
|
5246
5251
|
// branch nodes are removed
|
|
5247
5252
|
let textNode;
|
|
5248
5253
|
while ((textNode = node.previousSibling) !== prevElem) {
|
|
5249
5254
|
if (textNode.nodeValue.trim().length && textNode.nodeType !== 8) {
|
|
5250
|
-
throw new
|
|
5255
|
+
throw new OwlError("text is not allowed between branching directives");
|
|
5251
5256
|
}
|
|
5252
5257
|
textNode.remove();
|
|
5253
5258
|
}
|
|
5254
5259
|
}
|
|
5255
5260
|
else {
|
|
5256
|
-
throw new
|
|
5261
|
+
throw new OwlError("t-elif and t-else directives must be preceded by a t-if or t-elif directive");
|
|
5257
5262
|
}
|
|
5258
5263
|
}
|
|
5259
5264
|
}
|
|
@@ -5269,7 +5274,7 @@ function normalizeTEsc(el) {
|
|
|
5269
5274
|
const elements = [...el.querySelectorAll("[t-esc]")].filter((el) => el.tagName[0] === el.tagName[0].toUpperCase() || el.hasAttribute("t-component"));
|
|
5270
5275
|
for (const el of elements) {
|
|
5271
5276
|
if (el.childNodes.length) {
|
|
5272
|
-
throw new
|
|
5277
|
+
throw new OwlError("Cannot have t-esc on a component that already has content");
|
|
5273
5278
|
}
|
|
5274
5279
|
const value = el.getAttribute("t-esc");
|
|
5275
5280
|
el.removeAttribute("t-esc");
|
|
@@ -5321,7 +5326,7 @@ function parseXML(xml) {
|
|
|
5321
5326
|
}
|
|
5322
5327
|
}
|
|
5323
5328
|
}
|
|
5324
|
-
throw new
|
|
5329
|
+
throw new OwlError(msg);
|
|
5325
5330
|
}
|
|
5326
5331
|
return doc;
|
|
5327
5332
|
}
|
|
@@ -5375,7 +5380,7 @@ const mainEventHandler = (data, ev, currentTarget) => {
|
|
|
5375
5380
|
if (Object.hasOwnProperty.call(data, 0)) {
|
|
5376
5381
|
const handler = data[0];
|
|
5377
5382
|
if (typeof handler !== "function") {
|
|
5378
|
-
throw new
|
|
5383
|
+
throw new OwlError(`Invalid handler (expected a function, received: '${handler}')`);
|
|
5379
5384
|
}
|
|
5380
5385
|
let node = data[1] ? data[1].__owl__ : null;
|
|
5381
5386
|
if (node ? node.status === 1 /* MOUNTED */ : true) {
|
|
@@ -5559,10 +5564,10 @@ class App extends TemplateSet {
|
|
|
5559
5564
|
if (isStatic) {
|
|
5560
5565
|
C = parent.constructor.components[name];
|
|
5561
5566
|
if (!C) {
|
|
5562
|
-
throw new
|
|
5567
|
+
throw new OwlError(`Cannot find the definition of component "${name}"`);
|
|
5563
5568
|
}
|
|
5564
5569
|
else if (!(C.prototype instanceof Component)) {
|
|
5565
|
-
throw new
|
|
5570
|
+
throw new OwlError(`"${name}" is not a Component. It must inherit from the Component class`);
|
|
5566
5571
|
}
|
|
5567
5572
|
}
|
|
5568
5573
|
node = new ComponentNode(C, props, this, ctx, key);
|
|
@@ -5718,10 +5723,10 @@ TemplateSet.prototype._compileTemplate = function _compileTemplate(name, templat
|
|
|
5718
5723
|
});
|
|
5719
5724
|
};
|
|
5720
5725
|
|
|
5721
|
-
export { App, Component, EventBus, __info__, blockDom, loadFile, markRaw, markup, mount, onError, onMounted, onPatched, onRendered, onWillDestroy, onWillPatch, onWillRender, onWillStart, onWillUnmount, onWillUpdateProps, reactive, status, toRaw, useChildSubEnv, useComponent, useEffect, useEnv, useExternalListener, useRef, useState, useSubEnv, validate, whenReady, xml };
|
|
5726
|
+
export { App, Component, EventBus, OwlError, __info__, blockDom, loadFile, markRaw, markup, mount, onError, onMounted, onPatched, onRendered, onWillDestroy, onWillPatch, onWillRender, onWillStart, onWillUnmount, onWillUpdateProps, reactive, status, toRaw, useChildSubEnv, useComponent, useEffect, useEnv, useExternalListener, useRef, useState, useSubEnv, validate, whenReady, xml };
|
|
5722
5727
|
|
|
5723
5728
|
|
|
5724
|
-
__info__.version = '2.0.0-beta-
|
|
5725
|
-
__info__.date = '2022-
|
|
5726
|
-
__info__.hash = '
|
|
5729
|
+
__info__.version = '2.0.0-beta-15';
|
|
5730
|
+
__info__.date = '2022-07-20T08:02:36.538Z';
|
|
5731
|
+
__info__.hash = '588b655';
|
|
5727
5732
|
__info__.url = 'https://github.com/odoo/owl';
|