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