@odoo/owl 2.0.7 → 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,45 +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
- function singleRefSetter(refs, name) {
3051
- let _el = null;
3052
- return (el) => {
3053
- if (el || refs[name] === _el) {
3054
- refs[name] = el;
3055
- _el = el;
3056
- }
3057
- };
3058
- }
3059
3027
  /**
3060
3028
  * Validate the component props (or next props) against the (static) props
3061
3029
  * description. This is potentially an expensive operation: it may needs to
@@ -3094,6 +3062,16 @@ function validateProps(name, props, comp) {
3094
3062
  throw new OwlError(`Invalid props for component '${ComponentClass.name}': ` + errors.join(", "));
3095
3063
  }
3096
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
+ }
3097
3075
  const helpers = {
3098
3076
  withDefault,
3099
3077
  zero: Symbol("zero"),
@@ -3103,17 +3081,15 @@ const helpers = {
3103
3081
  withKey,
3104
3082
  prepareList,
3105
3083
  setContextValue,
3106
- multiRefSetter,
3107
- singleRefSetter,
3108
3084
  shallowEqual,
3109
3085
  toNumber,
3110
3086
  validateProps,
3111
3087
  LazyValue,
3112
3088
  safeOutput,
3113
- bind,
3114
3089
  createCatcher,
3115
3090
  markRaw,
3116
3091
  OwlError,
3092
+ makeRefWrapper,
3117
3093
  };
3118
3094
 
3119
3095
  const bdom = { text, createBlock, list, multi, html, toggler, comment };
@@ -3540,6 +3516,7 @@ function interpolate(s) {
3540
3516
  return replaceDynamicParts(s, compileExpr);
3541
3517
  }
3542
3518
 
3519
+ const whitespaceRE = /\s+/g;
3543
3520
  // using a non-html document so that <inner/outer>HTML serializes as XML instead
3544
3521
  // of HTML (as we will parse it as xml later)
3545
3522
  const xmlDoc = document.implementation.createDocument(null, null, null);
@@ -3549,6 +3526,27 @@ function generateId(prefix = "") {
3549
3526
  nextDataIds[prefix] = (nextDataIds[prefix] || 0) + 1;
3550
3527
  return prefix + nextDataIds[prefix];
3551
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
+ }
3552
3550
  // -----------------------------------------------------------------------------
3553
3551
  // BlockDescription
3554
3552
  // -----------------------------------------------------------------------------
@@ -3624,10 +3622,8 @@ class CodeTarget {
3624
3622
  this.code = [];
3625
3623
  this.hasRoot = false;
3626
3624
  this.hasCache = false;
3627
- this.hasRef = false;
3628
- // maps ref name to [id, expr]
3629
- this.refInfo = {};
3630
3625
  this.shouldProtectScope = false;
3626
+ this.hasRefWrapper = false;
3631
3627
  this.name = name;
3632
3628
  this.on = on || null;
3633
3629
  }
@@ -3643,17 +3639,13 @@ class CodeTarget {
3643
3639
  generateCode() {
3644
3640
  let result = [];
3645
3641
  result.push(`function ${this.name}(ctx, node, key = "") {`);
3646
- if (this.hasRef) {
3647
- result.push(` const refs = this.__owl__.refs;`);
3648
- for (let name in this.refInfo) {
3649
- const [id, expr] = this.refInfo[name];
3650
- result.push(` const ${id} = ${expr};`);
3651
- }
3652
- }
3653
3642
  if (this.shouldProtectScope) {
3654
3643
  result.push(` ctx = Object.create(ctx);`);
3655
3644
  result.push(` ctx[isBoundary] = 1`);
3656
3645
  }
3646
+ if (this.hasRefWrapper) {
3647
+ result.push(` let refWrapper = makeRefWrapper(this.__owl__);`);
3648
+ }
3657
3649
  if (this.hasCache) {
3658
3650
  result.push(` let cache = ctx.cache || {};`);
3659
3651
  result.push(` let nextCache = ctx.cache = {};`);
@@ -3935,6 +3927,9 @@ class CodeGenerator {
3935
3927
  const match = translationRE.exec(value);
3936
3928
  value = match[1] + this.translateFn(match[2]) + match[3];
3937
3929
  }
3930
+ if (!ctx.inPreTag) {
3931
+ value = value.replace(whitespaceRE, " ");
3932
+ }
3938
3933
  if (!block || forceNewBlock) {
3939
3934
  block = this.createBlock(block, "text", ctx);
3940
3935
  this.insertBlock(`text(\`${value}\`)`, block, {
@@ -3999,21 +3994,29 @@ class CodeGenerator {
3999
3994
  attrName = key === "t-att" ? null : key.slice(6);
4000
3995
  expr = compileExpr(ast.attrs[key]);
4001
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
+ }
4002
4001
  // we force a new string or new boolean to bypass the equality check in blockdom when patching same value
4003
4002
  if (attrName === "value") {
4004
- // When the expression is falsy, fall back to an empty string
4005
- 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}) || ""))`;
4006
4005
  }
4007
4006
  else {
4008
4007
  expr = `new Boolean(${expr})`;
4009
4008
  }
4010
- }
4011
- const idx = block.insertData(expr, "attr");
4012
- if (key === "t-att") {
4013
- attrs[`block-attributes`] = String(idx);
4009
+ const idx = block.insertData(expr, "prop");
4010
+ attrs[`block-property-${idx}`] = attrName;
4014
4011
  }
4015
4012
  else {
4016
- 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
+ }
4017
4020
  }
4018
4021
  }
4019
4022
  else if (this.translatableAttributes.includes(key)) {
@@ -4050,8 +4053,8 @@ class CodeGenerator {
4050
4053
  targetExpr = compileExpr(dynamicTgExpr);
4051
4054
  }
4052
4055
  }
4053
- idx = block.insertData(`${fullExpression} === ${targetExpr}`, "attr");
4054
- attrs[`block-attribute-${idx}`] = specialInitTargetAttr;
4056
+ idx = block.insertData(`${fullExpression} === ${targetExpr}`, "prop");
4057
+ attrs[`block-property-${idx}`] = specialInitTargetAttr;
4055
4058
  }
4056
4059
  else if (hasDynamicChildren) {
4057
4060
  const bValueId = generateId("bValue");
@@ -4059,8 +4062,8 @@ class CodeGenerator {
4059
4062
  this.define(tModelSelectedExpr, fullExpression);
4060
4063
  }
4061
4064
  else {
4062
- idx = block.insertData(`${fullExpression}`, "attr");
4063
- attrs[`block-attribute-${idx}`] = targetAttr;
4065
+ idx = block.insertData(`${fullExpression}`, "prop");
4066
+ attrs[`block-property-${idx}`] = targetAttr;
4064
4067
  }
4065
4068
  this.helpers.add("toNumber");
4066
4069
  let valueCode = `ev.target.${targetAttr}`;
@@ -4078,32 +4081,21 @@ class CodeGenerator {
4078
4081
  }
4079
4082
  // t-ref
4080
4083
  if (ast.ref) {
4081
- this.target.hasRef = true;
4084
+ if (this.dev) {
4085
+ this.helpers.add("makeRefWrapper");
4086
+ this.target.hasRefWrapper = true;
4087
+ }
4082
4088
  const isDynamic = INTERP_REGEXP.test(ast.ref);
4089
+ let name = `\`${ast.ref}\``;
4083
4090
  if (isDynamic) {
4084
- this.helpers.add("singleRefSetter");
4085
- const str = replaceDynamicParts(ast.ref, (expr) => this.captureExpression(expr, true));
4086
- const idx = block.insertData(`singleRefSetter(refs, ${str})`, "ref");
4087
- attrs["block-ref"] = String(idx);
4091
+ name = replaceDynamicParts(ast.ref, (expr) => this.captureExpression(expr, true));
4088
4092
  }
4089
- else {
4090
- let name = ast.ref;
4091
- if (name in this.target.refInfo) {
4092
- // ref has already been defined
4093
- this.helpers.add("multiRefSetter");
4094
- const info = this.target.refInfo[name];
4095
- const index = block.data.push(info[0]) - 1;
4096
- attrs["block-ref"] = String(index);
4097
- info[1] = `multiRefSetter(refs, \`${name}\`)`;
4098
- }
4099
- else {
4100
- let id = generateId("ref");
4101
- this.helpers.add("singleRefSetter");
4102
- this.target.refInfo[name] = [id, `singleRefSetter(refs, \`${name}\`)`];
4103
- const index = block.data.push(id) - 1;
4104
- attrs["block-ref"] = String(index);
4105
- }
4093
+ let setRefStr = `(el) => this.__owl__.setRef((${name}), el)`;
4094
+ if (this.dev) {
4095
+ setRefStr = `refWrapper(${name}, ${setRefStr})`;
4106
4096
  }
4097
+ const idx = block.insertData(setRefStr, "ref");
4098
+ attrs["block-ref"] = String(idx);
4107
4099
  }
4108
4100
  const dom = xmlDoc.createElement(ast.tag);
4109
4101
  for (const [attr, val] of Object.entries(attrs)) {
@@ -4126,6 +4118,7 @@ class CodeGenerator {
4126
4118
  tKeyExpr: ctx.tKeyExpr,
4127
4119
  nameSpace,
4128
4120
  tModelSelectedExpr,
4121
+ inPreTag: ctx.inPreTag || ast.tag === "pre",
4129
4122
  });
4130
4123
  this.compileAST(child, subCtx);
4131
4124
  }
@@ -4510,13 +4503,15 @@ class CodeGenerator {
4510
4503
  value = this.captureExpression(value);
4511
4504
  if (name.includes(".")) {
4512
4505
  let [_name, suffix] = name.split(".");
4513
- if (suffix === "bind") {
4514
- this.helpers.add("bind");
4515
- name = _name;
4516
- value = `bind(this, ${value || undefined})`;
4517
- }
4518
- else {
4519
- 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");
4520
4515
  }
4521
4516
  }
4522
4517
  name = /^[a-z_]+$/i.test(name) ? name : `'${name}'`;
@@ -4603,9 +4598,16 @@ class CodeGenerator {
4603
4598
  keyArg = `${ctx.tKeyExpr} + ${keyArg}`;
4604
4599
  }
4605
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
+ }
4606
4608
  this.staticDefs.push({
4607
4609
  id,
4608
- 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}])`,
4609
4611
  });
4610
4612
  if (ast.isDynamic) {
4611
4613
  // If the component class changes, this can cause delayed renders to go
@@ -4783,15 +4785,11 @@ function parseTNode(node, ctx) {
4783
4785
  // Text and Comment Nodes
4784
4786
  // -----------------------------------------------------------------------------
4785
4787
  const lineBreakRE = /[\r\n]/;
4786
- const whitespaceRE = /\s+/g;
4787
4788
  function parseTextCommentNode(node, ctx) {
4788
4789
  if (node.nodeType === Node.TEXT_NODE) {
4789
4790
  let value = node.textContent || "";
4790
- if (!ctx.inPreTag) {
4791
- if (lineBreakRE.test(value) && !value.trim()) {
4792
- return null;
4793
- }
4794
- value = value.replace(whitespaceRE, " ");
4791
+ if (!ctx.inPreTag && lineBreakRE.test(value) && !value.trim()) {
4792
+ return null;
4795
4793
  }
4796
4794
  return { type: 0 /* Text */, value };
4797
4795
  }
@@ -5479,50 +5477,8 @@ function compile(template, options = {}) {
5479
5477
  return new Function("app, bdom, helpers", code);
5480
5478
  }
5481
5479
 
5482
- const mainEventHandler = (data, ev, currentTarget) => {
5483
- const { data: _data, modifiers } = filterOutModifiersFromData(data);
5484
- data = _data;
5485
- let stopped = false;
5486
- if (modifiers.length) {
5487
- let selfMode = false;
5488
- const isSelf = ev.target === currentTarget;
5489
- for (const mod of modifiers) {
5490
- switch (mod) {
5491
- case "self":
5492
- selfMode = true;
5493
- if (isSelf) {
5494
- continue;
5495
- }
5496
- else {
5497
- return stopped;
5498
- }
5499
- case "prevent":
5500
- if ((selfMode && isSelf) || !selfMode)
5501
- ev.preventDefault();
5502
- continue;
5503
- case "stop":
5504
- if ((selfMode && isSelf) || !selfMode)
5505
- ev.stopPropagation();
5506
- stopped = true;
5507
- continue;
5508
- }
5509
- }
5510
- }
5511
- // If handler is empty, the array slot 0 will also be empty, and data will not have the property 0
5512
- // We check this rather than data[0] being truthy (or typeof function) so that it crashes
5513
- // as expected when there is a handler expression that evaluates to a falsy value
5514
- if (Object.hasOwnProperty.call(data, 0)) {
5515
- const handler = data[0];
5516
- if (typeof handler !== "function") {
5517
- throw new OwlError(`Invalid handler (expected a function, received: '${handler}')`);
5518
- }
5519
- let node = data[1] ? data[1].__owl__ : null;
5520
- if (node ? node.status === 1 /* MOUNTED */ : true) {
5521
- handler.call(node ? node.component : null, ev);
5522
- }
5523
- }
5524
- return stopped;
5525
- };
5480
+ // do not modify manually. This value is updated by the release script.
5481
+ const version = "2.0.8";
5526
5482
 
5527
5483
  // -----------------------------------------------------------------------------
5528
5484
  // Scheduler
@@ -5607,6 +5563,7 @@ class App extends TemplateSet {
5607
5563
  super(config);
5608
5564
  this.scheduler = new Scheduler();
5609
5565
  this.root = null;
5566
+ this.name = config.name || "";
5610
5567
  this.Root = Root;
5611
5568
  window.__OWL_DEVTOOLS__.apps.add(this);
5612
5569
  if (config.test) {
@@ -5667,21 +5624,36 @@ class App extends TemplateSet {
5667
5624
  }
5668
5625
  window.__OWL_DEVTOOLS__.apps.delete(this);
5669
5626
  }
5670
- createComponent(name, isStatic, hasSlotsProp, hasDynamicPropList, hasNoProp) {
5627
+ createComponent(name, isStatic, hasSlotsProp, hasDynamicPropList, propList) {
5671
5628
  const isDynamic = !isStatic;
5672
- function _arePropsDifferent(props1, props2) {
5673
- for (let k in props1) {
5674
- if (props1[k] !== props2[k]) {
5675
- 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
+ }
5676
5640
  }
5677
- }
5678
- 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
+ };
5679
5656
  }
5680
- const arePropsDifferent = hasSlotsProp
5681
- ? (_1, _2) => true
5682
- : hasNoProp
5683
- ? (_1, _2) => false
5684
- : _arePropsDifferent;
5685
5657
  const updateAndRender = ComponentNode.prototype.updateAndRender;
5686
5658
  const initiateRender = ComponentNode.prototype.initiateRender;
5687
5659
  return (props, key, ctx, parent, C) => {
@@ -5725,10 +5697,56 @@ class App extends TemplateSet {
5725
5697
  }
5726
5698
  }
5727
5699
  App.validateTarget = validateTarget;
5700
+ App.version = version;
5728
5701
  async function mount(C, target, config = {}) {
5729
5702
  return new App(C, config).mount(target, config);
5730
5703
  }
5731
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
+
5732
5750
  function status(component) {
5733
5751
  switch (component.__owl__.status) {
5734
5752
  case 0 /* NEW */:
@@ -5752,7 +5770,8 @@ function useRef(name) {
5752
5770
  const refs = node.refs;
5753
5771
  return {
5754
5772
  get el() {
5755
- return refs[name] || null;
5773
+ const el = refs[name];
5774
+ return (el === null || el === void 0 ? void 0 : el.ownerDocument.contains(el)) ? el : null;
5756
5775
  },
5757
5776
  };
5758
5777
  }
@@ -5857,7 +5876,9 @@ const blockDom = {
5857
5876
  html,
5858
5877
  comment,
5859
5878
  };
5860
- const __info__ = {};
5879
+ const __info__ = {
5880
+ version: App.version,
5881
+ };
5861
5882
 
5862
5883
  TemplateSet.prototype._compileTemplate = function _compileTemplate(name, template) {
5863
5884
  return compile(template, {
@@ -5871,7 +5892,6 @@ TemplateSet.prototype._compileTemplate = function _compileTemplate(name, templat
5871
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 };
5872
5893
 
5873
5894
 
5874
- __info__.version = '2.0.7';
5875
- __info__.date = '2023-02-20T08:44:48.289Z';
5876
- __info__.hash = '276c8a0';
5895
+ __info__.date = '2023-03-09T12:11:34.048Z';
5896
+ __info__.hash = '532ab7f';
5877
5897
  __info__.url = 'https://github.com/odoo/owl';