@odoo/owl 2.0.0-beta-14 → 2.0.0-beta-17
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 +142 -124
- package/dist/owl.es.js +142 -125
- package/dist/owl.iife.js +142 -124
- package/dist/owl.iife.min.js +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 +2 -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;
|
|
@@ -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;
|
|
@@ -2124,12 +2131,18 @@ function batched(callback) {
|
|
|
2124
2131
|
};
|
|
2125
2132
|
}
|
|
2126
2133
|
function validateTarget(target) {
|
|
2127
|
-
|
|
2128
|
-
|
|
2129
|
-
|
|
2130
|
-
|
|
2131
|
-
|
|
2134
|
+
// Get the document and HTMLElement corresponding to the target to allow mounting in iframes
|
|
2135
|
+
const document = target && target.ownerDocument;
|
|
2136
|
+
if (document) {
|
|
2137
|
+
const HTMLElement = document.defaultView.HTMLElement;
|
|
2138
|
+
if (target instanceof HTMLElement) {
|
|
2139
|
+
if (!document.body.contains(target)) {
|
|
2140
|
+
throw new OwlError("Cannot mount a component on a detached dom node");
|
|
2141
|
+
}
|
|
2142
|
+
return;
|
|
2143
|
+
}
|
|
2132
2144
|
}
|
|
2145
|
+
throw new OwlError("Cannot mount component: the target is not a valid DOM element");
|
|
2133
2146
|
}
|
|
2134
2147
|
class EventBus extends EventTarget {
|
|
2135
2148
|
trigger(name, payload) {
|
|
@@ -2149,7 +2162,7 @@ function whenReady(fn) {
|
|
|
2149
2162
|
async function loadFile(url) {
|
|
2150
2163
|
const result = await fetch(url);
|
|
2151
2164
|
if (!result.ok) {
|
|
2152
|
-
throw new
|
|
2165
|
+
throw new OwlError("Error while fetching xml templates");
|
|
2153
2166
|
}
|
|
2154
2167
|
return await result.text();
|
|
2155
2168
|
}
|
|
@@ -2171,7 +2184,7 @@ function markup(value) {
|
|
|
2171
2184
|
let currentNode = null;
|
|
2172
2185
|
function getCurrent() {
|
|
2173
2186
|
if (!currentNode) {
|
|
2174
|
-
throw new
|
|
2187
|
+
throw new OwlError("No active component (a hook function should only be called in 'setup')");
|
|
2175
2188
|
}
|
|
2176
2189
|
return currentNode;
|
|
2177
2190
|
}
|
|
@@ -2233,7 +2246,6 @@ class ComponentNode {
|
|
|
2233
2246
|
this.parent = parent;
|
|
2234
2247
|
this.props = props;
|
|
2235
2248
|
this.parentKey = parentKey;
|
|
2236
|
-
this.level = parent ? parent.level + 1 : 0;
|
|
2237
2249
|
const defaultProps = C.defaultProps;
|
|
2238
2250
|
props = Object.assign({}, props);
|
|
2239
2251
|
if (defaultProps) {
|
|
@@ -2466,17 +2478,27 @@ class ComponentNode {
|
|
|
2466
2478
|
|
|
2467
2479
|
const TIMEOUT = Symbol("timeout");
|
|
2468
2480
|
function wrapError(fn, hookName) {
|
|
2469
|
-
const error = new
|
|
2470
|
-
const timeoutError = new
|
|
2481
|
+
const error = new OwlError(`The following error occurred in ${hookName}: `);
|
|
2482
|
+
const timeoutError = new OwlError(`${hookName}'s promise hasn't resolved after 3 seconds`);
|
|
2471
2483
|
const node = getCurrent();
|
|
2472
2484
|
return (...args) => {
|
|
2485
|
+
const onError = (cause) => {
|
|
2486
|
+
error.cause = cause;
|
|
2487
|
+
if (cause instanceof Error) {
|
|
2488
|
+
error.message += `"${cause.message}"`;
|
|
2489
|
+
}
|
|
2490
|
+
else {
|
|
2491
|
+
error.message = `Something that is not an Error was thrown in ${hookName} (see this Error's "cause" property)`;
|
|
2492
|
+
}
|
|
2493
|
+
throw error;
|
|
2494
|
+
};
|
|
2473
2495
|
try {
|
|
2474
2496
|
const result = fn(...args);
|
|
2475
2497
|
if (result instanceof Promise) {
|
|
2476
2498
|
if (hookName === "onWillStart" || hookName === "onWillUpdateProps") {
|
|
2477
2499
|
const fiber = node.fiber;
|
|
2478
2500
|
Promise.race([
|
|
2479
|
-
result,
|
|
2501
|
+
result.catch(() => { }),
|
|
2480
2502
|
new Promise((resolve) => setTimeout(() => resolve(TIMEOUT), 3000)),
|
|
2481
2503
|
]).then((res) => {
|
|
2482
2504
|
if (res === TIMEOUT && node.fiber === fiber) {
|
|
@@ -2484,21 +2506,12 @@ function wrapError(fn, hookName) {
|
|
|
2484
2506
|
}
|
|
2485
2507
|
});
|
|
2486
2508
|
}
|
|
2487
|
-
return result.catch(
|
|
2488
|
-
error.cause = cause;
|
|
2489
|
-
if (cause instanceof Error) {
|
|
2490
|
-
error.message += `"${cause.message}"`;
|
|
2491
|
-
}
|
|
2492
|
-
throw error;
|
|
2493
|
-
});
|
|
2509
|
+
return result.catch(onError);
|
|
2494
2510
|
}
|
|
2495
2511
|
return result;
|
|
2496
2512
|
}
|
|
2497
2513
|
catch (cause) {
|
|
2498
|
-
|
|
2499
|
-
error.message += `"${cause.message}"`;
|
|
2500
|
-
}
|
|
2501
|
-
throw error;
|
|
2514
|
+
onError(cause);
|
|
2502
2515
|
}
|
|
2503
2516
|
};
|
|
2504
2517
|
}
|
|
@@ -2602,7 +2615,7 @@ class VPortal extends VText {
|
|
|
2602
2615
|
}
|
|
2603
2616
|
this.target = el && el.querySelector(this.selector);
|
|
2604
2617
|
if (!this.target) {
|
|
2605
|
-
throw new
|
|
2618
|
+
throw new OwlError("invalid portal target");
|
|
2606
2619
|
}
|
|
2607
2620
|
}
|
|
2608
2621
|
this.realBDom.mount(this.target, null);
|
|
@@ -2696,7 +2709,7 @@ function toSchema(spec) {
|
|
|
2696
2709
|
function validate(obj, spec) {
|
|
2697
2710
|
let errors = validateSchema(obj, spec);
|
|
2698
2711
|
if (errors.length) {
|
|
2699
|
-
throw new
|
|
2712
|
+
throw new OwlError("Invalid object: " + errors.join(", "));
|
|
2700
2713
|
}
|
|
2701
2714
|
}
|
|
2702
2715
|
/**
|
|
@@ -2849,7 +2862,7 @@ function prepareList(collection) {
|
|
|
2849
2862
|
keys = Object.values(collection);
|
|
2850
2863
|
}
|
|
2851
2864
|
else {
|
|
2852
|
-
throw new
|
|
2865
|
+
throw new OwlError("Invalid loop expression");
|
|
2853
2866
|
}
|
|
2854
2867
|
const n = values.length;
|
|
2855
2868
|
return [keys, values, n, new Array(n)];
|
|
@@ -2955,7 +2968,7 @@ function multiRefSetter(refs, name) {
|
|
|
2955
2968
|
if (el) {
|
|
2956
2969
|
count++;
|
|
2957
2970
|
if (count > 1) {
|
|
2958
|
-
throw new
|
|
2971
|
+
throw new OwlError("Cannot have 2 elements with same ref name at the same time");
|
|
2959
2972
|
}
|
|
2960
2973
|
}
|
|
2961
2974
|
if (count === 0 || el) {
|
|
@@ -2992,13 +3005,13 @@ function validateProps(name, props, parent) {
|
|
|
2992
3005
|
: name in schema && !("*" in schema) && !isOptional(schema[name]);
|
|
2993
3006
|
for (let p in defaultProps) {
|
|
2994
3007
|
if (isMandatory(p)) {
|
|
2995
|
-
throw new
|
|
3008
|
+
throw new OwlError(`A default value cannot be defined for a mandatory prop (name: '${p}', component: ${ComponentClass.name})`);
|
|
2996
3009
|
}
|
|
2997
3010
|
}
|
|
2998
3011
|
}
|
|
2999
3012
|
const errors = validateSchema(props, schema);
|
|
3000
3013
|
if (errors.length) {
|
|
3001
|
-
throw new
|
|
3014
|
+
throw new OwlError(`Invalid props for component '${ComponentClass.name}': ` + errors.join(", "));
|
|
3002
3015
|
}
|
|
3003
3016
|
}
|
|
3004
3017
|
const helpers = {
|
|
@@ -3019,6 +3032,7 @@ const helpers = {
|
|
|
3019
3032
|
bind,
|
|
3020
3033
|
createCatcher,
|
|
3021
3034
|
markRaw,
|
|
3035
|
+
OwlError,
|
|
3022
3036
|
};
|
|
3023
3037
|
|
|
3024
3038
|
const bdom = { text, createBlock, list, multi, html, toggler, comment };
|
|
@@ -3046,7 +3060,7 @@ function parseXML$1(xml) {
|
|
|
3046
3060
|
}
|
|
3047
3061
|
}
|
|
3048
3062
|
}
|
|
3049
|
-
throw new
|
|
3063
|
+
throw new OwlError(msg);
|
|
3050
3064
|
}
|
|
3051
3065
|
return doc;
|
|
3052
3066
|
}
|
|
@@ -3077,7 +3091,7 @@ class TemplateSet {
|
|
|
3077
3091
|
if (currentAsString === newAsString) {
|
|
3078
3092
|
return;
|
|
3079
3093
|
}
|
|
3080
|
-
throw new
|
|
3094
|
+
throw new OwlError(`Template ${name} already defined with different content`);
|
|
3081
3095
|
}
|
|
3082
3096
|
this.rawTemplates[name] = template;
|
|
3083
3097
|
}
|
|
@@ -3102,7 +3116,7 @@ class TemplateSet {
|
|
|
3102
3116
|
extraInfo = ` (for component "${componentName}")`;
|
|
3103
3117
|
}
|
|
3104
3118
|
catch { }
|
|
3105
|
-
throw new
|
|
3119
|
+
throw new OwlError(`Missing template: "${name}"${extraInfo}`);
|
|
3106
3120
|
}
|
|
3107
3121
|
const isFn = typeof rawTemplate === "function" && !(rawTemplate instanceof Element);
|
|
3108
3122
|
const templateFn = isFn ? rawTemplate : this._compileTemplate(name, rawTemplate);
|
|
@@ -3118,7 +3132,7 @@ class TemplateSet {
|
|
|
3118
3132
|
return this.templates[name];
|
|
3119
3133
|
}
|
|
3120
3134
|
_compileTemplate(name, template) {
|
|
3121
|
-
throw new
|
|
3135
|
+
throw new OwlError(`Unable to compile a template. Please use owl full build instead`);
|
|
3122
3136
|
}
|
|
3123
3137
|
callTemplate(owner, subTemplate, ctx, parent, key) {
|
|
3124
3138
|
const template = this.getTemplate(subTemplate);
|
|
@@ -3200,14 +3214,14 @@ let tokenizeString = function (expr) {
|
|
|
3200
3214
|
i++;
|
|
3201
3215
|
cur = expr[i];
|
|
3202
3216
|
if (!cur) {
|
|
3203
|
-
throw new
|
|
3217
|
+
throw new OwlError("Invalid expression");
|
|
3204
3218
|
}
|
|
3205
3219
|
s += cur;
|
|
3206
3220
|
}
|
|
3207
3221
|
i++;
|
|
3208
3222
|
}
|
|
3209
3223
|
if (expr[i] !== start) {
|
|
3210
|
-
throw new
|
|
3224
|
+
throw new OwlError("Invalid expression");
|
|
3211
3225
|
}
|
|
3212
3226
|
s += start;
|
|
3213
3227
|
if (start === "`") {
|
|
@@ -3314,7 +3328,7 @@ function tokenize(expr) {
|
|
|
3314
3328
|
error = e; // Silence all errors and throw a generic error below
|
|
3315
3329
|
}
|
|
3316
3330
|
if (current.length || error) {
|
|
3317
|
-
throw new
|
|
3331
|
+
throw new OwlError(`Tokenizer error: could not tokenize \`${expr}\``);
|
|
3318
3332
|
}
|
|
3319
3333
|
return result;
|
|
3320
3334
|
}
|
|
@@ -3865,7 +3879,7 @@ class CodeGenerator {
|
|
|
3865
3879
|
.slice(1)
|
|
3866
3880
|
.map((m) => {
|
|
3867
3881
|
if (!MODS.has(m)) {
|
|
3868
|
-
throw new
|
|
3882
|
+
throw new OwlError(`Unknown event modifier: '${m}'`);
|
|
3869
3883
|
}
|
|
3870
3884
|
return `"${m}"`;
|
|
3871
3885
|
});
|
|
@@ -3911,8 +3925,13 @@ class CodeGenerator {
|
|
|
3911
3925
|
expr = compileExpr(ast.attrs[key]);
|
|
3912
3926
|
if (attrName && isProp(ast.tag, attrName)) {
|
|
3913
3927
|
// we force a new string or new boolean to bypass the equality check in blockdom when patching same value
|
|
3914
|
-
|
|
3915
|
-
|
|
3928
|
+
if (attrName === "value") {
|
|
3929
|
+
// When the expression is falsy, fall back to an empty string
|
|
3930
|
+
expr = `new String((${expr}) || "")`;
|
|
3931
|
+
}
|
|
3932
|
+
else {
|
|
3933
|
+
expr = `new Boolean(${expr})`;
|
|
3934
|
+
}
|
|
3916
3935
|
}
|
|
3917
3936
|
const idx = block.insertData(expr, "attr");
|
|
3918
3937
|
if (key === "t-att") {
|
|
@@ -4186,7 +4205,8 @@ class CodeGenerator {
|
|
|
4186
4205
|
this.define(`key${this.target.loopLevel}`, ast.key ? compileExpr(ast.key) : loopVar);
|
|
4187
4206
|
if (this.dev) {
|
|
4188
4207
|
// Throw error on duplicate keys in dev mode
|
|
4189
|
-
this.
|
|
4208
|
+
this.helpers.add("OwlError");
|
|
4209
|
+
this.addLine(`if (keys${block.id}.has(key${this.target.loopLevel})) { throw new OwlError(\`Got duplicate key in t-foreach: \${key${this.target.loopLevel}}\`)}`);
|
|
4190
4210
|
this.addLine(`keys${block.id}.add(key${this.target.loopLevel});`);
|
|
4191
4211
|
}
|
|
4192
4212
|
let id;
|
|
@@ -4400,7 +4420,7 @@ class CodeGenerator {
|
|
|
4400
4420
|
value = `bind(ctx, ${value || undefined})`;
|
|
4401
4421
|
}
|
|
4402
4422
|
else {
|
|
4403
|
-
throw new
|
|
4423
|
+
throw new OwlError("Invalid prop suffix");
|
|
4404
4424
|
}
|
|
4405
4425
|
}
|
|
4406
4426
|
name = /^[a-z_]+$/i.test(name) ? name : `'${name}'`;
|
|
@@ -4593,9 +4613,6 @@ class CodeGenerator {
|
|
|
4593
4613
|
}
|
|
4594
4614
|
}
|
|
4595
4615
|
|
|
4596
|
-
// -----------------------------------------------------------------------------
|
|
4597
|
-
// AST Type definition
|
|
4598
|
-
// -----------------------------------------------------------------------------
|
|
4599
4616
|
// -----------------------------------------------------------------------------
|
|
4600
4617
|
// Parser
|
|
4601
4618
|
// -----------------------------------------------------------------------------
|
|
@@ -4704,7 +4721,7 @@ function parseDOMNode(node, ctx) {
|
|
|
4704
4721
|
return null;
|
|
4705
4722
|
}
|
|
4706
4723
|
if (tagName.startsWith("block-")) {
|
|
4707
|
-
throw new
|
|
4724
|
+
throw new OwlError(`Invalid tag name: '${tagName}'`);
|
|
4708
4725
|
}
|
|
4709
4726
|
ctx = Object.assign({}, ctx);
|
|
4710
4727
|
if (tagName === "pre") {
|
|
@@ -4723,14 +4740,14 @@ function parseDOMNode(node, ctx) {
|
|
|
4723
4740
|
const value = node.getAttribute(attr);
|
|
4724
4741
|
if (attr.startsWith("t-on")) {
|
|
4725
4742
|
if (attr === "t-on") {
|
|
4726
|
-
throw new
|
|
4743
|
+
throw new OwlError("Missing event name with t-on directive");
|
|
4727
4744
|
}
|
|
4728
4745
|
on = on || {};
|
|
4729
4746
|
on[attr.slice(5)] = value;
|
|
4730
4747
|
}
|
|
4731
4748
|
else if (attr.startsWith("t-model")) {
|
|
4732
4749
|
if (!["input", "select", "textarea"].includes(tagName)) {
|
|
4733
|
-
throw new
|
|
4750
|
+
throw new OwlError("The t-model directive only works with <input>, <textarea> and <select>");
|
|
4734
4751
|
}
|
|
4735
4752
|
let baseExpr, expr;
|
|
4736
4753
|
if (hasDotAtTheEnd.test(value)) {
|
|
@@ -4744,7 +4761,7 @@ function parseDOMNode(node, ctx) {
|
|
|
4744
4761
|
expr = value.slice(index + 1, -1);
|
|
4745
4762
|
}
|
|
4746
4763
|
else {
|
|
4747
|
-
throw new
|
|
4764
|
+
throw new OwlError(`Invalid t-model expression: "${value}" (it should be assignable)`);
|
|
4748
4765
|
}
|
|
4749
4766
|
const typeAttr = node.getAttribute("type");
|
|
4750
4767
|
const isInput = tagName === "input";
|
|
@@ -4774,11 +4791,11 @@ function parseDOMNode(node, ctx) {
|
|
|
4774
4791
|
}
|
|
4775
4792
|
}
|
|
4776
4793
|
else if (attr.startsWith("block-")) {
|
|
4777
|
-
throw new
|
|
4794
|
+
throw new OwlError(`Invalid attribute: '${attr}'`);
|
|
4778
4795
|
}
|
|
4779
4796
|
else if (attr !== "t-name") {
|
|
4780
4797
|
if (attr.startsWith("t-") && !attr.startsWith("t-att")) {
|
|
4781
|
-
throw new
|
|
4798
|
+
throw new OwlError(`Unknown QWeb directive: '${attr}'`);
|
|
4782
4799
|
}
|
|
4783
4800
|
const tModel = ctx.tModelInfo;
|
|
4784
4801
|
if (tModel && ["t-att-value", "t-attf-value"].includes(attr)) {
|
|
@@ -4829,7 +4846,7 @@ function parseTEscNode(node, ctx) {
|
|
|
4829
4846
|
};
|
|
4830
4847
|
}
|
|
4831
4848
|
if (ast.type === 11 /* TComponent */) {
|
|
4832
|
-
throw new
|
|
4849
|
+
throw new OwlError("t-esc is not supported on Component nodes");
|
|
4833
4850
|
}
|
|
4834
4851
|
return tesc;
|
|
4835
4852
|
}
|
|
@@ -4877,7 +4894,7 @@ function parseTForEach(node, ctx) {
|
|
|
4877
4894
|
node.removeAttribute("t-as");
|
|
4878
4895
|
const key = node.getAttribute("t-key");
|
|
4879
4896
|
if (!key) {
|
|
4880
|
-
throw new
|
|
4897
|
+
throw new OwlError(`"Directive t-foreach should always be used with a t-key!" (expression: t-foreach="${collection}" t-as="${elem}")`);
|
|
4881
4898
|
}
|
|
4882
4899
|
node.removeAttribute("t-key");
|
|
4883
4900
|
const memo = node.getAttribute("t-memo") || "";
|
|
@@ -5037,7 +5054,7 @@ function parseComponent(node, ctx) {
|
|
|
5037
5054
|
const firstLetter = name[0];
|
|
5038
5055
|
let isDynamic = node.hasAttribute("t-component");
|
|
5039
5056
|
if (isDynamic && name !== "t") {
|
|
5040
|
-
throw new
|
|
5057
|
+
throw new OwlError(`Directive 't-component' can only be used on <t> nodes (used on a <${name}>)`);
|
|
5041
5058
|
}
|
|
5042
5059
|
if (!(firstLetter === firstLetter.toUpperCase() || isDynamic)) {
|
|
5043
5060
|
return null;
|
|
@@ -5061,7 +5078,7 @@ function parseComponent(node, ctx) {
|
|
|
5061
5078
|
}
|
|
5062
5079
|
else {
|
|
5063
5080
|
const message = directiveErrorMap.get(name.split("-").slice(0, 2).join("-"));
|
|
5064
|
-
throw new
|
|
5081
|
+
throw new OwlError(message || `unsupported directive on Component: ${name}`);
|
|
5065
5082
|
}
|
|
5066
5083
|
}
|
|
5067
5084
|
else {
|
|
@@ -5076,7 +5093,7 @@ function parseComponent(node, ctx) {
|
|
|
5076
5093
|
const slotNodes = Array.from(clone.querySelectorAll("[t-set-slot]"));
|
|
5077
5094
|
for (let slotNode of slotNodes) {
|
|
5078
5095
|
if (slotNode.tagName !== "t") {
|
|
5079
|
-
throw new
|
|
5096
|
+
throw new OwlError(`Directive 't-set-slot' can only be used on <t> nodes (used on a <${slotNode.tagName}>)`);
|
|
5080
5097
|
}
|
|
5081
5098
|
const name = slotNode.getAttribute("t-set-slot");
|
|
5082
5099
|
// check if this is defined in a sub component (in which case it should
|
|
@@ -5241,25 +5258,25 @@ function normalizeTIf(el) {
|
|
|
5241
5258
|
let nattr = (name) => +!!node.getAttribute(name);
|
|
5242
5259
|
if (prevElem && (pattr("t-if") || pattr("t-elif"))) {
|
|
5243
5260
|
if (pattr("t-foreach")) {
|
|
5244
|
-
throw new
|
|
5261
|
+
throw new OwlError("t-if cannot stay at the same level as t-foreach when using t-elif or t-else");
|
|
5245
5262
|
}
|
|
5246
5263
|
if (["t-if", "t-elif", "t-else"].map(nattr).reduce(function (a, b) {
|
|
5247
5264
|
return a + b;
|
|
5248
5265
|
}) > 1) {
|
|
5249
|
-
throw new
|
|
5266
|
+
throw new OwlError("Only one conditional branching directive is allowed per node");
|
|
5250
5267
|
}
|
|
5251
5268
|
// All text (with only spaces) and comment nodes (nodeType 8) between
|
|
5252
5269
|
// branch nodes are removed
|
|
5253
5270
|
let textNode;
|
|
5254
5271
|
while ((textNode = node.previousSibling) !== prevElem) {
|
|
5255
5272
|
if (textNode.nodeValue.trim().length && textNode.nodeType !== 8) {
|
|
5256
|
-
throw new
|
|
5273
|
+
throw new OwlError("text is not allowed between branching directives");
|
|
5257
5274
|
}
|
|
5258
5275
|
textNode.remove();
|
|
5259
5276
|
}
|
|
5260
5277
|
}
|
|
5261
5278
|
else {
|
|
5262
|
-
throw new
|
|
5279
|
+
throw new OwlError("t-elif and t-else directives must be preceded by a t-if or t-elif directive");
|
|
5263
5280
|
}
|
|
5264
5281
|
}
|
|
5265
5282
|
}
|
|
@@ -5275,7 +5292,7 @@ function normalizeTEsc(el) {
|
|
|
5275
5292
|
const elements = [...el.querySelectorAll("[t-esc]")].filter((el) => el.tagName[0] === el.tagName[0].toUpperCase() || el.hasAttribute("t-component"));
|
|
5276
5293
|
for (const el of elements) {
|
|
5277
5294
|
if (el.childNodes.length) {
|
|
5278
|
-
throw new
|
|
5295
|
+
throw new OwlError("Cannot have t-esc on a component that already has content");
|
|
5279
5296
|
}
|
|
5280
5297
|
const value = el.getAttribute("t-esc");
|
|
5281
5298
|
el.removeAttribute("t-esc");
|
|
@@ -5327,7 +5344,7 @@ function parseXML(xml) {
|
|
|
5327
5344
|
}
|
|
5328
5345
|
}
|
|
5329
5346
|
}
|
|
5330
|
-
throw new
|
|
5347
|
+
throw new OwlError(msg);
|
|
5331
5348
|
}
|
|
5332
5349
|
return doc;
|
|
5333
5350
|
}
|
|
@@ -5381,7 +5398,7 @@ const mainEventHandler = (data, ev, currentTarget) => {
|
|
|
5381
5398
|
if (Object.hasOwnProperty.call(data, 0)) {
|
|
5382
5399
|
const handler = data[0];
|
|
5383
5400
|
if (typeof handler !== "function") {
|
|
5384
|
-
throw new
|
|
5401
|
+
throw new OwlError(`Invalid handler (expected a function, received: '${handler}')`);
|
|
5385
5402
|
}
|
|
5386
5403
|
let node = data[1] ? data[1].__owl__ : null;
|
|
5387
5404
|
if (node ? node.status === 1 /* MOUNTED */ : true) {
|
|
@@ -5565,10 +5582,10 @@ class App extends TemplateSet {
|
|
|
5565
5582
|
if (isStatic) {
|
|
5566
5583
|
C = parent.constructor.components[name];
|
|
5567
5584
|
if (!C) {
|
|
5568
|
-
throw new
|
|
5585
|
+
throw new OwlError(`Cannot find the definition of component "${name}"`);
|
|
5569
5586
|
}
|
|
5570
5587
|
else if (!(C.prototype instanceof Component)) {
|
|
5571
|
-
throw new
|
|
5588
|
+
throw new OwlError(`"${name}" is not a Component. It must inherit from the Component class`);
|
|
5572
5589
|
}
|
|
5573
5590
|
}
|
|
5574
5591
|
node = new ComponentNode(C, props, this, ctx, key);
|
|
@@ -5727,6 +5744,7 @@ TemplateSet.prototype._compileTemplate = function _compileTemplate(name, templat
|
|
|
5727
5744
|
exports.App = App;
|
|
5728
5745
|
exports.Component = Component;
|
|
5729
5746
|
exports.EventBus = EventBus;
|
|
5747
|
+
exports.OwlError = OwlError;
|
|
5730
5748
|
exports.__info__ = __info__;
|
|
5731
5749
|
exports.blockDom = blockDom;
|
|
5732
5750
|
exports.loadFile = loadFile;
|
|
@@ -5759,7 +5777,7 @@ exports.whenReady = whenReady;
|
|
|
5759
5777
|
exports.xml = xml;
|
|
5760
5778
|
|
|
5761
5779
|
|
|
5762
|
-
__info__.version = '2.0.0-beta-
|
|
5763
|
-
__info__.date = '2022-
|
|
5764
|
-
__info__.hash = '
|
|
5780
|
+
__info__.version = '2.0.0-beta-17';
|
|
5781
|
+
__info__.date = '2022-09-01T13:41:44.572Z';
|
|
5782
|
+
__info__.hash = '9cb74d6';
|
|
5765
5783
|
__info__.url = 'https://github.com/odoo/owl';
|