@odoo/owl 2.0.0-beta.2 → 2.0.0-beta.3
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/CHANGELOG.md +766 -0
- package/dist/owl.cjs.js +230 -93
- package/dist/owl.cjs.min.js +1 -1
- package/dist/owl.es.js +230 -93
- package/dist/owl.es.min.js +1 -1
- package/dist/owl.iife.js +230 -93
- package/dist/owl.iife.min.js +1 -1
- package/dist/types/app/template_helpers.d.ts +2 -1
- package/dist/types/blockdom/event_catcher.d.ts +7 -0
- package/dist/types/blockdom/events.d.ts +1 -0
- package/dist/types/blockdom/index.d.ts +1 -0
- package/dist/types/compiler/code_generator.d.ts +9 -6
- package/dist/types/compiler/parser.d.ts +25 -23
- package/package.json +1 -1
package/dist/owl.cjs.js
CHANGED
|
@@ -267,10 +267,14 @@ function createElementHandler(evName, capture = false) {
|
|
|
267
267
|
this[eventKey] = data;
|
|
268
268
|
this.addEventListener(evName, listener, { capture });
|
|
269
269
|
}
|
|
270
|
+
function remove() {
|
|
271
|
+
delete this[eventKey];
|
|
272
|
+
this.removeEventListener(evName, listener, { capture });
|
|
273
|
+
}
|
|
270
274
|
function update(data) {
|
|
271
275
|
this[eventKey] = data;
|
|
272
276
|
}
|
|
273
|
-
return { setup, update };
|
|
277
|
+
return { setup, update, remove };
|
|
274
278
|
}
|
|
275
279
|
// Synthetic handler: a form of event delegation that allows placing only one
|
|
276
280
|
// listener per event type.
|
|
@@ -287,7 +291,10 @@ function createSyntheticHandler(evName, capture = false) {
|
|
|
287
291
|
_data[currentId] = data;
|
|
288
292
|
this[eventKey] = _data;
|
|
289
293
|
}
|
|
290
|
-
|
|
294
|
+
function remove() {
|
|
295
|
+
delete this[eventKey];
|
|
296
|
+
}
|
|
297
|
+
return { setup, update: setup, remove };
|
|
291
298
|
}
|
|
292
299
|
function nativeToSyntheticEvent(eventKey, event) {
|
|
293
300
|
let dom = event.target;
|
|
@@ -1282,6 +1289,75 @@ function html(str) {
|
|
|
1282
1289
|
return new VHtml(str);
|
|
1283
1290
|
}
|
|
1284
1291
|
|
|
1292
|
+
function createCatcher(eventsSpec) {
|
|
1293
|
+
let setupFns = [];
|
|
1294
|
+
let removeFns = [];
|
|
1295
|
+
for (let name in eventsSpec) {
|
|
1296
|
+
let index = eventsSpec[name];
|
|
1297
|
+
let { setup, remove } = createEventHandler(name);
|
|
1298
|
+
setupFns[index] = setup;
|
|
1299
|
+
removeFns[index] = remove;
|
|
1300
|
+
}
|
|
1301
|
+
let n = setupFns.length;
|
|
1302
|
+
class VCatcher {
|
|
1303
|
+
constructor(child, handlers) {
|
|
1304
|
+
this.afterNode = null;
|
|
1305
|
+
this.child = child;
|
|
1306
|
+
this.handlers = handlers;
|
|
1307
|
+
}
|
|
1308
|
+
mount(parent, afterNode) {
|
|
1309
|
+
this.parentEl = parent;
|
|
1310
|
+
this.afterNode = afterNode;
|
|
1311
|
+
this.child.mount(parent, afterNode);
|
|
1312
|
+
for (let i = 0; i < n; i++) {
|
|
1313
|
+
let origFn = this.handlers[i][0];
|
|
1314
|
+
const self = this;
|
|
1315
|
+
this.handlers[i][0] = function (ev) {
|
|
1316
|
+
const target = ev.target;
|
|
1317
|
+
let currentNode = self.child.firstNode();
|
|
1318
|
+
const afterNode = self.afterNode;
|
|
1319
|
+
while (currentNode !== afterNode) {
|
|
1320
|
+
if (currentNode.contains(target)) {
|
|
1321
|
+
return origFn.call(this, ev);
|
|
1322
|
+
}
|
|
1323
|
+
currentNode = currentNode.nextSibling;
|
|
1324
|
+
}
|
|
1325
|
+
};
|
|
1326
|
+
setupFns[i].call(parent, this.handlers[i]);
|
|
1327
|
+
}
|
|
1328
|
+
}
|
|
1329
|
+
moveBefore(other, afterNode) {
|
|
1330
|
+
this.afterNode = null;
|
|
1331
|
+
this.child.moveBefore(other ? other.child : null, afterNode);
|
|
1332
|
+
}
|
|
1333
|
+
patch(other, withBeforeRemove) {
|
|
1334
|
+
if (this === other) {
|
|
1335
|
+
return;
|
|
1336
|
+
}
|
|
1337
|
+
this.handlers = other.handlers;
|
|
1338
|
+
this.child.patch(other.child, withBeforeRemove);
|
|
1339
|
+
}
|
|
1340
|
+
beforeRemove() {
|
|
1341
|
+
this.child.beforeRemove();
|
|
1342
|
+
}
|
|
1343
|
+
remove() {
|
|
1344
|
+
for (let i = 0; i < n; i++) {
|
|
1345
|
+
removeFns[i].call(this.parentEl);
|
|
1346
|
+
}
|
|
1347
|
+
this.child.remove();
|
|
1348
|
+
}
|
|
1349
|
+
firstNode() {
|
|
1350
|
+
return this.child.firstNode();
|
|
1351
|
+
}
|
|
1352
|
+
toString() {
|
|
1353
|
+
return this.child.toString();
|
|
1354
|
+
}
|
|
1355
|
+
}
|
|
1356
|
+
return function (child, handlers) {
|
|
1357
|
+
return new VCatcher(child, handlers);
|
|
1358
|
+
};
|
|
1359
|
+
}
|
|
1360
|
+
|
|
1285
1361
|
function mount$1(vnode, fixture, afterNode = null) {
|
|
1286
1362
|
vnode.mount(fixture, afterNode);
|
|
1287
1363
|
}
|
|
@@ -2734,24 +2810,31 @@ const TOKENIZERS = [
|
|
|
2734
2810
|
function tokenize(expr) {
|
|
2735
2811
|
const result = [];
|
|
2736
2812
|
let token = true;
|
|
2737
|
-
|
|
2738
|
-
|
|
2739
|
-
|
|
2740
|
-
|
|
2741
|
-
|
|
2742
|
-
|
|
2743
|
-
|
|
2744
|
-
|
|
2745
|
-
|
|
2813
|
+
let error;
|
|
2814
|
+
let current = expr;
|
|
2815
|
+
try {
|
|
2816
|
+
while (token) {
|
|
2817
|
+
current = current.trim();
|
|
2818
|
+
if (current) {
|
|
2819
|
+
for (let tokenizer of TOKENIZERS) {
|
|
2820
|
+
token = tokenizer(current);
|
|
2821
|
+
if (token) {
|
|
2822
|
+
result.push(token);
|
|
2823
|
+
current = current.slice(token.size || token.value.length);
|
|
2824
|
+
break;
|
|
2825
|
+
}
|
|
2746
2826
|
}
|
|
2747
2827
|
}
|
|
2828
|
+
else {
|
|
2829
|
+
token = false;
|
|
2830
|
+
}
|
|
2748
2831
|
}
|
|
2749
|
-
else {
|
|
2750
|
-
token = false;
|
|
2751
|
-
}
|
|
2752
2832
|
}
|
|
2753
|
-
|
|
2754
|
-
|
|
2833
|
+
catch (e) {
|
|
2834
|
+
error = e; // Silence all errors and throw a generic error below
|
|
2835
|
+
}
|
|
2836
|
+
if (current.length || error) {
|
|
2837
|
+
throw new Error(`Tokenizer error: could not tokenize \`${expr}\``);
|
|
2755
2838
|
}
|
|
2756
2839
|
return result;
|
|
2757
2840
|
}
|
|
@@ -2956,7 +3039,7 @@ function createContext(parentCtx, params) {
|
|
|
2956
3039
|
}, params);
|
|
2957
3040
|
}
|
|
2958
3041
|
class CodeTarget {
|
|
2959
|
-
constructor(name) {
|
|
3042
|
+
constructor(name, on) {
|
|
2960
3043
|
this.indentLevel = 0;
|
|
2961
3044
|
this.loopLevel = 0;
|
|
2962
3045
|
this.code = [];
|
|
@@ -2967,6 +3050,7 @@ class CodeTarget {
|
|
|
2967
3050
|
this.refInfo = {};
|
|
2968
3051
|
this.shouldProtectScope = false;
|
|
2969
3052
|
this.name = name;
|
|
3053
|
+
this.on = on || null;
|
|
2970
3054
|
}
|
|
2971
3055
|
addLine(line, idx) {
|
|
2972
3056
|
const prefix = new Array(this.indentLevel + 2).join(" ");
|
|
@@ -3016,7 +3100,7 @@ class CodeGenerator {
|
|
|
3016
3100
|
this.targets = [];
|
|
3017
3101
|
this.target = new CodeTarget("template");
|
|
3018
3102
|
this.translatableAttributes = TRANSLATABLE_ATTRS;
|
|
3019
|
-
this.
|
|
3103
|
+
this.staticDefs = [];
|
|
3020
3104
|
this.helpers = new Set();
|
|
3021
3105
|
this.translateFn = options.translateFn || ((s) => s);
|
|
3022
3106
|
if (options.translatableAttributes) {
|
|
@@ -3059,8 +3143,8 @@ class CodeGenerator {
|
|
|
3059
3143
|
if (this.templateName) {
|
|
3060
3144
|
mainCode.push(`// Template name: "${this.templateName}"`);
|
|
3061
3145
|
}
|
|
3062
|
-
for (let { id,
|
|
3063
|
-
mainCode.push(`const ${id} =
|
|
3146
|
+
for (let { id, expr } of this.staticDefs) {
|
|
3147
|
+
mainCode.push(`const ${id} = ${expr};`);
|
|
3064
3148
|
}
|
|
3065
3149
|
// define all blocks
|
|
3066
3150
|
if (this.blocks.length) {
|
|
@@ -3096,19 +3180,21 @@ class CodeGenerator {
|
|
|
3096
3180
|
}
|
|
3097
3181
|
return code;
|
|
3098
3182
|
}
|
|
3099
|
-
compileInNewTarget(prefix, ast, ctx) {
|
|
3183
|
+
compileInNewTarget(prefix, ast, ctx, on) {
|
|
3100
3184
|
const name = this.generateId(prefix);
|
|
3101
3185
|
const initialTarget = this.target;
|
|
3102
|
-
const target = new CodeTarget(name);
|
|
3186
|
+
const target = new CodeTarget(name, on);
|
|
3103
3187
|
this.targets.push(target);
|
|
3104
3188
|
this.target = target;
|
|
3105
|
-
|
|
3106
|
-
this.compileAST(ast, subCtx);
|
|
3189
|
+
this.compileAST(ast, createContext(ctx));
|
|
3107
3190
|
this.target = initialTarget;
|
|
3108
3191
|
return name;
|
|
3109
3192
|
}
|
|
3110
|
-
addLine(line) {
|
|
3111
|
-
this.target.addLine(line);
|
|
3193
|
+
addLine(line, idx) {
|
|
3194
|
+
this.target.addLine(line, idx);
|
|
3195
|
+
}
|
|
3196
|
+
define(varName, expr) {
|
|
3197
|
+
this.addLine(`const ${varName} = ${expr};`);
|
|
3112
3198
|
}
|
|
3113
3199
|
generateId(prefix = "") {
|
|
3114
3200
|
this.ids[prefix] = (this.ids[prefix] || 0) + 1;
|
|
@@ -3150,10 +3236,13 @@ class CodeGenerator {
|
|
|
3150
3236
|
blockExpr = `toggler(${tKeyExpr}, ${blockExpr})`;
|
|
3151
3237
|
}
|
|
3152
3238
|
if (block.isRoot && !ctx.preventRoot) {
|
|
3239
|
+
if (this.target.on) {
|
|
3240
|
+
blockExpr = this.wrapWithEventCatcher(blockExpr, this.target.on);
|
|
3241
|
+
}
|
|
3153
3242
|
this.addLine(`return ${blockExpr};`);
|
|
3154
3243
|
}
|
|
3155
3244
|
else {
|
|
3156
|
-
this.
|
|
3245
|
+
this.define(block.varName, blockExpr);
|
|
3157
3246
|
}
|
|
3158
3247
|
}
|
|
3159
3248
|
/**
|
|
@@ -3181,7 +3270,7 @@ class CodeGenerator {
|
|
|
3181
3270
|
if (!mapping.has(tok.varName)) {
|
|
3182
3271
|
const varId = this.generateId("v");
|
|
3183
3272
|
mapping.set(tok.varName, varId);
|
|
3184
|
-
this.
|
|
3273
|
+
this.define(varId, tok.value);
|
|
3185
3274
|
}
|
|
3186
3275
|
tok.value = mapping.get(tok.varName);
|
|
3187
3276
|
}
|
|
@@ -3320,7 +3409,7 @@ class CodeGenerator {
|
|
|
3320
3409
|
this.blocks.push(block);
|
|
3321
3410
|
if (ast.dynamicTag) {
|
|
3322
3411
|
const tagExpr = this.generateId("tag");
|
|
3323
|
-
this.
|
|
3412
|
+
this.define(tagExpr, compileExpr(ast.dynamicTag));
|
|
3324
3413
|
block.dynamicTagName = tagExpr;
|
|
3325
3414
|
}
|
|
3326
3415
|
}
|
|
@@ -3402,10 +3491,10 @@ class CodeGenerator {
|
|
|
3402
3491
|
const { hasDynamicChildren, baseExpr, expr, eventType, shouldNumberize, shouldTrim, targetAttr, specialInitTargetAttr, } = ast.model;
|
|
3403
3492
|
const baseExpression = compileExpr(baseExpr);
|
|
3404
3493
|
const bExprId = this.generateId("bExpr");
|
|
3405
|
-
this.
|
|
3494
|
+
this.define(bExprId, baseExpression);
|
|
3406
3495
|
const expression = compileExpr(expr);
|
|
3407
3496
|
const exprId = this.generateId("expr");
|
|
3408
|
-
this.
|
|
3497
|
+
this.define(exprId, expression);
|
|
3409
3498
|
const fullExpression = `${bExprId}[${exprId}]`;
|
|
3410
3499
|
let idx;
|
|
3411
3500
|
if (specialInitTargetAttr) {
|
|
@@ -3415,7 +3504,7 @@ class CodeGenerator {
|
|
|
3415
3504
|
else if (hasDynamicChildren) {
|
|
3416
3505
|
const bValueId = this.generateId("bValue");
|
|
3417
3506
|
tModelSelectedExpr = `${bValueId}`;
|
|
3418
|
-
this.
|
|
3507
|
+
this.define(tModelSelectedExpr, fullExpression);
|
|
3419
3508
|
}
|
|
3420
3509
|
else {
|
|
3421
3510
|
idx = block.insertData(`${fullExpression}`, "attr");
|
|
@@ -3463,14 +3552,14 @@ class CodeGenerator {
|
|
|
3463
3552
|
const children = block.children.slice();
|
|
3464
3553
|
let current = children.shift();
|
|
3465
3554
|
for (let i = codeIdx; i < code.length; i++) {
|
|
3466
|
-
if (code[i].trimStart().startsWith(`
|
|
3467
|
-
code[i] = code[i].replace(`
|
|
3555
|
+
if (code[i].trimStart().startsWith(`const ${current.varName} `)) {
|
|
3556
|
+
code[i] = code[i].replace(`const ${current.varName}`, current.varName);
|
|
3468
3557
|
current = children.shift();
|
|
3469
3558
|
if (!current)
|
|
3470
3559
|
break;
|
|
3471
3560
|
}
|
|
3472
3561
|
}
|
|
3473
|
-
this.
|
|
3562
|
+
this.addLine(`let ${block.children.map((c) => c.varName)};`, codeIdx);
|
|
3474
3563
|
}
|
|
3475
3564
|
}
|
|
3476
3565
|
}
|
|
@@ -3558,14 +3647,14 @@ class CodeGenerator {
|
|
|
3558
3647
|
const children = block.children.slice();
|
|
3559
3648
|
let current = children.shift();
|
|
3560
3649
|
for (let i = codeIdx; i < code.length; i++) {
|
|
3561
|
-
if (code[i].trimStart().startsWith(`
|
|
3562
|
-
code[i] = code[i].replace(`
|
|
3650
|
+
if (code[i].trimStart().startsWith(`const ${current.varName} `)) {
|
|
3651
|
+
code[i] = code[i].replace(`const ${current.varName}`, current.varName);
|
|
3563
3652
|
current = children.shift();
|
|
3564
3653
|
if (!current)
|
|
3565
3654
|
break;
|
|
3566
3655
|
}
|
|
3567
3656
|
}
|
|
3568
|
-
this.
|
|
3657
|
+
this.addLine(`let ${block.children.map((c) => c.varName)};`, codeIdx);
|
|
3569
3658
|
}
|
|
3570
3659
|
// note: this part is duplicated from end of compilemulti:
|
|
3571
3660
|
const args = block.children.map((c) => c.varName).join(", ");
|
|
@@ -3586,10 +3675,10 @@ class CodeGenerator {
|
|
|
3586
3675
|
const l = `l_block${block.id}`;
|
|
3587
3676
|
const c = `c_block${block.id}`;
|
|
3588
3677
|
this.helpers.add("prepareList");
|
|
3589
|
-
this.
|
|
3678
|
+
this.define(`[${keys}, ${vals}, ${l}, ${c}]`, `prepareList(${compileExpr(ast.collection)});`);
|
|
3590
3679
|
// Throw errors on duplicate keys in dev mode
|
|
3591
3680
|
if (this.dev) {
|
|
3592
|
-
this.
|
|
3681
|
+
this.define(`keys${block.id}`, `new Set()`);
|
|
3593
3682
|
}
|
|
3594
3683
|
this.addLine(`for (let ${loopVar} = 0; ${loopVar} < ${l}; ${loopVar}++) {`);
|
|
3595
3684
|
this.target.indentLevel++;
|
|
@@ -3606,7 +3695,7 @@ class CodeGenerator {
|
|
|
3606
3695
|
if (!ast.hasNoValue) {
|
|
3607
3696
|
this.addLine(`ctx[\`${ast.elem}_value\`] = ${keys}[${loopVar}];`);
|
|
3608
3697
|
}
|
|
3609
|
-
this.
|
|
3698
|
+
this.define(`key${this.target.loopLevel}`, ast.key ? compileExpr(ast.key) : loopVar);
|
|
3610
3699
|
if (this.dev) {
|
|
3611
3700
|
// Throw error on duplicate keys in dev mode
|
|
3612
3701
|
this.addLine(`if (keys${block.id}.has(key${this.target.loopLevel})) { throw new Error(\`Got duplicate key in t-foreach: \${key${this.target.loopLevel}}\`)}`);
|
|
@@ -3616,8 +3705,8 @@ class CodeGenerator {
|
|
|
3616
3705
|
if (ast.memo) {
|
|
3617
3706
|
this.target.hasCache = true;
|
|
3618
3707
|
id = this.generateId();
|
|
3619
|
-
this.
|
|
3620
|
-
this.
|
|
3708
|
+
this.define(`memo${id}`, compileExpr(ast.memo));
|
|
3709
|
+
this.define(`vnode${id}`, `cache[key${this.target.loopLevel}];`);
|
|
3621
3710
|
this.addLine(`if (vnode${id}) {`);
|
|
3622
3711
|
this.target.indentLevel++;
|
|
3623
3712
|
this.addLine(`if (shallowEqual(vnode${id}.memo, memo${id})) {`);
|
|
@@ -3645,7 +3734,7 @@ class CodeGenerator {
|
|
|
3645
3734
|
}
|
|
3646
3735
|
compileTKey(ast, ctx) {
|
|
3647
3736
|
const tKeyExpr = this.generateId("tKey_");
|
|
3648
|
-
this.
|
|
3737
|
+
this.define(tKeyExpr, compileExpr(ast.expr));
|
|
3649
3738
|
ctx = createContext(ctx, {
|
|
3650
3739
|
tKeyExpr,
|
|
3651
3740
|
block: ctx.block,
|
|
@@ -3690,14 +3779,14 @@ class CodeGenerator {
|
|
|
3690
3779
|
const children = block.children.slice();
|
|
3691
3780
|
let current = children.shift();
|
|
3692
3781
|
for (let i = codeIdx; i < code.length; i++) {
|
|
3693
|
-
if (code[i].trimStart().startsWith(`
|
|
3694
|
-
code[i] = code[i].replace(`
|
|
3782
|
+
if (code[i].trimStart().startsWith(`const ${current.varName} `)) {
|
|
3783
|
+
code[i] = code[i].replace(`const ${current.varName}`, current.varName);
|
|
3695
3784
|
current = children.shift();
|
|
3696
3785
|
if (!current)
|
|
3697
3786
|
break;
|
|
3698
3787
|
}
|
|
3699
3788
|
}
|
|
3700
|
-
this.
|
|
3789
|
+
this.addLine(`let ${block.children.map((c) => c.varName)};`, codeIdx);
|
|
3701
3790
|
}
|
|
3702
3791
|
}
|
|
3703
3792
|
const args = block.children.map((c) => c.varName).join(", ");
|
|
@@ -3728,7 +3817,7 @@ class CodeGenerator {
|
|
|
3728
3817
|
const key = `key + \`${this.generateComponentKey()}\``;
|
|
3729
3818
|
if (isDynamic) {
|
|
3730
3819
|
const templateVar = this.generateId("template");
|
|
3731
|
-
this.
|
|
3820
|
+
this.define(templateVar, subTemplate);
|
|
3732
3821
|
block = this.createBlock(block, "multi", ctx);
|
|
3733
3822
|
this.helpers.add("call");
|
|
3734
3823
|
this.insertBlock(`call(this, ${templateVar}, ctx, node, ${key})`, block, {
|
|
@@ -3739,7 +3828,7 @@ class CodeGenerator {
|
|
|
3739
3828
|
else {
|
|
3740
3829
|
const id = this.generateId(`callTemplate_`);
|
|
3741
3830
|
this.helpers.add("getTemplate");
|
|
3742
|
-
this.
|
|
3831
|
+
this.staticDefs.push({ id, expr: `getTemplate(${subTemplate})` });
|
|
3743
3832
|
block = this.createBlock(block, "multi", ctx);
|
|
3744
3833
|
this.insertBlock(`${id}.call(this, ctx, node, ${key})`, block, {
|
|
3745
3834
|
...ctx,
|
|
@@ -3833,26 +3922,25 @@ class CodeGenerator {
|
|
|
3833
3922
|
compileComponent(ast, ctx) {
|
|
3834
3923
|
let { block } = ctx;
|
|
3835
3924
|
// props
|
|
3836
|
-
const hasSlotsProp = "slots" in ast.props;
|
|
3925
|
+
const hasSlotsProp = "slots" in (ast.props || {});
|
|
3837
3926
|
const props = [];
|
|
3838
|
-
const propExpr = this.formatPropObject(ast.props);
|
|
3927
|
+
const propExpr = this.formatPropObject(ast.props || {});
|
|
3839
3928
|
if (propExpr) {
|
|
3840
3929
|
props.push(propExpr);
|
|
3841
3930
|
}
|
|
3842
3931
|
// slots
|
|
3843
|
-
const hasSlot = !!Object.keys(ast.slots).length;
|
|
3844
3932
|
let slotDef = "";
|
|
3845
|
-
if (
|
|
3933
|
+
if (ast.slots) {
|
|
3846
3934
|
let ctxStr = "ctx";
|
|
3847
3935
|
if (this.target.loopLevel || !this.hasSafeContext) {
|
|
3848
3936
|
ctxStr = this.generateId("ctx");
|
|
3849
3937
|
this.helpers.add("capture");
|
|
3850
|
-
this.
|
|
3938
|
+
this.define(ctxStr, `capture(ctx)`);
|
|
3851
3939
|
}
|
|
3852
3940
|
let slotStr = [];
|
|
3853
3941
|
for (let slotName in ast.slots) {
|
|
3854
|
-
const slotAst = ast.slots[slotName]
|
|
3855
|
-
const name = this.compileInNewTarget("slot", slotAst, ctx);
|
|
3942
|
+
const slotAst = ast.slots[slotName];
|
|
3943
|
+
const name = this.compileInNewTarget("slot", slotAst.content, ctx, slotAst.on);
|
|
3856
3944
|
const params = [`__render: ${name}, __ctx: ${ctxStr}`];
|
|
3857
3945
|
const scope = ast.slots[slotName].scope;
|
|
3858
3946
|
if (scope) {
|
|
@@ -3878,7 +3966,7 @@ class CodeGenerator {
|
|
|
3878
3966
|
let propVar;
|
|
3879
3967
|
if ((slotDef && (ast.dynamicProps || hasSlotsProp)) || this.dev) {
|
|
3880
3968
|
propVar = this.generateId("props");
|
|
3881
|
-
this.
|
|
3969
|
+
this.define(propVar, propString);
|
|
3882
3970
|
propString = propVar;
|
|
3883
3971
|
}
|
|
3884
3972
|
if (slotDef && (ast.dynamicProps || hasSlotsProp)) {
|
|
@@ -3890,7 +3978,7 @@ class CodeGenerator {
|
|
|
3890
3978
|
let expr;
|
|
3891
3979
|
if (ast.isDynamic) {
|
|
3892
3980
|
expr = this.generateId("Comp");
|
|
3893
|
-
this.
|
|
3981
|
+
this.define(expr, compileExpr(ast.name));
|
|
3894
3982
|
}
|
|
3895
3983
|
else {
|
|
3896
3984
|
expr = `\`${ast.name}\``;
|
|
@@ -3911,9 +3999,28 @@ class CodeGenerator {
|
|
|
3911
3999
|
if (ast.isDynamic) {
|
|
3912
4000
|
blockExpr = `toggler(${expr}, ${blockExpr})`;
|
|
3913
4001
|
}
|
|
4002
|
+
// event handling
|
|
4003
|
+
if (ast.on) {
|
|
4004
|
+
blockExpr = this.wrapWithEventCatcher(blockExpr, ast.on);
|
|
4005
|
+
}
|
|
3914
4006
|
block = this.createBlock(block, "multi", ctx);
|
|
3915
4007
|
this.insertBlock(blockExpr, block, ctx);
|
|
3916
4008
|
}
|
|
4009
|
+
wrapWithEventCatcher(expr, on) {
|
|
4010
|
+
this.helpers.add("createCatcher");
|
|
4011
|
+
let name = this.generateId("catcher");
|
|
4012
|
+
let spec = {};
|
|
4013
|
+
let handlers = [];
|
|
4014
|
+
for (let ev in on) {
|
|
4015
|
+
let handlerId = this.generateId("hdlr");
|
|
4016
|
+
let idx = handlers.push(handlerId) - 1;
|
|
4017
|
+
spec[ev] = idx;
|
|
4018
|
+
const handler = this.generateHandlerCode(ev, on[ev]);
|
|
4019
|
+
this.define(handlerId, handler);
|
|
4020
|
+
}
|
|
4021
|
+
this.staticDefs.push({ id: name, expr: `createCatcher(${JSON.stringify(spec)})` });
|
|
4022
|
+
return `${name}(${expr}, [${handlers.join(",")}])`;
|
|
4023
|
+
}
|
|
3917
4024
|
compileTSlot(ast, ctx) {
|
|
3918
4025
|
this.helpers.add("callSlot");
|
|
3919
4026
|
let { block } = ctx;
|
|
@@ -3935,13 +4042,17 @@ class CodeGenerator {
|
|
|
3935
4042
|
else {
|
|
3936
4043
|
if (dynamic) {
|
|
3937
4044
|
let name = this.generateId("slot");
|
|
3938
|
-
this.
|
|
4045
|
+
this.define(name, slotName);
|
|
3939
4046
|
blockString = `toggler(${name}, callSlot(ctx, node, key, ${name}), ${dynamic}, ${scope})`;
|
|
3940
4047
|
}
|
|
3941
4048
|
else {
|
|
3942
4049
|
blockString = `callSlot(ctx, node, key, ${slotName}, ${dynamic}, ${scope})`;
|
|
3943
4050
|
}
|
|
3944
4051
|
}
|
|
4052
|
+
// event handling
|
|
4053
|
+
if (ast.on) {
|
|
4054
|
+
blockString = this.wrapWithEventCatcher(blockString, ast.on);
|
|
4055
|
+
}
|
|
3945
4056
|
if (block) {
|
|
3946
4057
|
this.insertAnchor(block);
|
|
3947
4058
|
}
|
|
@@ -3962,7 +4073,7 @@ class CodeGenerator {
|
|
|
3962
4073
|
if (this.target.loopLevel || !this.hasSafeContext) {
|
|
3963
4074
|
ctxStr = this.generateId("ctx");
|
|
3964
4075
|
this.helpers.add("capture");
|
|
3965
|
-
this.
|
|
4076
|
+
this.define(ctxStr, `capture(ctx);`);
|
|
3966
4077
|
}
|
|
3967
4078
|
const blockString = `component(Portal, {target: ${ast.target},slots: {'default': {__render: ${name}, __ctx: ${ctxStr}}}}, key + \`${key}\`, node, ctx)`;
|
|
3968
4079
|
if (block) {
|
|
@@ -4096,8 +4207,8 @@ function parseDOMNode(node, ctx) {
|
|
|
4096
4207
|
const ref = node.getAttribute("t-ref");
|
|
4097
4208
|
node.removeAttribute("t-ref");
|
|
4098
4209
|
const nodeAttrsNames = node.getAttributeNames();
|
|
4099
|
-
|
|
4100
|
-
|
|
4210
|
+
let attrs = null;
|
|
4211
|
+
let on = null;
|
|
4101
4212
|
let model = null;
|
|
4102
4213
|
for (let attr of nodeAttrsNames) {
|
|
4103
4214
|
const value = node.getAttribute(attr);
|
|
@@ -4105,6 +4216,7 @@ function parseDOMNode(node, ctx) {
|
|
|
4105
4216
|
if (attr === "t-on") {
|
|
4106
4217
|
throw new Error("Missing event name with t-on directive");
|
|
4107
4218
|
}
|
|
4219
|
+
on = on || {};
|
|
4108
4220
|
on[attr.slice(5)] = value;
|
|
4109
4221
|
}
|
|
4110
4222
|
else if (attr.startsWith("t-model")) {
|
|
@@ -4142,6 +4254,7 @@ function parseDOMNode(node, ctx) {
|
|
|
4142
4254
|
targetAttr: isCheckboxInput ? "checked" : "value",
|
|
4143
4255
|
specialInitTargetAttr: isRadioInput ? "checked" : null,
|
|
4144
4256
|
eventType,
|
|
4257
|
+
hasDynamicChildren: false,
|
|
4145
4258
|
shouldTrim: hasTrimMod && (isOtherInput || isTextarea),
|
|
4146
4259
|
shouldNumberize: hasNumberMod && (isOtherInput || isTextarea),
|
|
4147
4260
|
};
|
|
@@ -4162,6 +4275,7 @@ function parseDOMNode(node, ctx) {
|
|
|
4162
4275
|
if (tModel && ["t-att-value", "t-attf-value"].includes(attr)) {
|
|
4163
4276
|
tModel.hasDynamicChildren = true;
|
|
4164
4277
|
}
|
|
4278
|
+
attrs = attrs || {};
|
|
4165
4279
|
attrs[attr] = value;
|
|
4166
4280
|
}
|
|
4167
4281
|
}
|
|
@@ -4312,7 +4426,7 @@ function parseTCall(node, ctx) {
|
|
|
4312
4426
|
if (ast && ast.type === 11 /* TComponent */) {
|
|
4313
4427
|
return {
|
|
4314
4428
|
...ast,
|
|
4315
|
-
slots: { default: { content: tcall } },
|
|
4429
|
+
slots: { default: { content: tcall, scope: null, on: null, attrs: null } },
|
|
4316
4430
|
};
|
|
4317
4431
|
}
|
|
4318
4432
|
}
|
|
@@ -4396,7 +4510,6 @@ function parseTSetNode(node, ctx) {
|
|
|
4396
4510
|
// -----------------------------------------------------------------------------
|
|
4397
4511
|
// Error messages when trying to use an unsupported directive on a component
|
|
4398
4512
|
const directiveErrorMap = new Map([
|
|
4399
|
-
["t-on", "t-on is no longer supported on components. Consider passing a callback in props."],
|
|
4400
4513
|
[
|
|
4401
4514
|
"t-ref",
|
|
4402
4515
|
"t-ref is no longer supported on components. Consider exposing only the public part of the component's API through a callback prop.",
|
|
@@ -4425,18 +4538,26 @@ function parseComponent(node, ctx) {
|
|
|
4425
4538
|
node.removeAttribute("t-props");
|
|
4426
4539
|
const defaultSlotScope = node.getAttribute("t-slot-scope");
|
|
4427
4540
|
node.removeAttribute("t-slot-scope");
|
|
4428
|
-
|
|
4541
|
+
let on = null;
|
|
4542
|
+
let props = null;
|
|
4429
4543
|
for (let name of node.getAttributeNames()) {
|
|
4430
4544
|
const value = node.getAttribute(name);
|
|
4431
4545
|
if (name.startsWith("t-")) {
|
|
4432
|
-
|
|
4433
|
-
|
|
4546
|
+
if (name.startsWith("t-on-")) {
|
|
4547
|
+
on = on || {};
|
|
4548
|
+
on[name.slice(5)] = value;
|
|
4549
|
+
}
|
|
4550
|
+
else {
|
|
4551
|
+
const message = directiveErrorMap.get(name.split("-").slice(0, 2).join("-"));
|
|
4552
|
+
throw new Error(message || `unsupported directive on Component: ${name}`);
|
|
4553
|
+
}
|
|
4434
4554
|
}
|
|
4435
4555
|
else {
|
|
4556
|
+
props = props || {};
|
|
4436
4557
|
props[name] = value;
|
|
4437
4558
|
}
|
|
4438
4559
|
}
|
|
4439
|
-
|
|
4560
|
+
let slots = null;
|
|
4440
4561
|
if (node.hasChildNodes()) {
|
|
4441
4562
|
const clone = node.cloneNode(true);
|
|
4442
4563
|
// named slots
|
|
@@ -4464,32 +4585,36 @@ function parseComponent(node, ctx) {
|
|
|
4464
4585
|
slotNode.remove();
|
|
4465
4586
|
const slotAst = parseNode(slotNode, ctx);
|
|
4466
4587
|
if (slotAst) {
|
|
4467
|
-
|
|
4468
|
-
|
|
4588
|
+
let on = null;
|
|
4589
|
+
let attrs = null;
|
|
4590
|
+
let scope = null;
|
|
4469
4591
|
for (let attributeName of slotNode.getAttributeNames()) {
|
|
4470
4592
|
const value = slotNode.getAttribute(attributeName);
|
|
4471
4593
|
if (attributeName === "t-slot-scope") {
|
|
4472
|
-
|
|
4594
|
+
scope = value;
|
|
4473
4595
|
continue;
|
|
4474
4596
|
}
|
|
4475
|
-
|
|
4476
|
-
|
|
4477
|
-
|
|
4478
|
-
|
|
4597
|
+
else if (attributeName.startsWith("t-on-")) {
|
|
4598
|
+
on = on || {};
|
|
4599
|
+
on[attributeName.slice(5)] = value;
|
|
4600
|
+
}
|
|
4601
|
+
else {
|
|
4602
|
+
attrs = attrs || {};
|
|
4603
|
+
attrs[attributeName] = value;
|
|
4604
|
+
}
|
|
4479
4605
|
}
|
|
4480
|
-
slots
|
|
4606
|
+
slots = slots || {};
|
|
4607
|
+
slots[name] = { content: slotAst, on, attrs, scope };
|
|
4481
4608
|
}
|
|
4482
4609
|
}
|
|
4483
4610
|
// default slot
|
|
4484
4611
|
const defaultContent = parseChildNodes(clone, ctx);
|
|
4485
4612
|
if (defaultContent) {
|
|
4486
|
-
slots
|
|
4487
|
-
|
|
4488
|
-
slots.default.scope = defaultSlotScope;
|
|
4489
|
-
}
|
|
4613
|
+
slots = slots || {};
|
|
4614
|
+
slots.default = { content: defaultContent, on, attrs: null, scope: defaultSlotScope };
|
|
4490
4615
|
}
|
|
4491
4616
|
}
|
|
4492
|
-
return { type: 11 /* TComponent */, name, isDynamic, dynamicProps, props, slots };
|
|
4617
|
+
return { type: 11 /* TComponent */, name, isDynamic, dynamicProps, props, slots, on };
|
|
4493
4618
|
}
|
|
4494
4619
|
// -----------------------------------------------------------------------------
|
|
4495
4620
|
// Slots
|
|
@@ -4500,15 +4625,24 @@ function parseTSlot(node, ctx) {
|
|
|
4500
4625
|
}
|
|
4501
4626
|
const name = node.getAttribute("t-slot");
|
|
4502
4627
|
node.removeAttribute("t-slot");
|
|
4503
|
-
|
|
4628
|
+
let attrs = null;
|
|
4629
|
+
let on = null;
|
|
4504
4630
|
for (let attributeName of node.getAttributeNames()) {
|
|
4505
4631
|
const value = node.getAttribute(attributeName);
|
|
4506
|
-
|
|
4632
|
+
if (attributeName.startsWith("t-on-")) {
|
|
4633
|
+
on = on || {};
|
|
4634
|
+
on[attributeName.slice(5)] = value;
|
|
4635
|
+
}
|
|
4636
|
+
else {
|
|
4637
|
+
attrs = attrs || {};
|
|
4638
|
+
attrs[attributeName] = value;
|
|
4639
|
+
}
|
|
4507
4640
|
}
|
|
4508
4641
|
return {
|
|
4509
4642
|
type: 14 /* TSlot */,
|
|
4510
4643
|
name,
|
|
4511
4644
|
attrs,
|
|
4645
|
+
on,
|
|
4512
4646
|
defaultContent: parseChildNodes(node, ctx),
|
|
4513
4647
|
};
|
|
4514
4648
|
}
|
|
@@ -4768,20 +4902,22 @@ function onWillRender(fn) {
|
|
|
4768
4902
|
const node = getCurrent();
|
|
4769
4903
|
const renderFn = node.renderFn;
|
|
4770
4904
|
const decorate = node.app.dev ? wrapError : (fn) => fn;
|
|
4771
|
-
|
|
4772
|
-
|
|
4905
|
+
fn = decorate(fn.bind(node.component), "onWillRender");
|
|
4906
|
+
node.renderFn = () => {
|
|
4907
|
+
fn();
|
|
4773
4908
|
return renderFn();
|
|
4774
|
-
}
|
|
4909
|
+
};
|
|
4775
4910
|
}
|
|
4776
4911
|
function onRendered(fn) {
|
|
4777
4912
|
const node = getCurrent();
|
|
4778
4913
|
const renderFn = node.renderFn;
|
|
4779
4914
|
const decorate = node.app.dev ? wrapError : (fn) => fn;
|
|
4780
|
-
|
|
4915
|
+
fn = decorate(fn.bind(node.component), "onRendered");
|
|
4916
|
+
node.renderFn = () => {
|
|
4781
4917
|
const result = renderFn();
|
|
4782
|
-
fn
|
|
4918
|
+
fn();
|
|
4783
4919
|
return result;
|
|
4784
|
-
}
|
|
4920
|
+
};
|
|
4785
4921
|
}
|
|
4786
4922
|
function onError(callback) {
|
|
4787
4923
|
const node = getCurrent();
|
|
@@ -4883,7 +5019,7 @@ function callSlot(ctx, parent, key, name, dynamic, extra, defaultContent) {
|
|
|
4883
5019
|
const { __render, __ctx, __scope } = slots[name] || {};
|
|
4884
5020
|
const slotScope = Object.create(__ctx || {});
|
|
4885
5021
|
if (__scope) {
|
|
4886
|
-
slotScope[__scope] = extra
|
|
5022
|
+
slotScope[__scope] = extra;
|
|
4887
5023
|
}
|
|
4888
5024
|
const slotBDom = __render ? __render.call(__ctx.__owl__.component, slotScope, parent, key) : null;
|
|
4889
5025
|
if (defaultContent) {
|
|
@@ -5039,6 +5175,7 @@ const helpers = {
|
|
|
5039
5175
|
LazyValue,
|
|
5040
5176
|
safeOutput,
|
|
5041
5177
|
bind,
|
|
5178
|
+
createCatcher,
|
|
5042
5179
|
};
|
|
5043
5180
|
|
|
5044
5181
|
const bdom = { text, createBlock, list, multi, html, toggler, component, comment };
|
|
@@ -5389,7 +5526,7 @@ exports.whenReady = whenReady;
|
|
|
5389
5526
|
exports.xml = xml;
|
|
5390
5527
|
|
|
5391
5528
|
|
|
5392
|
-
__info__.version = '2.0.0-beta.
|
|
5393
|
-
__info__.date = '2022-03-
|
|
5394
|
-
__info__.hash = '
|
|
5529
|
+
__info__.version = '2.0.0-beta.3';
|
|
5530
|
+
__info__.date = '2022-03-08T11:47:49.105Z';
|
|
5531
|
+
__info__.hash = 'c356351';
|
|
5395
5532
|
__info__.url = 'https://github.com/odoo/owl';
|