@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.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,45 +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
- function singleRefSetter(refs, name) {
3054
- let _el = null;
3055
- return (el) => {
3056
- if (el || refs[name] === _el) {
3057
- refs[name] = el;
3058
- _el = el;
3059
- }
3060
- };
3061
- }
3062
3030
  /**
3063
3031
  * Validate the component props (or next props) against the (static) props
3064
3032
  * description. This is potentially an expensive operation: it may needs to
@@ -3097,6 +3065,16 @@
3097
3065
  throw new OwlError(`Invalid props for component '${ComponentClass.name}': ` + errors.join(", "));
3098
3066
  }
3099
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
+ }
3100
3078
  const helpers = {
3101
3079
  withDefault,
3102
3080
  zero: Symbol("zero"),
@@ -3106,17 +3084,15 @@
3106
3084
  withKey,
3107
3085
  prepareList,
3108
3086
  setContextValue,
3109
- multiRefSetter,
3110
- singleRefSetter,
3111
3087
  shallowEqual,
3112
3088
  toNumber,
3113
3089
  validateProps,
3114
3090
  LazyValue,
3115
3091
  safeOutput,
3116
- bind,
3117
3092
  createCatcher,
3118
3093
  markRaw,
3119
3094
  OwlError,
3095
+ makeRefWrapper,
3120
3096
  };
3121
3097
 
3122
3098
  const bdom = { text, createBlock, list, multi, html, toggler, comment };
@@ -3543,6 +3519,7 @@
3543
3519
  return replaceDynamicParts(s, compileExpr);
3544
3520
  }
3545
3521
 
3522
+ const whitespaceRE = /\s+/g;
3546
3523
  // using a non-html document so that <inner/outer>HTML serializes as XML instead
3547
3524
  // of HTML (as we will parse it as xml later)
3548
3525
  const xmlDoc = document.implementation.createDocument(null, null, null);
@@ -3552,6 +3529,27 @@
3552
3529
  nextDataIds[prefix] = (nextDataIds[prefix] || 0) + 1;
3553
3530
  return prefix + nextDataIds[prefix];
3554
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
+ }
3555
3553
  // -----------------------------------------------------------------------------
3556
3554
  // BlockDescription
3557
3555
  // -----------------------------------------------------------------------------
@@ -3627,10 +3625,8 @@
3627
3625
  this.code = [];
3628
3626
  this.hasRoot = false;
3629
3627
  this.hasCache = false;
3630
- this.hasRef = false;
3631
- // maps ref name to [id, expr]
3632
- this.refInfo = {};
3633
3628
  this.shouldProtectScope = false;
3629
+ this.hasRefWrapper = false;
3634
3630
  this.name = name;
3635
3631
  this.on = on || null;
3636
3632
  }
@@ -3646,17 +3642,13 @@
3646
3642
  generateCode() {
3647
3643
  let result = [];
3648
3644
  result.push(`function ${this.name}(ctx, node, key = "") {`);
3649
- if (this.hasRef) {
3650
- result.push(` const refs = this.__owl__.refs;`);
3651
- for (let name in this.refInfo) {
3652
- const [id, expr] = this.refInfo[name];
3653
- result.push(` const ${id} = ${expr};`);
3654
- }
3655
- }
3656
3645
  if (this.shouldProtectScope) {
3657
3646
  result.push(` ctx = Object.create(ctx);`);
3658
3647
  result.push(` ctx[isBoundary] = 1`);
3659
3648
  }
3649
+ if (this.hasRefWrapper) {
3650
+ result.push(` let refWrapper = makeRefWrapper(this.__owl__);`);
3651
+ }
3660
3652
  if (this.hasCache) {
3661
3653
  result.push(` let cache = ctx.cache || {};`);
3662
3654
  result.push(` let nextCache = ctx.cache = {};`);
@@ -3938,6 +3930,9 @@
3938
3930
  const match = translationRE.exec(value);
3939
3931
  value = match[1] + this.translateFn(match[2]) + match[3];
3940
3932
  }
3933
+ if (!ctx.inPreTag) {
3934
+ value = value.replace(whitespaceRE, " ");
3935
+ }
3941
3936
  if (!block || forceNewBlock) {
3942
3937
  block = this.createBlock(block, "text", ctx);
3943
3938
  this.insertBlock(`text(\`${value}\`)`, block, {
@@ -4002,21 +3997,29 @@
4002
3997
  attrName = key === "t-att" ? null : key.slice(6);
4003
3998
  expr = compileExpr(ast.attrs[key]);
4004
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
+ }
4005
4004
  // we force a new string or new boolean to bypass the equality check in blockdom when patching same value
4006
4005
  if (attrName === "value") {
4007
- // When the expression is falsy, fall back to an empty string
4008
- 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}) || ""))`;
4009
4008
  }
4010
4009
  else {
4011
4010
  expr = `new Boolean(${expr})`;
4012
4011
  }
4013
- }
4014
- const idx = block.insertData(expr, "attr");
4015
- if (key === "t-att") {
4016
- attrs[`block-attributes`] = String(idx);
4012
+ const idx = block.insertData(expr, "prop");
4013
+ attrs[`block-property-${idx}`] = attrName;
4017
4014
  }
4018
4015
  else {
4019
- 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
+ }
4020
4023
  }
4021
4024
  }
4022
4025
  else if (this.translatableAttributes.includes(key)) {
@@ -4053,8 +4056,8 @@
4053
4056
  targetExpr = compileExpr(dynamicTgExpr);
4054
4057
  }
4055
4058
  }
4056
- idx = block.insertData(`${fullExpression} === ${targetExpr}`, "attr");
4057
- attrs[`block-attribute-${idx}`] = specialInitTargetAttr;
4059
+ idx = block.insertData(`${fullExpression} === ${targetExpr}`, "prop");
4060
+ attrs[`block-property-${idx}`] = specialInitTargetAttr;
4058
4061
  }
4059
4062
  else if (hasDynamicChildren) {
4060
4063
  const bValueId = generateId("bValue");
@@ -4062,8 +4065,8 @@
4062
4065
  this.define(tModelSelectedExpr, fullExpression);
4063
4066
  }
4064
4067
  else {
4065
- idx = block.insertData(`${fullExpression}`, "attr");
4066
- attrs[`block-attribute-${idx}`] = targetAttr;
4068
+ idx = block.insertData(`${fullExpression}`, "prop");
4069
+ attrs[`block-property-${idx}`] = targetAttr;
4067
4070
  }
4068
4071
  this.helpers.add("toNumber");
4069
4072
  let valueCode = `ev.target.${targetAttr}`;
@@ -4081,32 +4084,21 @@
4081
4084
  }
4082
4085
  // t-ref
4083
4086
  if (ast.ref) {
4084
- this.target.hasRef = true;
4087
+ if (this.dev) {
4088
+ this.helpers.add("makeRefWrapper");
4089
+ this.target.hasRefWrapper = true;
4090
+ }
4085
4091
  const isDynamic = INTERP_REGEXP.test(ast.ref);
4092
+ let name = `\`${ast.ref}\``;
4086
4093
  if (isDynamic) {
4087
- this.helpers.add("singleRefSetter");
4088
- const str = replaceDynamicParts(ast.ref, (expr) => this.captureExpression(expr, true));
4089
- const idx = block.insertData(`singleRefSetter(refs, ${str})`, "ref");
4090
- attrs["block-ref"] = String(idx);
4094
+ name = replaceDynamicParts(ast.ref, (expr) => this.captureExpression(expr, true));
4091
4095
  }
4092
- else {
4093
- let name = ast.ref;
4094
- if (name in this.target.refInfo) {
4095
- // ref has already been defined
4096
- this.helpers.add("multiRefSetter");
4097
- const info = this.target.refInfo[name];
4098
- const index = block.data.push(info[0]) - 1;
4099
- attrs["block-ref"] = String(index);
4100
- info[1] = `multiRefSetter(refs, \`${name}\`)`;
4101
- }
4102
- else {
4103
- let id = generateId("ref");
4104
- this.helpers.add("singleRefSetter");
4105
- this.target.refInfo[name] = [id, `singleRefSetter(refs, \`${name}\`)`];
4106
- const index = block.data.push(id) - 1;
4107
- attrs["block-ref"] = String(index);
4108
- }
4096
+ let setRefStr = `(el) => this.__owl__.setRef((${name}), el)`;
4097
+ if (this.dev) {
4098
+ setRefStr = `refWrapper(${name}, ${setRefStr})`;
4109
4099
  }
4100
+ const idx = block.insertData(setRefStr, "ref");
4101
+ attrs["block-ref"] = String(idx);
4110
4102
  }
4111
4103
  const dom = xmlDoc.createElement(ast.tag);
4112
4104
  for (const [attr, val] of Object.entries(attrs)) {
@@ -4129,6 +4121,7 @@
4129
4121
  tKeyExpr: ctx.tKeyExpr,
4130
4122
  nameSpace,
4131
4123
  tModelSelectedExpr,
4124
+ inPreTag: ctx.inPreTag || ast.tag === "pre",
4132
4125
  });
4133
4126
  this.compileAST(child, subCtx);
4134
4127
  }
@@ -4513,13 +4506,15 @@
4513
4506
  value = this.captureExpression(value);
4514
4507
  if (name.includes(".")) {
4515
4508
  let [_name, suffix] = name.split(".");
4516
- if (suffix === "bind") {
4517
- this.helpers.add("bind");
4518
- name = _name;
4519
- value = `bind(this, ${value || undefined})`;
4520
- }
4521
- else {
4522
- 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");
4523
4518
  }
4524
4519
  }
4525
4520
  name = /^[a-z_]+$/i.test(name) ? name : `'${name}'`;
@@ -4606,9 +4601,16 @@
4606
4601
  keyArg = `${ctx.tKeyExpr} + ${keyArg}`;
4607
4602
  }
4608
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
+ }
4609
4611
  this.staticDefs.push({
4610
4612
  id,
4611
- 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}])`,
4612
4614
  });
4613
4615
  if (ast.isDynamic) {
4614
4616
  // If the component class changes, this can cause delayed renders to go
@@ -4786,15 +4788,11 @@
4786
4788
  // Text and Comment Nodes
4787
4789
  // -----------------------------------------------------------------------------
4788
4790
  const lineBreakRE = /[\r\n]/;
4789
- const whitespaceRE = /\s+/g;
4790
4791
  function parseTextCommentNode(node, ctx) {
4791
4792
  if (node.nodeType === Node.TEXT_NODE) {
4792
4793
  let value = node.textContent || "";
4793
- if (!ctx.inPreTag) {
4794
- if (lineBreakRE.test(value) && !value.trim()) {
4795
- return null;
4796
- }
4797
- value = value.replace(whitespaceRE, " ");
4794
+ if (!ctx.inPreTag && lineBreakRE.test(value) && !value.trim()) {
4795
+ return null;
4798
4796
  }
4799
4797
  return { type: 0 /* Text */, value };
4800
4798
  }
@@ -5482,50 +5480,8 @@
5482
5480
  return new Function("app, bdom, helpers", code);
5483
5481
  }
5484
5482
 
5485
- const mainEventHandler = (data, ev, currentTarget) => {
5486
- const { data: _data, modifiers } = filterOutModifiersFromData(data);
5487
- data = _data;
5488
- let stopped = false;
5489
- if (modifiers.length) {
5490
- let selfMode = false;
5491
- const isSelf = ev.target === currentTarget;
5492
- for (const mod of modifiers) {
5493
- switch (mod) {
5494
- case "self":
5495
- selfMode = true;
5496
- if (isSelf) {
5497
- continue;
5498
- }
5499
- else {
5500
- return stopped;
5501
- }
5502
- case "prevent":
5503
- if ((selfMode && isSelf) || !selfMode)
5504
- ev.preventDefault();
5505
- continue;
5506
- case "stop":
5507
- if ((selfMode && isSelf) || !selfMode)
5508
- ev.stopPropagation();
5509
- stopped = true;
5510
- continue;
5511
- }
5512
- }
5513
- }
5514
- // If handler is empty, the array slot 0 will also be empty, and data will not have the property 0
5515
- // We check this rather than data[0] being truthy (or typeof function) so that it crashes
5516
- // as expected when there is a handler expression that evaluates to a falsy value
5517
- if (Object.hasOwnProperty.call(data, 0)) {
5518
- const handler = data[0];
5519
- if (typeof handler !== "function") {
5520
- throw new OwlError(`Invalid handler (expected a function, received: '${handler}')`);
5521
- }
5522
- let node = data[1] ? data[1].__owl__ : null;
5523
- if (node ? node.status === 1 /* MOUNTED */ : true) {
5524
- handler.call(node ? node.component : null, ev);
5525
- }
5526
- }
5527
- return stopped;
5528
- };
5483
+ // do not modify manually. This value is updated by the release script.
5484
+ const version = "2.0.8";
5529
5485
 
5530
5486
  // -----------------------------------------------------------------------------
5531
5487
  // Scheduler
@@ -5610,6 +5566,7 @@ See https://github.com/odoo/owl/blob/${hash}/doc/reference/app.md#configuration
5610
5566
  super(config);
5611
5567
  this.scheduler = new Scheduler();
5612
5568
  this.root = null;
5569
+ this.name = config.name || "";
5613
5570
  this.Root = Root;
5614
5571
  window.__OWL_DEVTOOLS__.apps.add(this);
5615
5572
  if (config.test) {
@@ -5670,21 +5627,36 @@ See https://github.com/odoo/owl/blob/${hash}/doc/reference/app.md#configuration
5670
5627
  }
5671
5628
  window.__OWL_DEVTOOLS__.apps.delete(this);
5672
5629
  }
5673
- createComponent(name, isStatic, hasSlotsProp, hasDynamicPropList, hasNoProp) {
5630
+ createComponent(name, isStatic, hasSlotsProp, hasDynamicPropList, propList) {
5674
5631
  const isDynamic = !isStatic;
5675
- function _arePropsDifferent(props1, props2) {
5676
- for (let k in props1) {
5677
- if (props1[k] !== props2[k]) {
5678
- 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
+ }
5679
5643
  }
5680
- }
5681
- 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
+ };
5682
5659
  }
5683
- const arePropsDifferent = hasSlotsProp
5684
- ? (_1, _2) => true
5685
- : hasNoProp
5686
- ? (_1, _2) => false
5687
- : _arePropsDifferent;
5688
5660
  const updateAndRender = ComponentNode.prototype.updateAndRender;
5689
5661
  const initiateRender = ComponentNode.prototype.initiateRender;
5690
5662
  return (props, key, ctx, parent, C) => {
@@ -5728,10 +5700,56 @@ See https://github.com/odoo/owl/blob/${hash}/doc/reference/app.md#configuration
5728
5700
  }
5729
5701
  }
5730
5702
  App.validateTarget = validateTarget;
5703
+ App.version = version;
5731
5704
  async function mount(C, target, config = {}) {
5732
5705
  return new App(C, config).mount(target, config);
5733
5706
  }
5734
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
+
5735
5753
  function status(component) {
5736
5754
  switch (component.__owl__.status) {
5737
5755
  case 0 /* NEW */:
@@ -5755,7 +5773,8 @@ See https://github.com/odoo/owl/blob/${hash}/doc/reference/app.md#configuration
5755
5773
  const refs = node.refs;
5756
5774
  return {
5757
5775
  get el() {
5758
- return refs[name] || null;
5776
+ const el = refs[name];
5777
+ return (el === null || el === void 0 ? void 0 : el.ownerDocument.contains(el)) ? el : null;
5759
5778
  },
5760
5779
  };
5761
5780
  }
@@ -5860,7 +5879,9 @@ See https://github.com/odoo/owl/blob/${hash}/doc/reference/app.md#configuration
5860
5879
  html,
5861
5880
  comment,
5862
5881
  };
5863
- const __info__ = {};
5882
+ const __info__ = {
5883
+ version: App.version,
5884
+ };
5864
5885
 
5865
5886
  TemplateSet.prototype._compileTemplate = function _compileTemplate(name, template) {
5866
5887
  return compile(template, {
@@ -5909,9 +5930,8 @@ See https://github.com/odoo/owl/blob/${hash}/doc/reference/app.md#configuration
5909
5930
  Object.defineProperty(exports, '__esModule', { value: true });
5910
5931
 
5911
5932
 
5912
- __info__.version = '2.0.7';
5913
- __info__.date = '2023-02-20T08:44:48.289Z';
5914
- __info__.hash = '276c8a0';
5933
+ __info__.date = '2023-03-09T12:11:34.048Z';
5934
+ __info__.hash = '532ab7f';
5915
5935
  __info__.url = 'https://github.com/odoo/owl';
5916
5936
 
5917
5937