@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.iife.js
CHANGED
|
@@ -80,6 +80,68 @@
|
|
|
80
80
|
return new VToggler(key, child);
|
|
81
81
|
}
|
|
82
82
|
|
|
83
|
+
// Custom error class that wraps error that happen in the owl lifecycle
|
|
84
|
+
class OwlError extends Error {
|
|
85
|
+
}
|
|
86
|
+
// Maps fibers to thrown errors
|
|
87
|
+
const fibersInError = new WeakMap();
|
|
88
|
+
const nodeErrorHandlers = new WeakMap();
|
|
89
|
+
function _handleError(node, error) {
|
|
90
|
+
if (!node) {
|
|
91
|
+
return false;
|
|
92
|
+
}
|
|
93
|
+
const fiber = node.fiber;
|
|
94
|
+
if (fiber) {
|
|
95
|
+
fibersInError.set(fiber, error);
|
|
96
|
+
}
|
|
97
|
+
const errorHandlers = nodeErrorHandlers.get(node);
|
|
98
|
+
if (errorHandlers) {
|
|
99
|
+
let handled = false;
|
|
100
|
+
// execute in the opposite order
|
|
101
|
+
for (let i = errorHandlers.length - 1; i >= 0; i--) {
|
|
102
|
+
try {
|
|
103
|
+
errorHandlers[i](error);
|
|
104
|
+
handled = true;
|
|
105
|
+
break;
|
|
106
|
+
}
|
|
107
|
+
catch (e) {
|
|
108
|
+
error = e;
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
if (handled) {
|
|
112
|
+
return true;
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
return _handleError(node.parent, error);
|
|
116
|
+
}
|
|
117
|
+
function handleError(params) {
|
|
118
|
+
let { error } = params;
|
|
119
|
+
// Wrap error if it wasn't wrapped by wrapError (ie when not in dev mode)
|
|
120
|
+
if (!(error instanceof OwlError)) {
|
|
121
|
+
error = Object.assign(new OwlError("An error occured in the owl lifecycle"), { cause: error });
|
|
122
|
+
}
|
|
123
|
+
const node = "node" in params ? params.node : params.fiber.node;
|
|
124
|
+
const fiber = "fiber" in params ? params.fiber : node.fiber;
|
|
125
|
+
// resets the fibers on components if possible. This is important so that
|
|
126
|
+
// new renderings can be properly included in the initial one, if any.
|
|
127
|
+
let current = fiber;
|
|
128
|
+
do {
|
|
129
|
+
current.node.fiber = current;
|
|
130
|
+
current = current.parent;
|
|
131
|
+
} while (current);
|
|
132
|
+
fibersInError.set(fiber.root, error);
|
|
133
|
+
const handled = _handleError(node, error);
|
|
134
|
+
if (!handled) {
|
|
135
|
+
console.warn(`[Owl] Unhandled error. Destroying the root component`);
|
|
136
|
+
try {
|
|
137
|
+
node.app.destroy();
|
|
138
|
+
}
|
|
139
|
+
catch (e) {
|
|
140
|
+
console.error(e);
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
|
|
83
145
|
const { setAttribute: elemSetAttribute, removeAttribute } = Element.prototype;
|
|
84
146
|
const tokenList = DOMTokenList.prototype;
|
|
85
147
|
const tokenListAdd = tokenList.add;
|
|
@@ -217,7 +279,7 @@
|
|
|
217
279
|
function makePropSetter(name) {
|
|
218
280
|
return function setProp(value) {
|
|
219
281
|
// support 0, fallback to empty string for other falsy values
|
|
220
|
-
this[name] = value === 0 ? 0 : value
|
|
282
|
+
this[name] = value === 0 ? 0 : value ? value.valueOf() : "";
|
|
221
283
|
};
|
|
222
284
|
}
|
|
223
285
|
function isProp(tag, key) {
|
|
@@ -701,7 +763,7 @@
|
|
|
701
763
|
};
|
|
702
764
|
}
|
|
703
765
|
}
|
|
704
|
-
throw new
|
|
766
|
+
throw new OwlError("boom");
|
|
705
767
|
}
|
|
706
768
|
function addRef(tree) {
|
|
707
769
|
tree.isRef = true;
|
|
@@ -1385,61 +1447,6 @@
|
|
|
1385
1447
|
vnode.remove();
|
|
1386
1448
|
}
|
|
1387
1449
|
|
|
1388
|
-
// Maps fibers to thrown errors
|
|
1389
|
-
const fibersInError = new WeakMap();
|
|
1390
|
-
const nodeErrorHandlers = new WeakMap();
|
|
1391
|
-
function _handleError(node, error) {
|
|
1392
|
-
if (!node) {
|
|
1393
|
-
return false;
|
|
1394
|
-
}
|
|
1395
|
-
const fiber = node.fiber;
|
|
1396
|
-
if (fiber) {
|
|
1397
|
-
fibersInError.set(fiber, error);
|
|
1398
|
-
}
|
|
1399
|
-
const errorHandlers = nodeErrorHandlers.get(node);
|
|
1400
|
-
if (errorHandlers) {
|
|
1401
|
-
let handled = false;
|
|
1402
|
-
// execute in the opposite order
|
|
1403
|
-
for (let i = errorHandlers.length - 1; i >= 0; i--) {
|
|
1404
|
-
try {
|
|
1405
|
-
errorHandlers[i](error);
|
|
1406
|
-
handled = true;
|
|
1407
|
-
break;
|
|
1408
|
-
}
|
|
1409
|
-
catch (e) {
|
|
1410
|
-
error = e;
|
|
1411
|
-
}
|
|
1412
|
-
}
|
|
1413
|
-
if (handled) {
|
|
1414
|
-
return true;
|
|
1415
|
-
}
|
|
1416
|
-
}
|
|
1417
|
-
return _handleError(node.parent, error);
|
|
1418
|
-
}
|
|
1419
|
-
function handleError(params) {
|
|
1420
|
-
const error = params.error;
|
|
1421
|
-
const node = "node" in params ? params.node : params.fiber.node;
|
|
1422
|
-
const fiber = "fiber" in params ? params.fiber : node.fiber;
|
|
1423
|
-
// resets the fibers on components if possible. This is important so that
|
|
1424
|
-
// new renderings can be properly included in the initial one, if any.
|
|
1425
|
-
let current = fiber;
|
|
1426
|
-
do {
|
|
1427
|
-
current.node.fiber = current;
|
|
1428
|
-
current = current.parent;
|
|
1429
|
-
} while (current);
|
|
1430
|
-
fibersInError.set(fiber.root, error);
|
|
1431
|
-
const handled = _handleError(node, error);
|
|
1432
|
-
if (!handled) {
|
|
1433
|
-
console.warn(`[Owl] Unhandled error. Destroying the root component`);
|
|
1434
|
-
try {
|
|
1435
|
-
node.app.destroy();
|
|
1436
|
-
}
|
|
1437
|
-
catch (e) {
|
|
1438
|
-
console.error(e);
|
|
1439
|
-
}
|
|
1440
|
-
}
|
|
1441
|
-
}
|
|
1442
|
-
|
|
1443
1450
|
function makeChildFiber(node, parent) {
|
|
1444
1451
|
let current = node.fiber;
|
|
1445
1452
|
if (current) {
|
|
@@ -1478,7 +1485,7 @@
|
|
|
1478
1485
|
return fiber;
|
|
1479
1486
|
}
|
|
1480
1487
|
function throwOnRender() {
|
|
1481
|
-
throw new
|
|
1488
|
+
throw new OwlError("Attempted to render cancelled fiber");
|
|
1482
1489
|
}
|
|
1483
1490
|
/**
|
|
1484
1491
|
* @returns number of not-yet rendered fibers cancelled
|
|
@@ -1855,7 +1862,7 @@
|
|
|
1855
1862
|
*/
|
|
1856
1863
|
function reactive(target, callback = () => { }) {
|
|
1857
1864
|
if (!canBeMadeReactive(target)) {
|
|
1858
|
-
throw new
|
|
1865
|
+
throw new OwlError(`Cannot make the given value reactive`);
|
|
1859
1866
|
}
|
|
1860
1867
|
if (SKIP in target) {
|
|
1861
1868
|
return target;
|
|
@@ -2124,10 +2131,10 @@
|
|
|
2124
2131
|
}
|
|
2125
2132
|
function validateTarget(target) {
|
|
2126
2133
|
if (!(target instanceof HTMLElement)) {
|
|
2127
|
-
throw new
|
|
2134
|
+
throw new OwlError("Cannot mount component: the target is not a valid DOM element");
|
|
2128
2135
|
}
|
|
2129
2136
|
if (!document.body.contains(target)) {
|
|
2130
|
-
throw new
|
|
2137
|
+
throw new OwlError("Cannot mount a component on a detached dom node");
|
|
2131
2138
|
}
|
|
2132
2139
|
}
|
|
2133
2140
|
class EventBus extends EventTarget {
|
|
@@ -2148,7 +2155,7 @@
|
|
|
2148
2155
|
async function loadFile(url) {
|
|
2149
2156
|
const result = await fetch(url);
|
|
2150
2157
|
if (!result.ok) {
|
|
2151
|
-
throw new
|
|
2158
|
+
throw new OwlError("Error while fetching xml templates");
|
|
2152
2159
|
}
|
|
2153
2160
|
return await result.text();
|
|
2154
2161
|
}
|
|
@@ -2170,7 +2177,7 @@
|
|
|
2170
2177
|
let currentNode = null;
|
|
2171
2178
|
function getCurrent() {
|
|
2172
2179
|
if (!currentNode) {
|
|
2173
|
-
throw new
|
|
2180
|
+
throw new OwlError("No active component (a hook function should only be called in 'setup')");
|
|
2174
2181
|
}
|
|
2175
2182
|
return currentNode;
|
|
2176
2183
|
}
|
|
@@ -2232,7 +2239,6 @@
|
|
|
2232
2239
|
this.parent = parent;
|
|
2233
2240
|
this.props = props;
|
|
2234
2241
|
this.parentKey = parentKey;
|
|
2235
|
-
this.level = parent ? parent.level + 1 : 0;
|
|
2236
2242
|
const defaultProps = C.defaultProps;
|
|
2237
2243
|
props = Object.assign({}, props);
|
|
2238
2244
|
if (defaultProps) {
|
|
@@ -2465,17 +2471,24 @@
|
|
|
2465
2471
|
|
|
2466
2472
|
const TIMEOUT = Symbol("timeout");
|
|
2467
2473
|
function wrapError(fn, hookName) {
|
|
2468
|
-
const error = new
|
|
2469
|
-
const timeoutError = new
|
|
2474
|
+
const error = new OwlError(`The following error occurred in ${hookName}: `);
|
|
2475
|
+
const timeoutError = new OwlError(`${hookName}'s promise hasn't resolved after 3 seconds`);
|
|
2470
2476
|
const node = getCurrent();
|
|
2471
2477
|
return (...args) => {
|
|
2478
|
+
const onError = (cause) => {
|
|
2479
|
+
if (cause instanceof Error) {
|
|
2480
|
+
error.cause = cause;
|
|
2481
|
+
error.message += `"${cause.message}"`;
|
|
2482
|
+
}
|
|
2483
|
+
throw error;
|
|
2484
|
+
};
|
|
2472
2485
|
try {
|
|
2473
2486
|
const result = fn(...args);
|
|
2474
2487
|
if (result instanceof Promise) {
|
|
2475
2488
|
if (hookName === "onWillStart" || hookName === "onWillUpdateProps") {
|
|
2476
2489
|
const fiber = node.fiber;
|
|
2477
2490
|
Promise.race([
|
|
2478
|
-
result,
|
|
2491
|
+
result.catch(() => { }),
|
|
2479
2492
|
new Promise((resolve) => setTimeout(() => resolve(TIMEOUT), 3000)),
|
|
2480
2493
|
]).then((res) => {
|
|
2481
2494
|
if (res === TIMEOUT && node.fiber === fiber) {
|
|
@@ -2483,21 +2496,12 @@
|
|
|
2483
2496
|
}
|
|
2484
2497
|
});
|
|
2485
2498
|
}
|
|
2486
|
-
return result.catch(
|
|
2487
|
-
error.cause = cause;
|
|
2488
|
-
if (cause instanceof Error) {
|
|
2489
|
-
error.message += `"${cause.message}"`;
|
|
2490
|
-
}
|
|
2491
|
-
throw error;
|
|
2492
|
-
});
|
|
2499
|
+
return result.catch(onError);
|
|
2493
2500
|
}
|
|
2494
2501
|
return result;
|
|
2495
2502
|
}
|
|
2496
2503
|
catch (cause) {
|
|
2497
|
-
|
|
2498
|
-
error.message += `"${cause.message}"`;
|
|
2499
|
-
}
|
|
2500
|
-
throw error;
|
|
2504
|
+
onError(cause);
|
|
2501
2505
|
}
|
|
2502
2506
|
};
|
|
2503
2507
|
}
|
|
@@ -2601,7 +2605,7 @@
|
|
|
2601
2605
|
}
|
|
2602
2606
|
this.target = el && el.querySelector(this.selector);
|
|
2603
2607
|
if (!this.target) {
|
|
2604
|
-
throw new
|
|
2608
|
+
throw new OwlError("invalid portal target");
|
|
2605
2609
|
}
|
|
2606
2610
|
}
|
|
2607
2611
|
this.realBDom.mount(this.target, null);
|
|
@@ -2695,7 +2699,7 @@
|
|
|
2695
2699
|
function validate(obj, spec) {
|
|
2696
2700
|
let errors = validateSchema(obj, spec);
|
|
2697
2701
|
if (errors.length) {
|
|
2698
|
-
throw new
|
|
2702
|
+
throw new OwlError("Invalid object: " + errors.join(", "));
|
|
2699
2703
|
}
|
|
2700
2704
|
}
|
|
2701
2705
|
/**
|
|
@@ -2848,7 +2852,7 @@
|
|
|
2848
2852
|
keys = Object.values(collection);
|
|
2849
2853
|
}
|
|
2850
2854
|
else {
|
|
2851
|
-
throw new
|
|
2855
|
+
throw new OwlError("Invalid loop expression");
|
|
2852
2856
|
}
|
|
2853
2857
|
const n = values.length;
|
|
2854
2858
|
return [keys, values, n, new Array(n)];
|
|
@@ -2954,7 +2958,7 @@
|
|
|
2954
2958
|
if (el) {
|
|
2955
2959
|
count++;
|
|
2956
2960
|
if (count > 1) {
|
|
2957
|
-
throw new
|
|
2961
|
+
throw new OwlError("Cannot have 2 elements with same ref name at the same time");
|
|
2958
2962
|
}
|
|
2959
2963
|
}
|
|
2960
2964
|
if (count === 0 || el) {
|
|
@@ -2991,13 +2995,13 @@
|
|
|
2991
2995
|
: name in schema && !("*" in schema) && !isOptional(schema[name]);
|
|
2992
2996
|
for (let p in defaultProps) {
|
|
2993
2997
|
if (isMandatory(p)) {
|
|
2994
|
-
throw new
|
|
2998
|
+
throw new OwlError(`A default value cannot be defined for a mandatory prop (name: '${p}', component: ${ComponentClass.name})`);
|
|
2995
2999
|
}
|
|
2996
3000
|
}
|
|
2997
3001
|
}
|
|
2998
3002
|
const errors = validateSchema(props, schema);
|
|
2999
3003
|
if (errors.length) {
|
|
3000
|
-
throw new
|
|
3004
|
+
throw new OwlError(`Invalid props for component '${ComponentClass.name}': ` + errors.join(", "));
|
|
3001
3005
|
}
|
|
3002
3006
|
}
|
|
3003
3007
|
const helpers = {
|
|
@@ -3018,6 +3022,7 @@
|
|
|
3018
3022
|
bind,
|
|
3019
3023
|
createCatcher,
|
|
3020
3024
|
markRaw,
|
|
3025
|
+
OwlError,
|
|
3021
3026
|
};
|
|
3022
3027
|
|
|
3023
3028
|
const bdom = { text, createBlock, list, multi, html, toggler, comment };
|
|
@@ -3045,7 +3050,7 @@
|
|
|
3045
3050
|
}
|
|
3046
3051
|
}
|
|
3047
3052
|
}
|
|
3048
|
-
throw new
|
|
3053
|
+
throw new OwlError(msg);
|
|
3049
3054
|
}
|
|
3050
3055
|
return doc;
|
|
3051
3056
|
}
|
|
@@ -3076,7 +3081,7 @@
|
|
|
3076
3081
|
if (currentAsString === newAsString) {
|
|
3077
3082
|
return;
|
|
3078
3083
|
}
|
|
3079
|
-
throw new
|
|
3084
|
+
throw new OwlError(`Template ${name} already defined with different content`);
|
|
3080
3085
|
}
|
|
3081
3086
|
this.rawTemplates[name] = template;
|
|
3082
3087
|
}
|
|
@@ -3101,7 +3106,7 @@
|
|
|
3101
3106
|
extraInfo = ` (for component "${componentName}")`;
|
|
3102
3107
|
}
|
|
3103
3108
|
catch { }
|
|
3104
|
-
throw new
|
|
3109
|
+
throw new OwlError(`Missing template: "${name}"${extraInfo}`);
|
|
3105
3110
|
}
|
|
3106
3111
|
const isFn = typeof rawTemplate === "function" && !(rawTemplate instanceof Element);
|
|
3107
3112
|
const templateFn = isFn ? rawTemplate : this._compileTemplate(name, rawTemplate);
|
|
@@ -3117,7 +3122,7 @@
|
|
|
3117
3122
|
return this.templates[name];
|
|
3118
3123
|
}
|
|
3119
3124
|
_compileTemplate(name, template) {
|
|
3120
|
-
throw new
|
|
3125
|
+
throw new OwlError(`Unable to compile a template. Please use owl full build instead`);
|
|
3121
3126
|
}
|
|
3122
3127
|
callTemplate(owner, subTemplate, ctx, parent, key) {
|
|
3123
3128
|
const template = this.getTemplate(subTemplate);
|
|
@@ -3199,14 +3204,14 @@
|
|
|
3199
3204
|
i++;
|
|
3200
3205
|
cur = expr[i];
|
|
3201
3206
|
if (!cur) {
|
|
3202
|
-
throw new
|
|
3207
|
+
throw new OwlError("Invalid expression");
|
|
3203
3208
|
}
|
|
3204
3209
|
s += cur;
|
|
3205
3210
|
}
|
|
3206
3211
|
i++;
|
|
3207
3212
|
}
|
|
3208
3213
|
if (expr[i] !== start) {
|
|
3209
|
-
throw new
|
|
3214
|
+
throw new OwlError("Invalid expression");
|
|
3210
3215
|
}
|
|
3211
3216
|
s += start;
|
|
3212
3217
|
if (start === "`") {
|
|
@@ -3313,7 +3318,7 @@
|
|
|
3313
3318
|
error = e; // Silence all errors and throw a generic error below
|
|
3314
3319
|
}
|
|
3315
3320
|
if (current.length || error) {
|
|
3316
|
-
throw new
|
|
3321
|
+
throw new OwlError(`Tokenizer error: could not tokenize \`${expr}\``);
|
|
3317
3322
|
}
|
|
3318
3323
|
return result;
|
|
3319
3324
|
}
|
|
@@ -3677,8 +3682,8 @@
|
|
|
3677
3682
|
define(varName, expr) {
|
|
3678
3683
|
this.addLine(`const ${varName} = ${expr};`);
|
|
3679
3684
|
}
|
|
3680
|
-
insertAnchor(block) {
|
|
3681
|
-
const tag = `block-child-${
|
|
3685
|
+
insertAnchor(block, index = block.children.length) {
|
|
3686
|
+
const tag = `block-child-${index}`;
|
|
3682
3687
|
const anchor = xmlDoc.createElement(tag);
|
|
3683
3688
|
block.insert(anchor);
|
|
3684
3689
|
}
|
|
@@ -3864,7 +3869,7 @@
|
|
|
3864
3869
|
.slice(1)
|
|
3865
3870
|
.map((m) => {
|
|
3866
3871
|
if (!MODS.has(m)) {
|
|
3867
|
-
throw new
|
|
3872
|
+
throw new OwlError(`Unknown event modifier: '${m}'`);
|
|
3868
3873
|
}
|
|
3869
3874
|
return `"${m}"`;
|
|
3870
3875
|
});
|
|
@@ -3906,13 +3911,18 @@
|
|
|
3906
3911
|
attrs["block-attribute-" + idx] = attrName;
|
|
3907
3912
|
}
|
|
3908
3913
|
else if (key.startsWith("t-att")) {
|
|
3914
|
+
attrName = key === "t-att" ? null : key.slice(6);
|
|
3909
3915
|
expr = compileExpr(ast.attrs[key]);
|
|
3916
|
+
if (attrName && isProp(ast.tag, attrName)) {
|
|
3917
|
+
// we force a new string or new boolean to bypass the equality check in blockdom when patching same value
|
|
3918
|
+
const C = attrName === "value" ? "String" : "Boolean";
|
|
3919
|
+
expr = `new ${C}(${expr})`;
|
|
3920
|
+
}
|
|
3910
3921
|
const idx = block.insertData(expr, "attr");
|
|
3911
3922
|
if (key === "t-att") {
|
|
3912
3923
|
attrs[`block-attributes`] = String(idx);
|
|
3913
3924
|
}
|
|
3914
3925
|
else {
|
|
3915
|
-
attrName = key.slice(6);
|
|
3916
3926
|
attrs[`block-attribute-${idx}`] = attrName;
|
|
3917
3927
|
}
|
|
3918
3928
|
}
|
|
@@ -4089,9 +4099,18 @@
|
|
|
4089
4099
|
}
|
|
4090
4100
|
this.insertBlock(blockStr, block, ctx);
|
|
4091
4101
|
}
|
|
4102
|
+
compileTIfBranch(content, block, ctx) {
|
|
4103
|
+
this.target.indentLevel++;
|
|
4104
|
+
let childN = block.children.length;
|
|
4105
|
+
this.compileAST(content, createContext(ctx, { block, index: ctx.index }));
|
|
4106
|
+
if (block.children.length > childN) {
|
|
4107
|
+
// we have some content => need to insert an anchor at correct index
|
|
4108
|
+
this.insertAnchor(block, childN);
|
|
4109
|
+
}
|
|
4110
|
+
this.target.indentLevel--;
|
|
4111
|
+
}
|
|
4092
4112
|
compileTIf(ast, ctx, nextNode) {
|
|
4093
|
-
let { block, forceNewBlock
|
|
4094
|
-
let currentIndex = index;
|
|
4113
|
+
let { block, forceNewBlock } = ctx;
|
|
4095
4114
|
const codeIdx = this.target.code.length;
|
|
4096
4115
|
const isNewBlock = !block || (block.type !== "multi" && forceNewBlock);
|
|
4097
4116
|
if (block) {
|
|
@@ -4101,28 +4120,16 @@
|
|
|
4101
4120
|
block = this.createBlock(block, "multi", ctx);
|
|
4102
4121
|
}
|
|
4103
4122
|
this.addLine(`if (${compileExpr(ast.condition)}) {`);
|
|
4104
|
-
this.
|
|
4105
|
-
this.insertAnchor(block);
|
|
4106
|
-
const subCtx = createContext(ctx, { block, index: currentIndex });
|
|
4107
|
-
this.compileAST(ast.content, subCtx);
|
|
4108
|
-
this.target.indentLevel--;
|
|
4123
|
+
this.compileTIfBranch(ast.content, block, ctx);
|
|
4109
4124
|
if (ast.tElif) {
|
|
4110
4125
|
for (let clause of ast.tElif) {
|
|
4111
4126
|
this.addLine(`} else if (${compileExpr(clause.condition)}) {`);
|
|
4112
|
-
this.
|
|
4113
|
-
this.insertAnchor(block);
|
|
4114
|
-
const subCtx = createContext(ctx, { block, index: currentIndex });
|
|
4115
|
-
this.compileAST(clause.content, subCtx);
|
|
4116
|
-
this.target.indentLevel--;
|
|
4127
|
+
this.compileTIfBranch(clause.content, block, ctx);
|
|
4117
4128
|
}
|
|
4118
4129
|
}
|
|
4119
4130
|
if (ast.tElse) {
|
|
4120
4131
|
this.addLine(`} else {`);
|
|
4121
|
-
this.
|
|
4122
|
-
this.insertAnchor(block);
|
|
4123
|
-
const subCtx = createContext(ctx, { block, index: currentIndex });
|
|
4124
|
-
this.compileAST(ast.tElse, subCtx);
|
|
4125
|
-
this.target.indentLevel--;
|
|
4132
|
+
this.compileTIfBranch(ast.tElse, block, ctx);
|
|
4126
4133
|
}
|
|
4127
4134
|
this.addLine("}");
|
|
4128
4135
|
if (isNewBlock) {
|
|
@@ -4183,7 +4190,8 @@
|
|
|
4183
4190
|
this.define(`key${this.target.loopLevel}`, ast.key ? compileExpr(ast.key) : loopVar);
|
|
4184
4191
|
if (this.dev) {
|
|
4185
4192
|
// Throw error on duplicate keys in dev mode
|
|
4186
|
-
this.
|
|
4193
|
+
this.helpers.add("OwlError");
|
|
4194
|
+
this.addLine(`if (keys${block.id}.has(key${this.target.loopLevel})) { throw new OwlError(\`Got duplicate key in t-foreach: \${key${this.target.loopLevel}}\`)}`);
|
|
4187
4195
|
this.addLine(`keys${block.id}.add(key${this.target.loopLevel});`);
|
|
4188
4196
|
}
|
|
4189
4197
|
let id;
|
|
@@ -4397,7 +4405,7 @@
|
|
|
4397
4405
|
value = `bind(ctx, ${value || undefined})`;
|
|
4398
4406
|
}
|
|
4399
4407
|
else {
|
|
4400
|
-
throw new
|
|
4408
|
+
throw new OwlError("Invalid prop suffix");
|
|
4401
4409
|
}
|
|
4402
4410
|
}
|
|
4403
4411
|
name = /^[a-z_]+$/i.test(name) ? name : `'${name}'`;
|
|
@@ -4590,9 +4598,6 @@
|
|
|
4590
4598
|
}
|
|
4591
4599
|
}
|
|
4592
4600
|
|
|
4593
|
-
// -----------------------------------------------------------------------------
|
|
4594
|
-
// AST Type definition
|
|
4595
|
-
// -----------------------------------------------------------------------------
|
|
4596
4601
|
// -----------------------------------------------------------------------------
|
|
4597
4602
|
// Parser
|
|
4598
4603
|
// -----------------------------------------------------------------------------
|
|
@@ -4701,7 +4706,7 @@
|
|
|
4701
4706
|
return null;
|
|
4702
4707
|
}
|
|
4703
4708
|
if (tagName.startsWith("block-")) {
|
|
4704
|
-
throw new
|
|
4709
|
+
throw new OwlError(`Invalid tag name: '${tagName}'`);
|
|
4705
4710
|
}
|
|
4706
4711
|
ctx = Object.assign({}, ctx);
|
|
4707
4712
|
if (tagName === "pre") {
|
|
@@ -4720,14 +4725,14 @@
|
|
|
4720
4725
|
const value = node.getAttribute(attr);
|
|
4721
4726
|
if (attr.startsWith("t-on")) {
|
|
4722
4727
|
if (attr === "t-on") {
|
|
4723
|
-
throw new
|
|
4728
|
+
throw new OwlError("Missing event name with t-on directive");
|
|
4724
4729
|
}
|
|
4725
4730
|
on = on || {};
|
|
4726
4731
|
on[attr.slice(5)] = value;
|
|
4727
4732
|
}
|
|
4728
4733
|
else if (attr.startsWith("t-model")) {
|
|
4729
4734
|
if (!["input", "select", "textarea"].includes(tagName)) {
|
|
4730
|
-
throw new
|
|
4735
|
+
throw new OwlError("The t-model directive only works with <input>, <textarea> and <select>");
|
|
4731
4736
|
}
|
|
4732
4737
|
let baseExpr, expr;
|
|
4733
4738
|
if (hasDotAtTheEnd.test(value)) {
|
|
@@ -4741,7 +4746,7 @@
|
|
|
4741
4746
|
expr = value.slice(index + 1, -1);
|
|
4742
4747
|
}
|
|
4743
4748
|
else {
|
|
4744
|
-
throw new
|
|
4749
|
+
throw new OwlError(`Invalid t-model expression: "${value}" (it should be assignable)`);
|
|
4745
4750
|
}
|
|
4746
4751
|
const typeAttr = node.getAttribute("type");
|
|
4747
4752
|
const isInput = tagName === "input";
|
|
@@ -4771,11 +4776,11 @@
|
|
|
4771
4776
|
}
|
|
4772
4777
|
}
|
|
4773
4778
|
else if (attr.startsWith("block-")) {
|
|
4774
|
-
throw new
|
|
4779
|
+
throw new OwlError(`Invalid attribute: '${attr}'`);
|
|
4775
4780
|
}
|
|
4776
4781
|
else if (attr !== "t-name") {
|
|
4777
4782
|
if (attr.startsWith("t-") && !attr.startsWith("t-att")) {
|
|
4778
|
-
throw new
|
|
4783
|
+
throw new OwlError(`Unknown QWeb directive: '${attr}'`);
|
|
4779
4784
|
}
|
|
4780
4785
|
const tModel = ctx.tModelInfo;
|
|
4781
4786
|
if (tModel && ["t-att-value", "t-attf-value"].includes(attr)) {
|
|
@@ -4826,7 +4831,7 @@
|
|
|
4826
4831
|
};
|
|
4827
4832
|
}
|
|
4828
4833
|
if (ast.type === 11 /* TComponent */) {
|
|
4829
|
-
throw new
|
|
4834
|
+
throw new OwlError("t-esc is not supported on Component nodes");
|
|
4830
4835
|
}
|
|
4831
4836
|
return tesc;
|
|
4832
4837
|
}
|
|
@@ -4874,7 +4879,7 @@
|
|
|
4874
4879
|
node.removeAttribute("t-as");
|
|
4875
4880
|
const key = node.getAttribute("t-key");
|
|
4876
4881
|
if (!key) {
|
|
4877
|
-
throw new
|
|
4882
|
+
throw new OwlError(`"Directive t-foreach should always be used with a t-key!" (expression: t-foreach="${collection}" t-as="${elem}")`);
|
|
4878
4883
|
}
|
|
4879
4884
|
node.removeAttribute("t-key");
|
|
4880
4885
|
const memo = node.getAttribute("t-memo") || "";
|
|
@@ -5034,7 +5039,7 @@
|
|
|
5034
5039
|
const firstLetter = name[0];
|
|
5035
5040
|
let isDynamic = node.hasAttribute("t-component");
|
|
5036
5041
|
if (isDynamic && name !== "t") {
|
|
5037
|
-
throw new
|
|
5042
|
+
throw new OwlError(`Directive 't-component' can only be used on <t> nodes (used on a <${name}>)`);
|
|
5038
5043
|
}
|
|
5039
5044
|
if (!(firstLetter === firstLetter.toUpperCase() || isDynamic)) {
|
|
5040
5045
|
return null;
|
|
@@ -5058,7 +5063,7 @@
|
|
|
5058
5063
|
}
|
|
5059
5064
|
else {
|
|
5060
5065
|
const message = directiveErrorMap.get(name.split("-").slice(0, 2).join("-"));
|
|
5061
|
-
throw new
|
|
5066
|
+
throw new OwlError(message || `unsupported directive on Component: ${name}`);
|
|
5062
5067
|
}
|
|
5063
5068
|
}
|
|
5064
5069
|
else {
|
|
@@ -5073,7 +5078,7 @@
|
|
|
5073
5078
|
const slotNodes = Array.from(clone.querySelectorAll("[t-set-slot]"));
|
|
5074
5079
|
for (let slotNode of slotNodes) {
|
|
5075
5080
|
if (slotNode.tagName !== "t") {
|
|
5076
|
-
throw new
|
|
5081
|
+
throw new OwlError(`Directive 't-set-slot' can only be used on <t> nodes (used on a <${slotNode.tagName}>)`);
|
|
5077
5082
|
}
|
|
5078
5083
|
const name = slotNode.getAttribute("t-set-slot");
|
|
5079
5084
|
// check if this is defined in a sub component (in which case it should
|
|
@@ -5238,25 +5243,25 @@
|
|
|
5238
5243
|
let nattr = (name) => +!!node.getAttribute(name);
|
|
5239
5244
|
if (prevElem && (pattr("t-if") || pattr("t-elif"))) {
|
|
5240
5245
|
if (pattr("t-foreach")) {
|
|
5241
|
-
throw new
|
|
5246
|
+
throw new OwlError("t-if cannot stay at the same level as t-foreach when using t-elif or t-else");
|
|
5242
5247
|
}
|
|
5243
5248
|
if (["t-if", "t-elif", "t-else"].map(nattr).reduce(function (a, b) {
|
|
5244
5249
|
return a + b;
|
|
5245
5250
|
}) > 1) {
|
|
5246
|
-
throw new
|
|
5251
|
+
throw new OwlError("Only one conditional branching directive is allowed per node");
|
|
5247
5252
|
}
|
|
5248
5253
|
// All text (with only spaces) and comment nodes (nodeType 8) between
|
|
5249
5254
|
// branch nodes are removed
|
|
5250
5255
|
let textNode;
|
|
5251
5256
|
while ((textNode = node.previousSibling) !== prevElem) {
|
|
5252
5257
|
if (textNode.nodeValue.trim().length && textNode.nodeType !== 8) {
|
|
5253
|
-
throw new
|
|
5258
|
+
throw new OwlError("text is not allowed between branching directives");
|
|
5254
5259
|
}
|
|
5255
5260
|
textNode.remove();
|
|
5256
5261
|
}
|
|
5257
5262
|
}
|
|
5258
5263
|
else {
|
|
5259
|
-
throw new
|
|
5264
|
+
throw new OwlError("t-elif and t-else directives must be preceded by a t-if or t-elif directive");
|
|
5260
5265
|
}
|
|
5261
5266
|
}
|
|
5262
5267
|
}
|
|
@@ -5272,7 +5277,7 @@
|
|
|
5272
5277
|
const elements = [...el.querySelectorAll("[t-esc]")].filter((el) => el.tagName[0] === el.tagName[0].toUpperCase() || el.hasAttribute("t-component"));
|
|
5273
5278
|
for (const el of elements) {
|
|
5274
5279
|
if (el.childNodes.length) {
|
|
5275
|
-
throw new
|
|
5280
|
+
throw new OwlError("Cannot have t-esc on a component that already has content");
|
|
5276
5281
|
}
|
|
5277
5282
|
const value = el.getAttribute("t-esc");
|
|
5278
5283
|
el.removeAttribute("t-esc");
|
|
@@ -5324,7 +5329,7 @@
|
|
|
5324
5329
|
}
|
|
5325
5330
|
}
|
|
5326
5331
|
}
|
|
5327
|
-
throw new
|
|
5332
|
+
throw new OwlError(msg);
|
|
5328
5333
|
}
|
|
5329
5334
|
return doc;
|
|
5330
5335
|
}
|
|
@@ -5378,7 +5383,7 @@
|
|
|
5378
5383
|
if (Object.hasOwnProperty.call(data, 0)) {
|
|
5379
5384
|
const handler = data[0];
|
|
5380
5385
|
if (typeof handler !== "function") {
|
|
5381
|
-
throw new
|
|
5386
|
+
throw new OwlError(`Invalid handler (expected a function, received: '${handler}')`);
|
|
5382
5387
|
}
|
|
5383
5388
|
let node = data[1] ? data[1].__owl__ : null;
|
|
5384
5389
|
if (node ? node.status === 1 /* MOUNTED */ : true) {
|
|
@@ -5562,10 +5567,10 @@ See https://github.com/odoo/owl/blob/${hash}/doc/reference/app.md#configuration
|
|
|
5562
5567
|
if (isStatic) {
|
|
5563
5568
|
C = parent.constructor.components[name];
|
|
5564
5569
|
if (!C) {
|
|
5565
|
-
throw new
|
|
5570
|
+
throw new OwlError(`Cannot find the definition of component "${name}"`);
|
|
5566
5571
|
}
|
|
5567
5572
|
else if (!(C.prototype instanceof Component)) {
|
|
5568
|
-
throw new
|
|
5573
|
+
throw new OwlError(`"${name}" is not a Component. It must inherit from the Component class`);
|
|
5569
5574
|
}
|
|
5570
5575
|
}
|
|
5571
5576
|
node = new ComponentNode(C, props, this, ctx, key);
|
|
@@ -5724,6 +5729,7 @@ See https://github.com/odoo/owl/blob/${hash}/doc/reference/app.md#configuration
|
|
|
5724
5729
|
exports.App = App;
|
|
5725
5730
|
exports.Component = Component;
|
|
5726
5731
|
exports.EventBus = EventBus;
|
|
5732
|
+
exports.OwlError = OwlError;
|
|
5727
5733
|
exports.__info__ = __info__;
|
|
5728
5734
|
exports.blockDom = blockDom;
|
|
5729
5735
|
exports.loadFile = loadFile;
|
|
@@ -5758,9 +5764,9 @@ See https://github.com/odoo/owl/blob/${hash}/doc/reference/app.md#configuration
|
|
|
5758
5764
|
Object.defineProperty(exports, '__esModule', { value: true });
|
|
5759
5765
|
|
|
5760
5766
|
|
|
5761
|
-
__info__.version = '2.0.0-beta-
|
|
5762
|
-
__info__.date = '2022-
|
|
5763
|
-
__info__.hash = '
|
|
5767
|
+
__info__.version = '2.0.0-beta-15';
|
|
5768
|
+
__info__.date = '2022-07-20T08:02:36.538Z';
|
|
5769
|
+
__info__.hash = '588b655';
|
|
5764
5770
|
__info__.url = 'https://github.com/odoo/owl';
|
|
5765
5771
|
|
|
5766
5772
|
|