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