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