@odoo/owl 2.0.6 → 2.0.8

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
@@ -279,32 +279,6 @@
279
279
  tokenListAdd.call(cl, c);
280
280
  }
281
281
  }
282
- }
283
- function makePropSetter(name) {
284
- return function setProp(value) {
285
- // support 0, fallback to empty string for other falsy values
286
- this[name] = value === 0 ? 0 : value ? value.valueOf() : "";
287
- };
288
- }
289
- function isProp(tag, key) {
290
- switch (tag) {
291
- case "input":
292
- return (key === "checked" ||
293
- key === "indeterminate" ||
294
- key === "value" ||
295
- key === "readonly" ||
296
- key === "disabled");
297
- case "option":
298
- return key === "selected" || key === "disabled";
299
- case "textarea":
300
- return key === "value" || key === "readonly" || key === "disabled";
301
- case "select":
302
- return key === "value" || key === "disabled";
303
- case "button":
304
- case "optgroup":
305
- return key === "disabled";
306
- }
307
- return false;
308
282
  }
309
283
 
310
284
  function createEventHandler(rawEvent) {
@@ -608,6 +582,12 @@
608
582
  const nodeGetFirstChild = getDescriptor$1(nodeProto$2, "firstChild").get;
609
583
  const nodeGetNextSibling = getDescriptor$1(nodeProto$2, "nextSibling").get;
610
584
  const NO_OP = () => { };
585
+ function makePropSetter(name) {
586
+ return function setProp(value) {
587
+ // support 0, fallback to empty string for other falsy values
588
+ this[name] = value === 0 ? 0 : value ? value.valueOf() : "";
589
+ };
590
+ }
611
591
  const cache$1 = {};
612
592
  /**
613
593
  * Compiling blocks is a multi-step process:
@@ -725,6 +705,15 @@
725
705
  tag: tagName,
726
706
  });
727
707
  }
708
+ else if (attrName.startsWith("block-property-")) {
709
+ const idx = parseInt(attrName.slice(15), 10);
710
+ info.push({
711
+ type: "property",
712
+ idx,
713
+ name: attrValue,
714
+ tag: tagName,
715
+ });
716
+ }
728
717
  else if (attrName === "block-attributes") {
729
718
  info.push({
730
719
  type: "attributes",
@@ -871,16 +860,22 @@
871
860
  };
872
861
  }
873
862
  break;
863
+ case "property": {
864
+ const refIdx = info.refIdx;
865
+ const setProp = makePropSetter(info.name);
866
+ ctx.locations.push({
867
+ idx: info.idx,
868
+ refIdx,
869
+ setData: setProp,
870
+ updateData: setProp,
871
+ });
872
+ break;
873
+ }
874
874
  case "attribute": {
875
875
  const refIdx = info.refIdx;
876
876
  let updater;
877
877
  let setter;
878
- if (isProp(info.tag, info.name)) {
879
- const setProp = makePropSetter(info.name);
880
- setter = setProp;
881
- updater = setProp;
882
- }
883
- else if (info.name === "class") {
878
+ if (info.name === "class") {
884
879
  setter = setClass;
885
880
  updater = updateClass;
886
881
  }
@@ -2485,6 +2480,18 @@
2485
2480
  this.fiber = null;
2486
2481
  }
2487
2482
  }
2483
+ /**
2484
+ * Sets a ref to a given HTMLElement.
2485
+ *
2486
+ * @param name the name of the ref to set
2487
+ * @param el the HTMLElement to set the ref to. The ref is not set if the el
2488
+ * is null, but useRef will not return elements that are not in the DOM
2489
+ */
2490
+ setRef(name, el) {
2491
+ if (el) {
2492
+ this.refs[name] = el;
2493
+ }
2494
+ }
2488
2495
  // ---------------------------------------------------------------------------
2489
2496
  // Block DOM methods
2490
2497
  // ---------------------------------------------------------------------------
@@ -3020,36 +3027,6 @@
3020
3027
  }
3021
3028
  return toggler(safeKey, block);
3022
3029
  }
3023
- let boundFunctions = new WeakMap();
3024
- const WeakMapGet = WeakMap.prototype.get;
3025
- const WeakMapSet = WeakMap.prototype.set;
3026
- function bind(component, fn) {
3027
- let boundFnMap = WeakMapGet.call(boundFunctions, component);
3028
- if (!boundFnMap) {
3029
- boundFnMap = new WeakMap();
3030
- WeakMapSet.call(boundFunctions, component, boundFnMap);
3031
- }
3032
- let boundFn = WeakMapGet.call(boundFnMap, fn);
3033
- if (!boundFn) {
3034
- boundFn = fn.bind(component);
3035
- WeakMapSet.call(boundFnMap, fn, boundFn);
3036
- }
3037
- return boundFn;
3038
- }
3039
- function multiRefSetter(refs, name) {
3040
- let count = 0;
3041
- return (el) => {
3042
- if (el) {
3043
- count++;
3044
- if (count > 1) {
3045
- throw new OwlError("Cannot have 2 elements with same ref name at the same time");
3046
- }
3047
- }
3048
- if (count === 0 || el) {
3049
- refs[name] = el;
3050
- }
3051
- };
3052
- }
3053
3030
  /**
3054
3031
  * Validate the component props (or next props) against the (static) props
3055
3032
  * description. This is potentially an expensive operation: it may needs to
@@ -3088,6 +3065,16 @@
3088
3065
  throw new OwlError(`Invalid props for component '${ComponentClass.name}': ` + errors.join(", "));
3089
3066
  }
3090
3067
  }
3068
+ function makeRefWrapper(node) {
3069
+ let refNames = new Set();
3070
+ return (name, fn) => {
3071
+ if (refNames.has(name)) {
3072
+ throw new OwlError(`Cannot set the same ref more than once in the same component, ref "${name}" was set multiple times in ${node.name}`);
3073
+ }
3074
+ refNames.add(name);
3075
+ return fn;
3076
+ };
3077
+ }
3091
3078
  const helpers = {
3092
3079
  withDefault,
3093
3080
  zero: Symbol("zero"),
@@ -3097,16 +3084,15 @@
3097
3084
  withKey,
3098
3085
  prepareList,
3099
3086
  setContextValue,
3100
- multiRefSetter,
3101
3087
  shallowEqual,
3102
3088
  toNumber,
3103
3089
  validateProps,
3104
3090
  LazyValue,
3105
3091
  safeOutput,
3106
- bind,
3107
3092
  createCatcher,
3108
3093
  markRaw,
3109
3094
  OwlError,
3095
+ makeRefWrapper,
3110
3096
  };
3111
3097
 
3112
3098
  const bdom = { text, createBlock, list, multi, html, toggler, comment };
@@ -3533,6 +3519,7 @@
3533
3519
  return replaceDynamicParts(s, compileExpr);
3534
3520
  }
3535
3521
 
3522
+ const whitespaceRE = /\s+/g;
3536
3523
  // using a non-html document so that <inner/outer>HTML serializes as XML instead
3537
3524
  // of HTML (as we will parse it as xml later)
3538
3525
  const xmlDoc = document.implementation.createDocument(null, null, null);
@@ -3542,6 +3529,27 @@
3542
3529
  nextDataIds[prefix] = (nextDataIds[prefix] || 0) + 1;
3543
3530
  return prefix + nextDataIds[prefix];
3544
3531
  }
3532
+ function isProp(tag, key) {
3533
+ switch (tag) {
3534
+ case "input":
3535
+ return (key === "checked" ||
3536
+ key === "indeterminate" ||
3537
+ key === "value" ||
3538
+ key === "readonly" ||
3539
+ key === "readOnly" ||
3540
+ key === "disabled");
3541
+ case "option":
3542
+ return key === "selected" || key === "disabled";
3543
+ case "textarea":
3544
+ return key === "value" || key === "readonly" || key === "readOnly" || key === "disabled";
3545
+ case "select":
3546
+ return key === "value" || key === "disabled";
3547
+ case "button":
3548
+ case "optgroup":
3549
+ return key === "disabled";
3550
+ }
3551
+ return false;
3552
+ }
3545
3553
  // -----------------------------------------------------------------------------
3546
3554
  // BlockDescription
3547
3555
  // -----------------------------------------------------------------------------
@@ -3617,10 +3625,8 @@
3617
3625
  this.code = [];
3618
3626
  this.hasRoot = false;
3619
3627
  this.hasCache = false;
3620
- this.hasRef = false;
3621
- // maps ref name to [id, expr]
3622
- this.refInfo = {};
3623
3628
  this.shouldProtectScope = false;
3629
+ this.hasRefWrapper = false;
3624
3630
  this.name = name;
3625
3631
  this.on = on || null;
3626
3632
  }
@@ -3636,17 +3642,13 @@
3636
3642
  generateCode() {
3637
3643
  let result = [];
3638
3644
  result.push(`function ${this.name}(ctx, node, key = "") {`);
3639
- if (this.hasRef) {
3640
- result.push(` const refs = this.__owl__.refs;`);
3641
- for (let name in this.refInfo) {
3642
- const [id, expr] = this.refInfo[name];
3643
- result.push(` const ${id} = ${expr};`);
3644
- }
3645
- }
3646
3645
  if (this.shouldProtectScope) {
3647
3646
  result.push(` ctx = Object.create(ctx);`);
3648
3647
  result.push(` ctx[isBoundary] = 1`);
3649
3648
  }
3649
+ if (this.hasRefWrapper) {
3650
+ result.push(` let refWrapper = makeRefWrapper(this.__owl__);`);
3651
+ }
3650
3652
  if (this.hasCache) {
3651
3653
  result.push(` let cache = ctx.cache || {};`);
3652
3654
  result.push(` let nextCache = ctx.cache = {};`);
@@ -3928,6 +3930,9 @@
3928
3930
  const match = translationRE.exec(value);
3929
3931
  value = match[1] + this.translateFn(match[2]) + match[3];
3930
3932
  }
3933
+ if (!ctx.inPreTag) {
3934
+ value = value.replace(whitespaceRE, " ");
3935
+ }
3931
3936
  if (!block || forceNewBlock) {
3932
3937
  block = this.createBlock(block, "text", ctx);
3933
3938
  this.insertBlock(`text(\`${value}\`)`, block, {
@@ -3992,21 +3997,29 @@
3992
3997
  attrName = key === "t-att" ? null : key.slice(6);
3993
3998
  expr = compileExpr(ast.attrs[key]);
3994
3999
  if (attrName && isProp(ast.tag, attrName)) {
4000
+ if (attrName === "readonly") {
4001
+ // the property has a different name than the attribute
4002
+ attrName = "readOnly";
4003
+ }
3995
4004
  // we force a new string or new boolean to bypass the equality check in blockdom when patching same value
3996
4005
  if (attrName === "value") {
3997
- // When the expression is falsy, fall back to an empty string
3998
- expr = `new String((${expr}) || "")`;
4006
+ // When the expression is falsy (except 0), fall back to an empty string
4007
+ expr = `new String((${expr}) === 0 ? 0 : ((${expr}) || ""))`;
3999
4008
  }
4000
4009
  else {
4001
4010
  expr = `new Boolean(${expr})`;
4002
4011
  }
4003
- }
4004
- const idx = block.insertData(expr, "attr");
4005
- if (key === "t-att") {
4006
- attrs[`block-attributes`] = String(idx);
4012
+ const idx = block.insertData(expr, "prop");
4013
+ attrs[`block-property-${idx}`] = attrName;
4007
4014
  }
4008
4015
  else {
4009
- attrs[`block-attribute-${idx}`] = attrName;
4016
+ const idx = block.insertData(expr, "attr");
4017
+ if (key === "t-att") {
4018
+ attrs[`block-attributes`] = String(idx);
4019
+ }
4020
+ else {
4021
+ attrs[`block-attribute-${idx}`] = attrName;
4022
+ }
4010
4023
  }
4011
4024
  }
4012
4025
  else if (this.translatableAttributes.includes(key)) {
@@ -4043,8 +4056,8 @@
4043
4056
  targetExpr = compileExpr(dynamicTgExpr);
4044
4057
  }
4045
4058
  }
4046
- idx = block.insertData(`${fullExpression} === ${targetExpr}`, "attr");
4047
- attrs[`block-attribute-${idx}`] = specialInitTargetAttr;
4059
+ idx = block.insertData(`${fullExpression} === ${targetExpr}`, "prop");
4060
+ attrs[`block-property-${idx}`] = specialInitTargetAttr;
4048
4061
  }
4049
4062
  else if (hasDynamicChildren) {
4050
4063
  const bValueId = generateId("bValue");
@@ -4052,8 +4065,8 @@
4052
4065
  this.define(tModelSelectedExpr, fullExpression);
4053
4066
  }
4054
4067
  else {
4055
- idx = block.insertData(`${fullExpression}`, "attr");
4056
- attrs[`block-attribute-${idx}`] = targetAttr;
4068
+ idx = block.insertData(`${fullExpression}`, "prop");
4069
+ attrs[`block-property-${idx}`] = targetAttr;
4057
4070
  }
4058
4071
  this.helpers.add("toNumber");
4059
4072
  let valueCode = `ev.target.${targetAttr}`;
@@ -4071,30 +4084,21 @@
4071
4084
  }
4072
4085
  // t-ref
4073
4086
  if (ast.ref) {
4074
- this.target.hasRef = true;
4087
+ if (this.dev) {
4088
+ this.helpers.add("makeRefWrapper");
4089
+ this.target.hasRefWrapper = true;
4090
+ }
4075
4091
  const isDynamic = INTERP_REGEXP.test(ast.ref);
4092
+ let name = `\`${ast.ref}\``;
4076
4093
  if (isDynamic) {
4077
- const str = replaceDynamicParts(ast.ref, (expr) => this.captureExpression(expr, true));
4078
- const idx = block.insertData(`(el) => refs[${str}] = el`, "ref");
4079
- attrs["block-ref"] = String(idx);
4094
+ name = replaceDynamicParts(ast.ref, (expr) => this.captureExpression(expr, true));
4080
4095
  }
4081
- else {
4082
- let name = ast.ref;
4083
- if (name in this.target.refInfo) {
4084
- // ref has already been defined
4085
- this.helpers.add("multiRefSetter");
4086
- const info = this.target.refInfo[name];
4087
- const index = block.data.push(info[0]) - 1;
4088
- attrs["block-ref"] = String(index);
4089
- info[1] = `multiRefSetter(refs, \`${name}\`)`;
4090
- }
4091
- else {
4092
- let id = generateId("ref");
4093
- this.target.refInfo[name] = [id, `(el) => refs[\`${name}\`] = el`];
4094
- const index = block.data.push(id) - 1;
4095
- attrs["block-ref"] = String(index);
4096
- }
4096
+ let setRefStr = `(el) => this.__owl__.setRef((${name}), el)`;
4097
+ if (this.dev) {
4098
+ setRefStr = `refWrapper(${name}, ${setRefStr})`;
4097
4099
  }
4100
+ const idx = block.insertData(setRefStr, "ref");
4101
+ attrs["block-ref"] = String(idx);
4098
4102
  }
4099
4103
  const dom = xmlDoc.createElement(ast.tag);
4100
4104
  for (const [attr, val] of Object.entries(attrs)) {
@@ -4117,6 +4121,7 @@
4117
4121
  tKeyExpr: ctx.tKeyExpr,
4118
4122
  nameSpace,
4119
4123
  tModelSelectedExpr,
4124
+ inPreTag: ctx.inPreTag || ast.tag === "pre",
4120
4125
  });
4121
4126
  this.compileAST(child, subCtx);
4122
4127
  }
@@ -4501,13 +4506,15 @@
4501
4506
  value = this.captureExpression(value);
4502
4507
  if (name.includes(".")) {
4503
4508
  let [_name, suffix] = name.split(".");
4504
- if (suffix === "bind") {
4505
- this.helpers.add("bind");
4506
- name = _name;
4507
- value = `bind(this, ${value || undefined})`;
4508
- }
4509
- else {
4510
- throw new OwlError("Invalid prop suffix");
4509
+ name = _name;
4510
+ switch (suffix) {
4511
+ case "bind":
4512
+ value = `${value}.bind(this)`;
4513
+ break;
4514
+ case "alike":
4515
+ break;
4516
+ default:
4517
+ throw new OwlError("Invalid prop suffix");
4511
4518
  }
4512
4519
  }
4513
4520
  name = /^[a-z_]+$/i.test(name) ? name : `'${name}'`;
@@ -4594,9 +4601,16 @@
4594
4601
  keyArg = `${ctx.tKeyExpr} + ${keyArg}`;
4595
4602
  }
4596
4603
  let id = generateId("comp");
4604
+ const propList = [];
4605
+ for (let p in ast.props || {}) {
4606
+ let [name, suffix] = p.split(".");
4607
+ if (!suffix) {
4608
+ propList.push(`"${name}"`);
4609
+ }
4610
+ }
4597
4611
  this.staticDefs.push({
4598
4612
  id,
4599
- expr: `app.createComponent(${ast.isDynamic ? null : expr}, ${!ast.isDynamic}, ${!!ast.slots}, ${!!ast.dynamicProps}, ${!ast.props && !ast.dynamicProps})`,
4613
+ expr: `app.createComponent(${ast.isDynamic ? null : expr}, ${!ast.isDynamic}, ${!!ast.slots}, ${!!ast.dynamicProps}, [${propList}])`,
4600
4614
  });
4601
4615
  if (ast.isDynamic) {
4602
4616
  // If the component class changes, this can cause delayed renders to go
@@ -4774,15 +4788,11 @@
4774
4788
  // Text and Comment Nodes
4775
4789
  // -----------------------------------------------------------------------------
4776
4790
  const lineBreakRE = /[\r\n]/;
4777
- const whitespaceRE = /\s+/g;
4778
4791
  function parseTextCommentNode(node, ctx) {
4779
4792
  if (node.nodeType === Node.TEXT_NODE) {
4780
4793
  let value = node.textContent || "";
4781
- if (!ctx.inPreTag) {
4782
- if (lineBreakRE.test(value) && !value.trim()) {
4783
- return null;
4784
- }
4785
- value = value.replace(whitespaceRE, " ");
4794
+ if (!ctx.inPreTag && lineBreakRE.test(value) && !value.trim()) {
4795
+ return null;
4786
4796
  }
4787
4797
  return { type: 0 /* Text */, value };
4788
4798
  }
@@ -5470,50 +5480,8 @@
5470
5480
  return new Function("app, bdom, helpers", code);
5471
5481
  }
5472
5482
 
5473
- const mainEventHandler = (data, ev, currentTarget) => {
5474
- const { data: _data, modifiers } = filterOutModifiersFromData(data);
5475
- data = _data;
5476
- let stopped = false;
5477
- if (modifiers.length) {
5478
- let selfMode = false;
5479
- const isSelf = ev.target === currentTarget;
5480
- for (const mod of modifiers) {
5481
- switch (mod) {
5482
- case "self":
5483
- selfMode = true;
5484
- if (isSelf) {
5485
- continue;
5486
- }
5487
- else {
5488
- return stopped;
5489
- }
5490
- case "prevent":
5491
- if ((selfMode && isSelf) || !selfMode)
5492
- ev.preventDefault();
5493
- continue;
5494
- case "stop":
5495
- if ((selfMode && isSelf) || !selfMode)
5496
- ev.stopPropagation();
5497
- stopped = true;
5498
- continue;
5499
- }
5500
- }
5501
- }
5502
- // If handler is empty, the array slot 0 will also be empty, and data will not have the property 0
5503
- // We check this rather than data[0] being truthy (or typeof function) so that it crashes
5504
- // as expected when there is a handler expression that evaluates to a falsy value
5505
- if (Object.hasOwnProperty.call(data, 0)) {
5506
- const handler = data[0];
5507
- if (typeof handler !== "function") {
5508
- throw new OwlError(`Invalid handler (expected a function, received: '${handler}')`);
5509
- }
5510
- let node = data[1] ? data[1].__owl__ : null;
5511
- if (node ? node.status === 1 /* MOUNTED */ : true) {
5512
- handler.call(node ? node.component : null, ev);
5513
- }
5514
- }
5515
- return stopped;
5516
- };
5483
+ // do not modify manually. This value is updated by the release script.
5484
+ const version = "2.0.8";
5517
5485
 
5518
5486
  // -----------------------------------------------------------------------------
5519
5487
  // Scheduler
@@ -5598,6 +5566,7 @@ See https://github.com/odoo/owl/blob/${hash}/doc/reference/app.md#configuration
5598
5566
  super(config);
5599
5567
  this.scheduler = new Scheduler();
5600
5568
  this.root = null;
5569
+ this.name = config.name || "";
5601
5570
  this.Root = Root;
5602
5571
  window.__OWL_DEVTOOLS__.apps.add(this);
5603
5572
  if (config.test) {
@@ -5658,21 +5627,36 @@ See https://github.com/odoo/owl/blob/${hash}/doc/reference/app.md#configuration
5658
5627
  }
5659
5628
  window.__OWL_DEVTOOLS__.apps.delete(this);
5660
5629
  }
5661
- createComponent(name, isStatic, hasSlotsProp, hasDynamicPropList, hasNoProp) {
5630
+ createComponent(name, isStatic, hasSlotsProp, hasDynamicPropList, propList) {
5662
5631
  const isDynamic = !isStatic;
5663
- function _arePropsDifferent(props1, props2) {
5664
- for (let k in props1) {
5665
- if (props1[k] !== props2[k]) {
5666
- return true;
5632
+ let arePropsDifferent;
5633
+ const hasNoProp = propList.length === 0;
5634
+ if (hasSlotsProp) {
5635
+ arePropsDifferent = (_1, _2) => true;
5636
+ }
5637
+ else if (hasDynamicPropList) {
5638
+ arePropsDifferent = function (props1, props2) {
5639
+ for (let k in props1) {
5640
+ if (props1[k] !== props2[k]) {
5641
+ return true;
5642
+ }
5667
5643
  }
5668
- }
5669
- return hasDynamicPropList && Object.keys(props1).length !== Object.keys(props2).length;
5644
+ return Object.keys(props1).length !== Object.keys(props2).length;
5645
+ };
5646
+ }
5647
+ else if (hasNoProp) {
5648
+ arePropsDifferent = (_1, _2) => false;
5649
+ }
5650
+ else {
5651
+ arePropsDifferent = function (props1, props2) {
5652
+ for (let p of propList) {
5653
+ if (props1[p] !== props2[p]) {
5654
+ return true;
5655
+ }
5656
+ }
5657
+ return false;
5658
+ };
5670
5659
  }
5671
- const arePropsDifferent = hasSlotsProp
5672
- ? (_1, _2) => true
5673
- : hasNoProp
5674
- ? (_1, _2) => false
5675
- : _arePropsDifferent;
5676
5660
  const updateAndRender = ComponentNode.prototype.updateAndRender;
5677
5661
  const initiateRender = ComponentNode.prototype.initiateRender;
5678
5662
  return (props, key, ctx, parent, C) => {
@@ -5716,10 +5700,56 @@ See https://github.com/odoo/owl/blob/${hash}/doc/reference/app.md#configuration
5716
5700
  }
5717
5701
  }
5718
5702
  App.validateTarget = validateTarget;
5703
+ App.version = version;
5719
5704
  async function mount(C, target, config = {}) {
5720
5705
  return new App(C, config).mount(target, config);
5721
5706
  }
5722
5707
 
5708
+ const mainEventHandler = (data, ev, currentTarget) => {
5709
+ const { data: _data, modifiers } = filterOutModifiersFromData(data);
5710
+ data = _data;
5711
+ let stopped = false;
5712
+ if (modifiers.length) {
5713
+ let selfMode = false;
5714
+ const isSelf = ev.target === currentTarget;
5715
+ for (const mod of modifiers) {
5716
+ switch (mod) {
5717
+ case "self":
5718
+ selfMode = true;
5719
+ if (isSelf) {
5720
+ continue;
5721
+ }
5722
+ else {
5723
+ return stopped;
5724
+ }
5725
+ case "prevent":
5726
+ if ((selfMode && isSelf) || !selfMode)
5727
+ ev.preventDefault();
5728
+ continue;
5729
+ case "stop":
5730
+ if ((selfMode && isSelf) || !selfMode)
5731
+ ev.stopPropagation();
5732
+ stopped = true;
5733
+ continue;
5734
+ }
5735
+ }
5736
+ }
5737
+ // If handler is empty, the array slot 0 will also be empty, and data will not have the property 0
5738
+ // We check this rather than data[0] being truthy (or typeof function) so that it crashes
5739
+ // as expected when there is a handler expression that evaluates to a falsy value
5740
+ if (Object.hasOwnProperty.call(data, 0)) {
5741
+ const handler = data[0];
5742
+ if (typeof handler !== "function") {
5743
+ throw new OwlError(`Invalid handler (expected a function, received: '${handler}')`);
5744
+ }
5745
+ let node = data[1] ? data[1].__owl__ : null;
5746
+ if (node ? node.status === 1 /* MOUNTED */ : true) {
5747
+ handler.call(node ? node.component : null, ev);
5748
+ }
5749
+ }
5750
+ return stopped;
5751
+ };
5752
+
5723
5753
  function status(component) {
5724
5754
  switch (component.__owl__.status) {
5725
5755
  case 0 /* NEW */:
@@ -5743,7 +5773,8 @@ See https://github.com/odoo/owl/blob/${hash}/doc/reference/app.md#configuration
5743
5773
  const refs = node.refs;
5744
5774
  return {
5745
5775
  get el() {
5746
- return refs[name] || null;
5776
+ const el = refs[name];
5777
+ return (el === null || el === void 0 ? void 0 : el.ownerDocument.contains(el)) ? el : null;
5747
5778
  },
5748
5779
  };
5749
5780
  }
@@ -5848,7 +5879,9 @@ See https://github.com/odoo/owl/blob/${hash}/doc/reference/app.md#configuration
5848
5879
  html,
5849
5880
  comment,
5850
5881
  };
5851
- const __info__ = {};
5882
+ const __info__ = {
5883
+ version: App.version,
5884
+ };
5852
5885
 
5853
5886
  TemplateSet.prototype._compileTemplate = function _compileTemplate(name, template) {
5854
5887
  return compile(template, {
@@ -5897,9 +5930,8 @@ See https://github.com/odoo/owl/blob/${hash}/doc/reference/app.md#configuration
5897
5930
  Object.defineProperty(exports, '__esModule', { value: true });
5898
5931
 
5899
5932
 
5900
- __info__.version = '2.0.6';
5901
- __info__.date = '2023-02-17T13:31:28.150Z';
5902
- __info__.hash = '1291f1f';
5933
+ __info__.date = '2023-03-09T12:11:34.048Z';
5934
+ __info__.hash = '532ab7f';
5903
5935
  __info__.url = 'https://github.com/odoo/owl';
5904
5936
 
5905
5937