@odoo/owl 2.0.0-beta-12 → 2.0.0-beta-16
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 +133 -121
- package/dist/owl.es.js +133 -122
- package/dist/owl.iife.js +133 -121
- package/dist/owl.iife.min.js +1 -1
- package/dist/types/compiler/code_generator.d.ts +1 -1
- 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.cjs.js
CHANGED
|
@@ -81,6 +81,68 @@ function toggler(key, child) {
|
|
|
81
81
|
return new VToggler(key, child);
|
|
82
82
|
}
|
|
83
83
|
|
|
84
|
+
// Custom error class that wraps error that happen in the owl lifecycle
|
|
85
|
+
class OwlError extends Error {
|
|
86
|
+
}
|
|
87
|
+
// Maps fibers to thrown errors
|
|
88
|
+
const fibersInError = new WeakMap();
|
|
89
|
+
const nodeErrorHandlers = new WeakMap();
|
|
90
|
+
function _handleError(node, error) {
|
|
91
|
+
if (!node) {
|
|
92
|
+
return false;
|
|
93
|
+
}
|
|
94
|
+
const fiber = node.fiber;
|
|
95
|
+
if (fiber) {
|
|
96
|
+
fibersInError.set(fiber, error);
|
|
97
|
+
}
|
|
98
|
+
const errorHandlers = nodeErrorHandlers.get(node);
|
|
99
|
+
if (errorHandlers) {
|
|
100
|
+
let handled = false;
|
|
101
|
+
// execute in the opposite order
|
|
102
|
+
for (let i = errorHandlers.length - 1; i >= 0; i--) {
|
|
103
|
+
try {
|
|
104
|
+
errorHandlers[i](error);
|
|
105
|
+
handled = true;
|
|
106
|
+
break;
|
|
107
|
+
}
|
|
108
|
+
catch (e) {
|
|
109
|
+
error = e;
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
if (handled) {
|
|
113
|
+
return true;
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
return _handleError(node.parent, error);
|
|
117
|
+
}
|
|
118
|
+
function handleError(params) {
|
|
119
|
+
let { error } = params;
|
|
120
|
+
// Wrap error if it wasn't wrapped by wrapError (ie when not in dev mode)
|
|
121
|
+
if (!(error instanceof OwlError)) {
|
|
122
|
+
error = Object.assign(new OwlError(`An error occured in the owl lifecycle (see this Error's "cause" property)`), { cause: error });
|
|
123
|
+
}
|
|
124
|
+
const node = "node" in params ? params.node : params.fiber.node;
|
|
125
|
+
const fiber = "fiber" in params ? params.fiber : node.fiber;
|
|
126
|
+
// resets the fibers on components if possible. This is important so that
|
|
127
|
+
// new renderings can be properly included in the initial one, if any.
|
|
128
|
+
let current = fiber;
|
|
129
|
+
do {
|
|
130
|
+
current.node.fiber = current;
|
|
131
|
+
current = current.parent;
|
|
132
|
+
} while (current);
|
|
133
|
+
fibersInError.set(fiber.root, error);
|
|
134
|
+
const handled = _handleError(node, error);
|
|
135
|
+
if (!handled) {
|
|
136
|
+
console.warn(`[Owl] Unhandled error. Destroying the root component`);
|
|
137
|
+
try {
|
|
138
|
+
node.app.destroy();
|
|
139
|
+
}
|
|
140
|
+
catch (e) {
|
|
141
|
+
console.error(e);
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
|
|
84
146
|
const { setAttribute: elemSetAttribute, removeAttribute } = Element.prototype;
|
|
85
147
|
const tokenList = DOMTokenList.prototype;
|
|
86
148
|
const tokenListAdd = tokenList.add;
|
|
@@ -218,7 +280,7 @@ function updateClass(val, oldVal) {
|
|
|
218
280
|
function makePropSetter(name) {
|
|
219
281
|
return function setProp(value) {
|
|
220
282
|
// support 0, fallback to empty string for other falsy values
|
|
221
|
-
this[name] = value === 0 ? 0 : value
|
|
283
|
+
this[name] = value === 0 ? 0 : value ? value.valueOf() : "";
|
|
222
284
|
};
|
|
223
285
|
}
|
|
224
286
|
function isProp(tag, key) {
|
|
@@ -702,7 +764,7 @@ function buildTree(node, parent = null, domParentTree = null) {
|
|
|
702
764
|
};
|
|
703
765
|
}
|
|
704
766
|
}
|
|
705
|
-
throw new
|
|
767
|
+
throw new OwlError("boom");
|
|
706
768
|
}
|
|
707
769
|
function addRef(tree) {
|
|
708
770
|
tree.isRef = true;
|
|
@@ -1386,61 +1448,6 @@ function remove(vnode, withBeforeRemove = false) {
|
|
|
1386
1448
|
vnode.remove();
|
|
1387
1449
|
}
|
|
1388
1450
|
|
|
1389
|
-
// Maps fibers to thrown errors
|
|
1390
|
-
const fibersInError = new WeakMap();
|
|
1391
|
-
const nodeErrorHandlers = new WeakMap();
|
|
1392
|
-
function _handleError(node, error) {
|
|
1393
|
-
if (!node) {
|
|
1394
|
-
return false;
|
|
1395
|
-
}
|
|
1396
|
-
const fiber = node.fiber;
|
|
1397
|
-
if (fiber) {
|
|
1398
|
-
fibersInError.set(fiber, error);
|
|
1399
|
-
}
|
|
1400
|
-
const errorHandlers = nodeErrorHandlers.get(node);
|
|
1401
|
-
if (errorHandlers) {
|
|
1402
|
-
let handled = false;
|
|
1403
|
-
// execute in the opposite order
|
|
1404
|
-
for (let i = errorHandlers.length - 1; i >= 0; i--) {
|
|
1405
|
-
try {
|
|
1406
|
-
errorHandlers[i](error);
|
|
1407
|
-
handled = true;
|
|
1408
|
-
break;
|
|
1409
|
-
}
|
|
1410
|
-
catch (e) {
|
|
1411
|
-
error = e;
|
|
1412
|
-
}
|
|
1413
|
-
}
|
|
1414
|
-
if (handled) {
|
|
1415
|
-
return true;
|
|
1416
|
-
}
|
|
1417
|
-
}
|
|
1418
|
-
return _handleError(node.parent, error);
|
|
1419
|
-
}
|
|
1420
|
-
function handleError(params) {
|
|
1421
|
-
const error = params.error;
|
|
1422
|
-
const node = "node" in params ? params.node : params.fiber.node;
|
|
1423
|
-
const fiber = "fiber" in params ? params.fiber : node.fiber;
|
|
1424
|
-
// resets the fibers on components if possible. This is important so that
|
|
1425
|
-
// new renderings can be properly included in the initial one, if any.
|
|
1426
|
-
let current = fiber;
|
|
1427
|
-
do {
|
|
1428
|
-
current.node.fiber = current;
|
|
1429
|
-
current = current.parent;
|
|
1430
|
-
} while (current);
|
|
1431
|
-
fibersInError.set(fiber.root, error);
|
|
1432
|
-
const handled = _handleError(node, error);
|
|
1433
|
-
if (!handled) {
|
|
1434
|
-
console.warn(`[Owl] Unhandled error. Destroying the root component`);
|
|
1435
|
-
try {
|
|
1436
|
-
node.app.destroy();
|
|
1437
|
-
}
|
|
1438
|
-
catch (e) {
|
|
1439
|
-
console.error(e);
|
|
1440
|
-
}
|
|
1441
|
-
}
|
|
1442
|
-
}
|
|
1443
|
-
|
|
1444
1451
|
function makeChildFiber(node, parent) {
|
|
1445
1452
|
let current = node.fiber;
|
|
1446
1453
|
if (current) {
|
|
@@ -1479,7 +1486,7 @@ function makeRootFiber(node) {
|
|
|
1479
1486
|
return fiber;
|
|
1480
1487
|
}
|
|
1481
1488
|
function throwOnRender() {
|
|
1482
|
-
throw new
|
|
1489
|
+
throw new OwlError("Attempted to render cancelled fiber");
|
|
1483
1490
|
}
|
|
1484
1491
|
/**
|
|
1485
1492
|
* @returns number of not-yet rendered fibers cancelled
|
|
@@ -1856,7 +1863,7 @@ const reactiveCache = new WeakMap();
|
|
|
1856
1863
|
*/
|
|
1857
1864
|
function reactive(target, callback = () => { }) {
|
|
1858
1865
|
if (!canBeMadeReactive(target)) {
|
|
1859
|
-
throw new
|
|
1866
|
+
throw new OwlError(`Cannot make the given value reactive`);
|
|
1860
1867
|
}
|
|
1861
1868
|
if (SKIP in target) {
|
|
1862
1869
|
return target;
|
|
@@ -2125,10 +2132,10 @@ function batched(callback) {
|
|
|
2125
2132
|
}
|
|
2126
2133
|
function validateTarget(target) {
|
|
2127
2134
|
if (!(target instanceof HTMLElement)) {
|
|
2128
|
-
throw new
|
|
2135
|
+
throw new OwlError("Cannot mount component: the target is not a valid DOM element");
|
|
2129
2136
|
}
|
|
2130
2137
|
if (!document.body.contains(target)) {
|
|
2131
|
-
throw new
|
|
2138
|
+
throw new OwlError("Cannot mount a component on a detached dom node");
|
|
2132
2139
|
}
|
|
2133
2140
|
}
|
|
2134
2141
|
class EventBus extends EventTarget {
|
|
@@ -2149,7 +2156,7 @@ function whenReady(fn) {
|
|
|
2149
2156
|
async function loadFile(url) {
|
|
2150
2157
|
const result = await fetch(url);
|
|
2151
2158
|
if (!result.ok) {
|
|
2152
|
-
throw new
|
|
2159
|
+
throw new OwlError("Error while fetching xml templates");
|
|
2153
2160
|
}
|
|
2154
2161
|
return await result.text();
|
|
2155
2162
|
}
|
|
@@ -2171,7 +2178,7 @@ function markup(value) {
|
|
|
2171
2178
|
let currentNode = null;
|
|
2172
2179
|
function getCurrent() {
|
|
2173
2180
|
if (!currentNode) {
|
|
2174
|
-
throw new
|
|
2181
|
+
throw new OwlError("No active component (a hook function should only be called in 'setup')");
|
|
2175
2182
|
}
|
|
2176
2183
|
return currentNode;
|
|
2177
2184
|
}
|
|
@@ -2233,7 +2240,6 @@ class ComponentNode {
|
|
|
2233
2240
|
this.parent = parent;
|
|
2234
2241
|
this.props = props;
|
|
2235
2242
|
this.parentKey = parentKey;
|
|
2236
|
-
this.level = parent ? parent.level + 1 : 0;
|
|
2237
2243
|
const defaultProps = C.defaultProps;
|
|
2238
2244
|
props = Object.assign({}, props);
|
|
2239
2245
|
if (defaultProps) {
|
|
@@ -2466,17 +2472,27 @@ class ComponentNode {
|
|
|
2466
2472
|
|
|
2467
2473
|
const TIMEOUT = Symbol("timeout");
|
|
2468
2474
|
function wrapError(fn, hookName) {
|
|
2469
|
-
const error = new
|
|
2470
|
-
const timeoutError = new
|
|
2475
|
+
const error = new OwlError(`The following error occurred in ${hookName}: `);
|
|
2476
|
+
const timeoutError = new OwlError(`${hookName}'s promise hasn't resolved after 3 seconds`);
|
|
2471
2477
|
const node = getCurrent();
|
|
2472
2478
|
return (...args) => {
|
|
2479
|
+
const onError = (cause) => {
|
|
2480
|
+
error.cause = cause;
|
|
2481
|
+
if (cause instanceof Error) {
|
|
2482
|
+
error.message += `"${cause.message}"`;
|
|
2483
|
+
}
|
|
2484
|
+
else {
|
|
2485
|
+
error.message = `Something that is not an Error was thrown in ${hookName} (see this Error's "cause" property)`;
|
|
2486
|
+
}
|
|
2487
|
+
throw error;
|
|
2488
|
+
};
|
|
2473
2489
|
try {
|
|
2474
2490
|
const result = fn(...args);
|
|
2475
2491
|
if (result instanceof Promise) {
|
|
2476
2492
|
if (hookName === "onWillStart" || hookName === "onWillUpdateProps") {
|
|
2477
2493
|
const fiber = node.fiber;
|
|
2478
2494
|
Promise.race([
|
|
2479
|
-
result,
|
|
2495
|
+
result.catch(() => { }),
|
|
2480
2496
|
new Promise((resolve) => setTimeout(() => resolve(TIMEOUT), 3000)),
|
|
2481
2497
|
]).then((res) => {
|
|
2482
2498
|
if (res === TIMEOUT && node.fiber === fiber) {
|
|
@@ -2484,21 +2500,12 @@ function wrapError(fn, hookName) {
|
|
|
2484
2500
|
}
|
|
2485
2501
|
});
|
|
2486
2502
|
}
|
|
2487
|
-
return result.catch(
|
|
2488
|
-
error.cause = cause;
|
|
2489
|
-
if (cause instanceof Error) {
|
|
2490
|
-
error.message += `"${cause.message}"`;
|
|
2491
|
-
}
|
|
2492
|
-
throw error;
|
|
2493
|
-
});
|
|
2503
|
+
return result.catch(onError);
|
|
2494
2504
|
}
|
|
2495
2505
|
return result;
|
|
2496
2506
|
}
|
|
2497
2507
|
catch (cause) {
|
|
2498
|
-
|
|
2499
|
-
error.message += `"${cause.message}"`;
|
|
2500
|
-
}
|
|
2501
|
-
throw error;
|
|
2508
|
+
onError(cause);
|
|
2502
2509
|
}
|
|
2503
2510
|
};
|
|
2504
2511
|
}
|
|
@@ -2602,7 +2609,7 @@ class VPortal extends VText {
|
|
|
2602
2609
|
}
|
|
2603
2610
|
this.target = el && el.querySelector(this.selector);
|
|
2604
2611
|
if (!this.target) {
|
|
2605
|
-
throw new
|
|
2612
|
+
throw new OwlError("invalid portal target");
|
|
2606
2613
|
}
|
|
2607
2614
|
}
|
|
2608
2615
|
this.realBDom.mount(this.target, null);
|
|
@@ -2696,7 +2703,7 @@ function toSchema(spec) {
|
|
|
2696
2703
|
function validate(obj, spec) {
|
|
2697
2704
|
let errors = validateSchema(obj, spec);
|
|
2698
2705
|
if (errors.length) {
|
|
2699
|
-
throw new
|
|
2706
|
+
throw new OwlError("Invalid object: " + errors.join(", "));
|
|
2700
2707
|
}
|
|
2701
2708
|
}
|
|
2702
2709
|
/**
|
|
@@ -2849,7 +2856,7 @@ function prepareList(collection) {
|
|
|
2849
2856
|
keys = Object.values(collection);
|
|
2850
2857
|
}
|
|
2851
2858
|
else {
|
|
2852
|
-
throw new
|
|
2859
|
+
throw new OwlError("Invalid loop expression");
|
|
2853
2860
|
}
|
|
2854
2861
|
const n = values.length;
|
|
2855
2862
|
return [keys, values, n, new Array(n)];
|
|
@@ -2955,7 +2962,7 @@ function multiRefSetter(refs, name) {
|
|
|
2955
2962
|
if (el) {
|
|
2956
2963
|
count++;
|
|
2957
2964
|
if (count > 1) {
|
|
2958
|
-
throw new
|
|
2965
|
+
throw new OwlError("Cannot have 2 elements with same ref name at the same time");
|
|
2959
2966
|
}
|
|
2960
2967
|
}
|
|
2961
2968
|
if (count === 0 || el) {
|
|
@@ -2992,13 +2999,13 @@ function validateProps(name, props, parent) {
|
|
|
2992
2999
|
: name in schema && !("*" in schema) && !isOptional(schema[name]);
|
|
2993
3000
|
for (let p in defaultProps) {
|
|
2994
3001
|
if (isMandatory(p)) {
|
|
2995
|
-
throw new
|
|
3002
|
+
throw new OwlError(`A default value cannot be defined for a mandatory prop (name: '${p}', component: ${ComponentClass.name})`);
|
|
2996
3003
|
}
|
|
2997
3004
|
}
|
|
2998
3005
|
}
|
|
2999
3006
|
const errors = validateSchema(props, schema);
|
|
3000
3007
|
if (errors.length) {
|
|
3001
|
-
throw new
|
|
3008
|
+
throw new OwlError(`Invalid props for component '${ComponentClass.name}': ` + errors.join(", "));
|
|
3002
3009
|
}
|
|
3003
3010
|
}
|
|
3004
3011
|
const helpers = {
|
|
@@ -3019,6 +3026,7 @@ const helpers = {
|
|
|
3019
3026
|
bind,
|
|
3020
3027
|
createCatcher,
|
|
3021
3028
|
markRaw,
|
|
3029
|
+
OwlError,
|
|
3022
3030
|
};
|
|
3023
3031
|
|
|
3024
3032
|
const bdom = { text, createBlock, list, multi, html, toggler, comment };
|
|
@@ -3046,7 +3054,7 @@ function parseXML$1(xml) {
|
|
|
3046
3054
|
}
|
|
3047
3055
|
}
|
|
3048
3056
|
}
|
|
3049
|
-
throw new
|
|
3057
|
+
throw new OwlError(msg);
|
|
3050
3058
|
}
|
|
3051
3059
|
return doc;
|
|
3052
3060
|
}
|
|
@@ -3077,7 +3085,7 @@ class TemplateSet {
|
|
|
3077
3085
|
if (currentAsString === newAsString) {
|
|
3078
3086
|
return;
|
|
3079
3087
|
}
|
|
3080
|
-
throw new
|
|
3088
|
+
throw new OwlError(`Template ${name} already defined with different content`);
|
|
3081
3089
|
}
|
|
3082
3090
|
this.rawTemplates[name] = template;
|
|
3083
3091
|
}
|
|
@@ -3102,7 +3110,7 @@ class TemplateSet {
|
|
|
3102
3110
|
extraInfo = ` (for component "${componentName}")`;
|
|
3103
3111
|
}
|
|
3104
3112
|
catch { }
|
|
3105
|
-
throw new
|
|
3113
|
+
throw new OwlError(`Missing template: "${name}"${extraInfo}`);
|
|
3106
3114
|
}
|
|
3107
3115
|
const isFn = typeof rawTemplate === "function" && !(rawTemplate instanceof Element);
|
|
3108
3116
|
const templateFn = isFn ? rawTemplate : this._compileTemplate(name, rawTemplate);
|
|
@@ -3118,7 +3126,7 @@ class TemplateSet {
|
|
|
3118
3126
|
return this.templates[name];
|
|
3119
3127
|
}
|
|
3120
3128
|
_compileTemplate(name, template) {
|
|
3121
|
-
throw new
|
|
3129
|
+
throw new OwlError(`Unable to compile a template. Please use owl full build instead`);
|
|
3122
3130
|
}
|
|
3123
3131
|
callTemplate(owner, subTemplate, ctx, parent, key) {
|
|
3124
3132
|
const template = this.getTemplate(subTemplate);
|
|
@@ -3200,14 +3208,14 @@ let tokenizeString = function (expr) {
|
|
|
3200
3208
|
i++;
|
|
3201
3209
|
cur = expr[i];
|
|
3202
3210
|
if (!cur) {
|
|
3203
|
-
throw new
|
|
3211
|
+
throw new OwlError("Invalid expression");
|
|
3204
3212
|
}
|
|
3205
3213
|
s += cur;
|
|
3206
3214
|
}
|
|
3207
3215
|
i++;
|
|
3208
3216
|
}
|
|
3209
3217
|
if (expr[i] !== start) {
|
|
3210
|
-
throw new
|
|
3218
|
+
throw new OwlError("Invalid expression");
|
|
3211
3219
|
}
|
|
3212
3220
|
s += start;
|
|
3213
3221
|
if (start === "`") {
|
|
@@ -3314,7 +3322,7 @@ function tokenize(expr) {
|
|
|
3314
3322
|
error = e; // Silence all errors and throw a generic error below
|
|
3315
3323
|
}
|
|
3316
3324
|
if (current.length || error) {
|
|
3317
|
-
throw new
|
|
3325
|
+
throw new OwlError(`Tokenizer error: could not tokenize \`${expr}\``);
|
|
3318
3326
|
}
|
|
3319
3327
|
return result;
|
|
3320
3328
|
}
|
|
@@ -3865,7 +3873,7 @@ class CodeGenerator {
|
|
|
3865
3873
|
.slice(1)
|
|
3866
3874
|
.map((m) => {
|
|
3867
3875
|
if (!MODS.has(m)) {
|
|
3868
|
-
throw new
|
|
3876
|
+
throw new OwlError(`Unknown event modifier: '${m}'`);
|
|
3869
3877
|
}
|
|
3870
3878
|
return `"${m}"`;
|
|
3871
3879
|
});
|
|
@@ -3907,13 +3915,18 @@ class CodeGenerator {
|
|
|
3907
3915
|
attrs["block-attribute-" + idx] = attrName;
|
|
3908
3916
|
}
|
|
3909
3917
|
else if (key.startsWith("t-att")) {
|
|
3918
|
+
attrName = key === "t-att" ? null : key.slice(6);
|
|
3910
3919
|
expr = compileExpr(ast.attrs[key]);
|
|
3920
|
+
if (attrName && isProp(ast.tag, attrName)) {
|
|
3921
|
+
// we force a new string or new boolean to bypass the equality check in blockdom when patching same value
|
|
3922
|
+
const C = attrName === "value" ? "String" : "Boolean";
|
|
3923
|
+
expr = `new ${C}(${expr})`;
|
|
3924
|
+
}
|
|
3911
3925
|
const idx = block.insertData(expr, "attr");
|
|
3912
3926
|
if (key === "t-att") {
|
|
3913
3927
|
attrs[`block-attributes`] = String(idx);
|
|
3914
3928
|
}
|
|
3915
3929
|
else {
|
|
3916
|
-
attrName = key.slice(6);
|
|
3917
3930
|
attrs[`block-attribute-${idx}`] = attrName;
|
|
3918
3931
|
}
|
|
3919
3932
|
}
|
|
@@ -4181,7 +4194,8 @@ class CodeGenerator {
|
|
|
4181
4194
|
this.define(`key${this.target.loopLevel}`, ast.key ? compileExpr(ast.key) : loopVar);
|
|
4182
4195
|
if (this.dev) {
|
|
4183
4196
|
// Throw error on duplicate keys in dev mode
|
|
4184
|
-
this.
|
|
4197
|
+
this.helpers.add("OwlError");
|
|
4198
|
+
this.addLine(`if (keys${block.id}.has(key${this.target.loopLevel})) { throw new OwlError(\`Got duplicate key in t-foreach: \${key${this.target.loopLevel}}\`)}`);
|
|
4185
4199
|
this.addLine(`keys${block.id}.add(key${this.target.loopLevel});`);
|
|
4186
4200
|
}
|
|
4187
4201
|
let id;
|
|
@@ -4395,7 +4409,7 @@ class CodeGenerator {
|
|
|
4395
4409
|
value = `bind(ctx, ${value || undefined})`;
|
|
4396
4410
|
}
|
|
4397
4411
|
else {
|
|
4398
|
-
throw new
|
|
4412
|
+
throw new OwlError("Invalid prop suffix");
|
|
4399
4413
|
}
|
|
4400
4414
|
}
|
|
4401
4415
|
name = /^[a-z_]+$/i.test(name) ? name : `'${name}'`;
|
|
@@ -4588,9 +4602,6 @@ class CodeGenerator {
|
|
|
4588
4602
|
}
|
|
4589
4603
|
}
|
|
4590
4604
|
|
|
4591
|
-
// -----------------------------------------------------------------------------
|
|
4592
|
-
// AST Type definition
|
|
4593
|
-
// -----------------------------------------------------------------------------
|
|
4594
4605
|
// -----------------------------------------------------------------------------
|
|
4595
4606
|
// Parser
|
|
4596
4607
|
// -----------------------------------------------------------------------------
|
|
@@ -4699,7 +4710,7 @@ function parseDOMNode(node, ctx) {
|
|
|
4699
4710
|
return null;
|
|
4700
4711
|
}
|
|
4701
4712
|
if (tagName.startsWith("block-")) {
|
|
4702
|
-
throw new
|
|
4713
|
+
throw new OwlError(`Invalid tag name: '${tagName}'`);
|
|
4703
4714
|
}
|
|
4704
4715
|
ctx = Object.assign({}, ctx);
|
|
4705
4716
|
if (tagName === "pre") {
|
|
@@ -4718,14 +4729,14 @@ function parseDOMNode(node, ctx) {
|
|
|
4718
4729
|
const value = node.getAttribute(attr);
|
|
4719
4730
|
if (attr.startsWith("t-on")) {
|
|
4720
4731
|
if (attr === "t-on") {
|
|
4721
|
-
throw new
|
|
4732
|
+
throw new OwlError("Missing event name with t-on directive");
|
|
4722
4733
|
}
|
|
4723
4734
|
on = on || {};
|
|
4724
4735
|
on[attr.slice(5)] = value;
|
|
4725
4736
|
}
|
|
4726
4737
|
else if (attr.startsWith("t-model")) {
|
|
4727
4738
|
if (!["input", "select", "textarea"].includes(tagName)) {
|
|
4728
|
-
throw new
|
|
4739
|
+
throw new OwlError("The t-model directive only works with <input>, <textarea> and <select>");
|
|
4729
4740
|
}
|
|
4730
4741
|
let baseExpr, expr;
|
|
4731
4742
|
if (hasDotAtTheEnd.test(value)) {
|
|
@@ -4739,7 +4750,7 @@ function parseDOMNode(node, ctx) {
|
|
|
4739
4750
|
expr = value.slice(index + 1, -1);
|
|
4740
4751
|
}
|
|
4741
4752
|
else {
|
|
4742
|
-
throw new
|
|
4753
|
+
throw new OwlError(`Invalid t-model expression: "${value}" (it should be assignable)`);
|
|
4743
4754
|
}
|
|
4744
4755
|
const typeAttr = node.getAttribute("type");
|
|
4745
4756
|
const isInput = tagName === "input";
|
|
@@ -4769,11 +4780,11 @@ function parseDOMNode(node, ctx) {
|
|
|
4769
4780
|
}
|
|
4770
4781
|
}
|
|
4771
4782
|
else if (attr.startsWith("block-")) {
|
|
4772
|
-
throw new
|
|
4783
|
+
throw new OwlError(`Invalid attribute: '${attr}'`);
|
|
4773
4784
|
}
|
|
4774
4785
|
else if (attr !== "t-name") {
|
|
4775
4786
|
if (attr.startsWith("t-") && !attr.startsWith("t-att")) {
|
|
4776
|
-
throw new
|
|
4787
|
+
throw new OwlError(`Unknown QWeb directive: '${attr}'`);
|
|
4777
4788
|
}
|
|
4778
4789
|
const tModel = ctx.tModelInfo;
|
|
4779
4790
|
if (tModel && ["t-att-value", "t-attf-value"].includes(attr)) {
|
|
@@ -4824,7 +4835,7 @@ function parseTEscNode(node, ctx) {
|
|
|
4824
4835
|
};
|
|
4825
4836
|
}
|
|
4826
4837
|
if (ast.type === 11 /* TComponent */) {
|
|
4827
|
-
throw new
|
|
4838
|
+
throw new OwlError("t-esc is not supported on Component nodes");
|
|
4828
4839
|
}
|
|
4829
4840
|
return tesc;
|
|
4830
4841
|
}
|
|
@@ -4872,7 +4883,7 @@ function parseTForEach(node, ctx) {
|
|
|
4872
4883
|
node.removeAttribute("t-as");
|
|
4873
4884
|
const key = node.getAttribute("t-key");
|
|
4874
4885
|
if (!key) {
|
|
4875
|
-
throw new
|
|
4886
|
+
throw new OwlError(`"Directive t-foreach should always be used with a t-key!" (expression: t-foreach="${collection}" t-as="${elem}")`);
|
|
4876
4887
|
}
|
|
4877
4888
|
node.removeAttribute("t-key");
|
|
4878
4889
|
const memo = node.getAttribute("t-memo") || "";
|
|
@@ -5032,7 +5043,7 @@ function parseComponent(node, ctx) {
|
|
|
5032
5043
|
const firstLetter = name[0];
|
|
5033
5044
|
let isDynamic = node.hasAttribute("t-component");
|
|
5034
5045
|
if (isDynamic && name !== "t") {
|
|
5035
|
-
throw new
|
|
5046
|
+
throw new OwlError(`Directive 't-component' can only be used on <t> nodes (used on a <${name}>)`);
|
|
5036
5047
|
}
|
|
5037
5048
|
if (!(firstLetter === firstLetter.toUpperCase() || isDynamic)) {
|
|
5038
5049
|
return null;
|
|
@@ -5056,7 +5067,7 @@ function parseComponent(node, ctx) {
|
|
|
5056
5067
|
}
|
|
5057
5068
|
else {
|
|
5058
5069
|
const message = directiveErrorMap.get(name.split("-").slice(0, 2).join("-"));
|
|
5059
|
-
throw new
|
|
5070
|
+
throw new OwlError(message || `unsupported directive on Component: ${name}`);
|
|
5060
5071
|
}
|
|
5061
5072
|
}
|
|
5062
5073
|
else {
|
|
@@ -5071,7 +5082,7 @@ function parseComponent(node, ctx) {
|
|
|
5071
5082
|
const slotNodes = Array.from(clone.querySelectorAll("[t-set-slot]"));
|
|
5072
5083
|
for (let slotNode of slotNodes) {
|
|
5073
5084
|
if (slotNode.tagName !== "t") {
|
|
5074
|
-
throw new
|
|
5085
|
+
throw new OwlError(`Directive 't-set-slot' can only be used on <t> nodes (used on a <${slotNode.tagName}>)`);
|
|
5075
5086
|
}
|
|
5076
5087
|
const name = slotNode.getAttribute("t-set-slot");
|
|
5077
5088
|
// check if this is defined in a sub component (in which case it should
|
|
@@ -5236,25 +5247,25 @@ function normalizeTIf(el) {
|
|
|
5236
5247
|
let nattr = (name) => +!!node.getAttribute(name);
|
|
5237
5248
|
if (prevElem && (pattr("t-if") || pattr("t-elif"))) {
|
|
5238
5249
|
if (pattr("t-foreach")) {
|
|
5239
|
-
throw new
|
|
5250
|
+
throw new OwlError("t-if cannot stay at the same level as t-foreach when using t-elif or t-else");
|
|
5240
5251
|
}
|
|
5241
5252
|
if (["t-if", "t-elif", "t-else"].map(nattr).reduce(function (a, b) {
|
|
5242
5253
|
return a + b;
|
|
5243
5254
|
}) > 1) {
|
|
5244
|
-
throw new
|
|
5255
|
+
throw new OwlError("Only one conditional branching directive is allowed per node");
|
|
5245
5256
|
}
|
|
5246
5257
|
// All text (with only spaces) and comment nodes (nodeType 8) between
|
|
5247
5258
|
// branch nodes are removed
|
|
5248
5259
|
let textNode;
|
|
5249
5260
|
while ((textNode = node.previousSibling) !== prevElem) {
|
|
5250
5261
|
if (textNode.nodeValue.trim().length && textNode.nodeType !== 8) {
|
|
5251
|
-
throw new
|
|
5262
|
+
throw new OwlError("text is not allowed between branching directives");
|
|
5252
5263
|
}
|
|
5253
5264
|
textNode.remove();
|
|
5254
5265
|
}
|
|
5255
5266
|
}
|
|
5256
5267
|
else {
|
|
5257
|
-
throw new
|
|
5268
|
+
throw new OwlError("t-elif and t-else directives must be preceded by a t-if or t-elif directive");
|
|
5258
5269
|
}
|
|
5259
5270
|
}
|
|
5260
5271
|
}
|
|
@@ -5270,7 +5281,7 @@ function normalizeTEsc(el) {
|
|
|
5270
5281
|
const elements = [...el.querySelectorAll("[t-esc]")].filter((el) => el.tagName[0] === el.tagName[0].toUpperCase() || el.hasAttribute("t-component"));
|
|
5271
5282
|
for (const el of elements) {
|
|
5272
5283
|
if (el.childNodes.length) {
|
|
5273
|
-
throw new
|
|
5284
|
+
throw new OwlError("Cannot have t-esc on a component that already has content");
|
|
5274
5285
|
}
|
|
5275
5286
|
const value = el.getAttribute("t-esc");
|
|
5276
5287
|
el.removeAttribute("t-esc");
|
|
@@ -5322,7 +5333,7 @@ function parseXML(xml) {
|
|
|
5322
5333
|
}
|
|
5323
5334
|
}
|
|
5324
5335
|
}
|
|
5325
|
-
throw new
|
|
5336
|
+
throw new OwlError(msg);
|
|
5326
5337
|
}
|
|
5327
5338
|
return doc;
|
|
5328
5339
|
}
|
|
@@ -5376,7 +5387,7 @@ const mainEventHandler = (data, ev, currentTarget) => {
|
|
|
5376
5387
|
if (Object.hasOwnProperty.call(data, 0)) {
|
|
5377
5388
|
const handler = data[0];
|
|
5378
5389
|
if (typeof handler !== "function") {
|
|
5379
|
-
throw new
|
|
5390
|
+
throw new OwlError(`Invalid handler (expected a function, received: '${handler}')`);
|
|
5380
5391
|
}
|
|
5381
5392
|
let node = data[1] ? data[1].__owl__ : null;
|
|
5382
5393
|
if (node ? node.status === 1 /* MOUNTED */ : true) {
|
|
@@ -5560,10 +5571,10 @@ class App extends TemplateSet {
|
|
|
5560
5571
|
if (isStatic) {
|
|
5561
5572
|
C = parent.constructor.components[name];
|
|
5562
5573
|
if (!C) {
|
|
5563
|
-
throw new
|
|
5574
|
+
throw new OwlError(`Cannot find the definition of component "${name}"`);
|
|
5564
5575
|
}
|
|
5565
5576
|
else if (!(C.prototype instanceof Component)) {
|
|
5566
|
-
throw new
|
|
5577
|
+
throw new OwlError(`"${name}" is not a Component. It must inherit from the Component class`);
|
|
5567
5578
|
}
|
|
5568
5579
|
}
|
|
5569
5580
|
node = new ComponentNode(C, props, this, ctx, key);
|
|
@@ -5722,6 +5733,7 @@ TemplateSet.prototype._compileTemplate = function _compileTemplate(name, templat
|
|
|
5722
5733
|
exports.App = App;
|
|
5723
5734
|
exports.Component = Component;
|
|
5724
5735
|
exports.EventBus = EventBus;
|
|
5736
|
+
exports.OwlError = OwlError;
|
|
5725
5737
|
exports.__info__ = __info__;
|
|
5726
5738
|
exports.blockDom = blockDom;
|
|
5727
5739
|
exports.loadFile = loadFile;
|
|
@@ -5754,7 +5766,7 @@ exports.whenReady = whenReady;
|
|
|
5754
5766
|
exports.xml = xml;
|
|
5755
5767
|
|
|
5756
5768
|
|
|
5757
|
-
__info__.version = '2.0.0-beta-
|
|
5758
|
-
__info__.date = '2022-
|
|
5759
|
-
__info__.hash = '
|
|
5769
|
+
__info__.version = '2.0.0-beta-16';
|
|
5770
|
+
__info__.date = '2022-07-22T07:43:54.584Z';
|
|
5771
|
+
__info__.hash = 'b90aa0e';
|
|
5760
5772
|
__info__.url = 'https://github.com/odoo/owl';
|