@odoo/owl 2.2.10 → 2.3.0

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.
Binary file
package/dist/owl.cjs.js CHANGED
@@ -2626,7 +2626,7 @@ function wrapError(fn, hookName) {
2626
2626
  result.catch(() => { }),
2627
2627
  new Promise((resolve) => setTimeout(() => resolve(TIMEOUT), 3000)),
2628
2628
  ]).then((res) => {
2629
- if (res === TIMEOUT && node.fiber === fiber) {
2629
+ if (res === TIMEOUT && node.fiber === fiber && node.status <= 2) {
2630
2630
  console.warn(timeoutError);
2631
2631
  }
2632
2632
  });
@@ -3516,7 +3516,7 @@ function compileExprToArray(expr) {
3516
3516
  const localVars = new Set();
3517
3517
  const tokens = tokenize(expr);
3518
3518
  let i = 0;
3519
- let stack = []; // to track last opening [ or {
3519
+ let stack = []; // to track last opening (, [ or {
3520
3520
  while (i < tokens.length) {
3521
3521
  let token = tokens[i];
3522
3522
  let prevToken = tokens[i - 1];
@@ -3525,10 +3525,12 @@ function compileExprToArray(expr) {
3525
3525
  switch (token.type) {
3526
3526
  case "LEFT_BRACE":
3527
3527
  case "LEFT_BRACKET":
3528
+ case "LEFT_PAREN":
3528
3529
  stack.push(token.type);
3529
3530
  break;
3530
3531
  case "RIGHT_BRACE":
3531
3532
  case "RIGHT_BRACKET":
3533
+ case "RIGHT_PAREN":
3532
3534
  stack.pop();
3533
3535
  }
3534
3536
  let isVar = token.type === "SYMBOL" && !RESERVED_WORDS.includes(token.value);
@@ -3640,6 +3642,13 @@ function isProp(tag, key) {
3640
3642
  }
3641
3643
  return false;
3642
3644
  }
3645
+ /**
3646
+ * Returns a template literal that evaluates to str. You can add interpolation
3647
+ * sigils into the string if required
3648
+ */
3649
+ function toStringExpression(str) {
3650
+ return `\`${str.replace(/\\/g, "\\\\").replace(/`/g, "\\`").replace(/\$\{/, "\\${")}\``;
3651
+ }
3643
3652
  // -----------------------------------------------------------------------------
3644
3653
  // BlockDescription
3645
3654
  // -----------------------------------------------------------------------------
@@ -3820,15 +3829,14 @@ class CodeGenerator {
3820
3829
  mainCode.push(``);
3821
3830
  for (let block of this.blocks) {
3822
3831
  if (block.dom) {
3823
- let xmlString = block.asXmlString();
3824
- xmlString = xmlString.replace(/\\/g, "\\\\").replace(/`/g, "\\`");
3832
+ let xmlString = toStringExpression(block.asXmlString());
3825
3833
  if (block.dynamicTagName) {
3826
- xmlString = xmlString.replace(/^<\w+/, `<\${tag || '${block.dom.nodeName}'}`);
3827
- xmlString = xmlString.replace(/\w+>$/, `\${tag || '${block.dom.nodeName}'}>`);
3828
- mainCode.push(`let ${block.blockName} = tag => createBlock(\`${xmlString}\`);`);
3834
+ xmlString = xmlString.replace(/^`<\w+/, `\`<\${tag || '${block.dom.nodeName}'}`);
3835
+ xmlString = xmlString.replace(/\w+>`$/, `\${tag || '${block.dom.nodeName}'}>\``);
3836
+ mainCode.push(`let ${block.blockName} = tag => createBlock(${xmlString});`);
3829
3837
  }
3830
3838
  else {
3831
- mainCode.push(`let ${block.blockName} = createBlock(\`${xmlString}\`);`);
3839
+ mainCode.push(`let ${block.blockName} = createBlock(${xmlString});`);
3832
3840
  }
3833
3841
  }
3834
3842
  }
@@ -4006,7 +4014,7 @@ class CodeGenerator {
4006
4014
  const isNewBlock = !block || forceNewBlock;
4007
4015
  if (isNewBlock) {
4008
4016
  block = this.createBlock(block, "comment", ctx);
4009
- this.insertBlock(`comment(\`${ast.value}\`)`, block, {
4017
+ this.insertBlock(`comment(${toStringExpression(ast.value)})`, block, {
4010
4018
  ...ctx,
4011
4019
  forceNewBlock: forceNewBlock && !block,
4012
4020
  });
@@ -4028,7 +4036,7 @@ class CodeGenerator {
4028
4036
  }
4029
4037
  if (!block || forceNewBlock) {
4030
4038
  block = this.createBlock(block, "text", ctx);
4031
- this.insertBlock(`text(\`${value}\`)`, block, {
4039
+ this.insertBlock(`text(${toStringExpression(value)})`, block, {
4032
4040
  ...ctx,
4033
4041
  forceNewBlock: forceNewBlock && !block,
4034
4042
  });
@@ -4249,7 +4257,8 @@ class CodeGenerator {
4249
4257
  expr = compileExpr(ast.expr);
4250
4258
  if (ast.defaultValue) {
4251
4259
  this.helpers.add("withDefault");
4252
- expr = `withDefault(${expr}, \`${ast.defaultValue}\`)`;
4260
+ // FIXME: defaultValue is not translated
4261
+ expr = `withDefault(${expr}, ${toStringExpression(ast.defaultValue)})`;
4253
4262
  }
4254
4263
  }
4255
4264
  if (!block || forceNewBlock) {
@@ -4502,7 +4511,7 @@ class CodeGenerator {
4502
4511
  this.addLine(`${ctxVar}[zero] = ${bl};`);
4503
4512
  }
4504
4513
  }
4505
- const key = `key + \`${this.generateComponentKey()}\``;
4514
+ const key = this.generateComponentKey();
4506
4515
  if (isDynamic) {
4507
4516
  const templateVar = generateId("template");
4508
4517
  if (!this.staticDefs.find((d) => d.id === "call")) {
@@ -4554,12 +4563,12 @@ class CodeGenerator {
4554
4563
  else {
4555
4564
  let value;
4556
4565
  if (ast.defaultValue) {
4557
- const defaultValue = ctx.translate ? this.translate(ast.defaultValue) : ast.defaultValue;
4566
+ const defaultValue = toStringExpression(ctx.translate ? this.translate(ast.defaultValue) : ast.defaultValue);
4558
4567
  if (ast.value) {
4559
- value = `withDefault(${expr}, \`${defaultValue}\`)`;
4568
+ value = `withDefault(${expr}, ${defaultValue})`;
4560
4569
  }
4561
4570
  else {
4562
- value = `\`${defaultValue}\``;
4571
+ value = defaultValue;
4563
4572
  }
4564
4573
  }
4565
4574
  else {
@@ -4570,12 +4579,12 @@ class CodeGenerator {
4570
4579
  }
4571
4580
  return null;
4572
4581
  }
4573
- generateComponentKey() {
4582
+ generateComponentKey(currentKey = "key") {
4574
4583
  const parts = [generateId("__")];
4575
4584
  for (let i = 0; i < this.target.loopLevel; i++) {
4576
4585
  parts.push(`\${key${i + 1}}`);
4577
4586
  }
4578
- return parts.join("__");
4587
+ return `${currentKey} + \`${parts.join("__")}\``;
4579
4588
  }
4580
4589
  /**
4581
4590
  * Formats a prop name and value into a string suitable to be inserted in the
@@ -4589,7 +4598,12 @@ class CodeGenerator {
4589
4598
  * "onClick.bind" "onClick" "onClick: bind(ctx, ctx['onClick'])"
4590
4599
  */
4591
4600
  formatProp(name, value) {
4592
- value = this.captureExpression(value);
4601
+ if (name.endsWith(".translate")) {
4602
+ value = toStringExpression(this.translateFn(value));
4603
+ }
4604
+ else {
4605
+ value = this.captureExpression(value);
4606
+ }
4593
4607
  if (name.includes(".")) {
4594
4608
  let [_name, suffix] = name.split(".");
4595
4609
  name = _name;
@@ -4598,6 +4612,7 @@ class CodeGenerator {
4598
4612
  value = `(${value}).bind(this)`;
4599
4613
  break;
4600
4614
  case "alike":
4615
+ case "translate":
4601
4616
  break;
4602
4617
  default:
4603
4618
  throw new OwlError("Invalid prop suffix");
@@ -4666,7 +4681,6 @@ class CodeGenerator {
4666
4681
  this.addLine(`${propVar}.slots = markRaw(Object.assign(${slotDef}, ${propVar}.slots))`);
4667
4682
  }
4668
4683
  // cmap key
4669
- const key = this.generateComponentKey();
4670
4684
  let expr;
4671
4685
  if (ast.isDynamic) {
4672
4686
  expr = generateId("Comp");
@@ -4682,7 +4696,7 @@ class CodeGenerator {
4682
4696
  // todo: check the forcenewblock condition
4683
4697
  this.insertAnchor(block);
4684
4698
  }
4685
- let keyArg = `key + \`${key}\``;
4699
+ let keyArg = this.generateComponentKey();
4686
4700
  if (ctx.tKeyExpr) {
4687
4701
  keyArg = `${ctx.tKeyExpr} + ${keyArg}`;
4688
4702
  }
@@ -4755,7 +4769,7 @@ class CodeGenerator {
4755
4769
  }
4756
4770
  let key = this.target.loopLevel ? `key${this.target.loopLevel}` : "key";
4757
4771
  if (isMultiple) {
4758
- key = `${key} + \`${this.generateComponentKey()}\``;
4772
+ key = this.generateComponentKey(key);
4759
4773
  }
4760
4774
  const props = ast.attrs ? this.formatPropObject(ast.attrs) : [];
4761
4775
  const scope = this.getPropString(props, dynProps);
@@ -4796,7 +4810,6 @@ class CodeGenerator {
4796
4810
  }
4797
4811
  let { block } = ctx;
4798
4812
  const name = this.compileInNewTarget("slot", ast.content, ctx);
4799
- const key = this.generateComponentKey();
4800
4813
  let ctxStr = "ctx";
4801
4814
  if (this.target.loopLevel || !this.hasSafeContext) {
4802
4815
  ctxStr = generateId("ctx");
@@ -4809,7 +4822,8 @@ class CodeGenerator {
4809
4822
  expr: `app.createComponent(null, false, true, false, false)`,
4810
4823
  });
4811
4824
  const target = compileExpr(ast.target);
4812
- const blockString = `${id}({target: ${target},slots: {'default': {__render: ${name}.bind(this), __ctx: ${ctxStr}}}}, key + \`${key}\`, node, ctx, Portal)`;
4825
+ const key = this.generateComponentKey();
4826
+ const blockString = `${id}({target: ${target},slots: {'default': {__render: ${name}.bind(this), __ctx: ${ctxStr}}}}, ${key}, node, ctx, Portal)`;
4813
4827
  if (block) {
4814
4828
  this.insertAnchor(block);
4815
4829
  }
@@ -5542,7 +5556,7 @@ function compile(template, options = {}) {
5542
5556
  }
5543
5557
 
5544
5558
  // do not modify manually. This file is generated by the release script.
5545
- const version = "2.2.10";
5559
+ const version = "2.3.0";
5546
5560
 
5547
5561
  // -----------------------------------------------------------------------------
5548
5562
  // Scheduler
@@ -5973,6 +5987,7 @@ exports.Component = Component;
5973
5987
  exports.EventBus = EventBus;
5974
5988
  exports.OwlError = OwlError;
5975
5989
  exports.__info__ = __info__;
5990
+ exports.batched = batched;
5976
5991
  exports.blockDom = blockDom;
5977
5992
  exports.loadFile = loadFile;
5978
5993
  exports.markRaw = markRaw;
@@ -6005,6 +6020,6 @@ exports.whenReady = whenReady;
6005
6020
  exports.xml = xml;
6006
6021
 
6007
6022
 
6008
- __info__.date = '2024-04-02T10:25:32.577Z';
6009
- __info__.hash = '97b69f1';
6023
+ __info__.date = '2024-07-25T13:13:44.371Z';
6024
+ __info__.hash = '0cde4b8';
6010
6025
  __info__.url = 'https://github.com/odoo/owl';
package/dist/owl.es.js CHANGED
@@ -2622,7 +2622,7 @@ function wrapError(fn, hookName) {
2622
2622
  result.catch(() => { }),
2623
2623
  new Promise((resolve) => setTimeout(() => resolve(TIMEOUT), 3000)),
2624
2624
  ]).then((res) => {
2625
- if (res === TIMEOUT && node.fiber === fiber) {
2625
+ if (res === TIMEOUT && node.fiber === fiber && node.status <= 2) {
2626
2626
  console.warn(timeoutError);
2627
2627
  }
2628
2628
  });
@@ -3512,7 +3512,7 @@ function compileExprToArray(expr) {
3512
3512
  const localVars = new Set();
3513
3513
  const tokens = tokenize(expr);
3514
3514
  let i = 0;
3515
- let stack = []; // to track last opening [ or {
3515
+ let stack = []; // to track last opening (, [ or {
3516
3516
  while (i < tokens.length) {
3517
3517
  let token = tokens[i];
3518
3518
  let prevToken = tokens[i - 1];
@@ -3521,10 +3521,12 @@ function compileExprToArray(expr) {
3521
3521
  switch (token.type) {
3522
3522
  case "LEFT_BRACE":
3523
3523
  case "LEFT_BRACKET":
3524
+ case "LEFT_PAREN":
3524
3525
  stack.push(token.type);
3525
3526
  break;
3526
3527
  case "RIGHT_BRACE":
3527
3528
  case "RIGHT_BRACKET":
3529
+ case "RIGHT_PAREN":
3528
3530
  stack.pop();
3529
3531
  }
3530
3532
  let isVar = token.type === "SYMBOL" && !RESERVED_WORDS.includes(token.value);
@@ -3636,6 +3638,13 @@ function isProp(tag, key) {
3636
3638
  }
3637
3639
  return false;
3638
3640
  }
3641
+ /**
3642
+ * Returns a template literal that evaluates to str. You can add interpolation
3643
+ * sigils into the string if required
3644
+ */
3645
+ function toStringExpression(str) {
3646
+ return `\`${str.replace(/\\/g, "\\\\").replace(/`/g, "\\`").replace(/\$\{/, "\\${")}\``;
3647
+ }
3639
3648
  // -----------------------------------------------------------------------------
3640
3649
  // BlockDescription
3641
3650
  // -----------------------------------------------------------------------------
@@ -3816,15 +3825,14 @@ class CodeGenerator {
3816
3825
  mainCode.push(``);
3817
3826
  for (let block of this.blocks) {
3818
3827
  if (block.dom) {
3819
- let xmlString = block.asXmlString();
3820
- xmlString = xmlString.replace(/\\/g, "\\\\").replace(/`/g, "\\`");
3828
+ let xmlString = toStringExpression(block.asXmlString());
3821
3829
  if (block.dynamicTagName) {
3822
- xmlString = xmlString.replace(/^<\w+/, `<\${tag || '${block.dom.nodeName}'}`);
3823
- xmlString = xmlString.replace(/\w+>$/, `\${tag || '${block.dom.nodeName}'}>`);
3824
- mainCode.push(`let ${block.blockName} = tag => createBlock(\`${xmlString}\`);`);
3830
+ xmlString = xmlString.replace(/^`<\w+/, `\`<\${tag || '${block.dom.nodeName}'}`);
3831
+ xmlString = xmlString.replace(/\w+>`$/, `\${tag || '${block.dom.nodeName}'}>\``);
3832
+ mainCode.push(`let ${block.blockName} = tag => createBlock(${xmlString});`);
3825
3833
  }
3826
3834
  else {
3827
- mainCode.push(`let ${block.blockName} = createBlock(\`${xmlString}\`);`);
3835
+ mainCode.push(`let ${block.blockName} = createBlock(${xmlString});`);
3828
3836
  }
3829
3837
  }
3830
3838
  }
@@ -4002,7 +4010,7 @@ class CodeGenerator {
4002
4010
  const isNewBlock = !block || forceNewBlock;
4003
4011
  if (isNewBlock) {
4004
4012
  block = this.createBlock(block, "comment", ctx);
4005
- this.insertBlock(`comment(\`${ast.value}\`)`, block, {
4013
+ this.insertBlock(`comment(${toStringExpression(ast.value)})`, block, {
4006
4014
  ...ctx,
4007
4015
  forceNewBlock: forceNewBlock && !block,
4008
4016
  });
@@ -4024,7 +4032,7 @@ class CodeGenerator {
4024
4032
  }
4025
4033
  if (!block || forceNewBlock) {
4026
4034
  block = this.createBlock(block, "text", ctx);
4027
- this.insertBlock(`text(\`${value}\`)`, block, {
4035
+ this.insertBlock(`text(${toStringExpression(value)})`, block, {
4028
4036
  ...ctx,
4029
4037
  forceNewBlock: forceNewBlock && !block,
4030
4038
  });
@@ -4245,7 +4253,8 @@ class CodeGenerator {
4245
4253
  expr = compileExpr(ast.expr);
4246
4254
  if (ast.defaultValue) {
4247
4255
  this.helpers.add("withDefault");
4248
- expr = `withDefault(${expr}, \`${ast.defaultValue}\`)`;
4256
+ // FIXME: defaultValue is not translated
4257
+ expr = `withDefault(${expr}, ${toStringExpression(ast.defaultValue)})`;
4249
4258
  }
4250
4259
  }
4251
4260
  if (!block || forceNewBlock) {
@@ -4498,7 +4507,7 @@ class CodeGenerator {
4498
4507
  this.addLine(`${ctxVar}[zero] = ${bl};`);
4499
4508
  }
4500
4509
  }
4501
- const key = `key + \`${this.generateComponentKey()}\``;
4510
+ const key = this.generateComponentKey();
4502
4511
  if (isDynamic) {
4503
4512
  const templateVar = generateId("template");
4504
4513
  if (!this.staticDefs.find((d) => d.id === "call")) {
@@ -4550,12 +4559,12 @@ class CodeGenerator {
4550
4559
  else {
4551
4560
  let value;
4552
4561
  if (ast.defaultValue) {
4553
- const defaultValue = ctx.translate ? this.translate(ast.defaultValue) : ast.defaultValue;
4562
+ const defaultValue = toStringExpression(ctx.translate ? this.translate(ast.defaultValue) : ast.defaultValue);
4554
4563
  if (ast.value) {
4555
- value = `withDefault(${expr}, \`${defaultValue}\`)`;
4564
+ value = `withDefault(${expr}, ${defaultValue})`;
4556
4565
  }
4557
4566
  else {
4558
- value = `\`${defaultValue}\``;
4567
+ value = defaultValue;
4559
4568
  }
4560
4569
  }
4561
4570
  else {
@@ -4566,12 +4575,12 @@ class CodeGenerator {
4566
4575
  }
4567
4576
  return null;
4568
4577
  }
4569
- generateComponentKey() {
4578
+ generateComponentKey(currentKey = "key") {
4570
4579
  const parts = [generateId("__")];
4571
4580
  for (let i = 0; i < this.target.loopLevel; i++) {
4572
4581
  parts.push(`\${key${i + 1}}`);
4573
4582
  }
4574
- return parts.join("__");
4583
+ return `${currentKey} + \`${parts.join("__")}\``;
4575
4584
  }
4576
4585
  /**
4577
4586
  * Formats a prop name and value into a string suitable to be inserted in the
@@ -4585,7 +4594,12 @@ class CodeGenerator {
4585
4594
  * "onClick.bind" "onClick" "onClick: bind(ctx, ctx['onClick'])"
4586
4595
  */
4587
4596
  formatProp(name, value) {
4588
- value = this.captureExpression(value);
4597
+ if (name.endsWith(".translate")) {
4598
+ value = toStringExpression(this.translateFn(value));
4599
+ }
4600
+ else {
4601
+ value = this.captureExpression(value);
4602
+ }
4589
4603
  if (name.includes(".")) {
4590
4604
  let [_name, suffix] = name.split(".");
4591
4605
  name = _name;
@@ -4594,6 +4608,7 @@ class CodeGenerator {
4594
4608
  value = `(${value}).bind(this)`;
4595
4609
  break;
4596
4610
  case "alike":
4611
+ case "translate":
4597
4612
  break;
4598
4613
  default:
4599
4614
  throw new OwlError("Invalid prop suffix");
@@ -4662,7 +4677,6 @@ class CodeGenerator {
4662
4677
  this.addLine(`${propVar}.slots = markRaw(Object.assign(${slotDef}, ${propVar}.slots))`);
4663
4678
  }
4664
4679
  // cmap key
4665
- const key = this.generateComponentKey();
4666
4680
  let expr;
4667
4681
  if (ast.isDynamic) {
4668
4682
  expr = generateId("Comp");
@@ -4678,7 +4692,7 @@ class CodeGenerator {
4678
4692
  // todo: check the forcenewblock condition
4679
4693
  this.insertAnchor(block);
4680
4694
  }
4681
- let keyArg = `key + \`${key}\``;
4695
+ let keyArg = this.generateComponentKey();
4682
4696
  if (ctx.tKeyExpr) {
4683
4697
  keyArg = `${ctx.tKeyExpr} + ${keyArg}`;
4684
4698
  }
@@ -4751,7 +4765,7 @@ class CodeGenerator {
4751
4765
  }
4752
4766
  let key = this.target.loopLevel ? `key${this.target.loopLevel}` : "key";
4753
4767
  if (isMultiple) {
4754
- key = `${key} + \`${this.generateComponentKey()}\``;
4768
+ key = this.generateComponentKey(key);
4755
4769
  }
4756
4770
  const props = ast.attrs ? this.formatPropObject(ast.attrs) : [];
4757
4771
  const scope = this.getPropString(props, dynProps);
@@ -4792,7 +4806,6 @@ class CodeGenerator {
4792
4806
  }
4793
4807
  let { block } = ctx;
4794
4808
  const name = this.compileInNewTarget("slot", ast.content, ctx);
4795
- const key = this.generateComponentKey();
4796
4809
  let ctxStr = "ctx";
4797
4810
  if (this.target.loopLevel || !this.hasSafeContext) {
4798
4811
  ctxStr = generateId("ctx");
@@ -4805,7 +4818,8 @@ class CodeGenerator {
4805
4818
  expr: `app.createComponent(null, false, true, false, false)`,
4806
4819
  });
4807
4820
  const target = compileExpr(ast.target);
4808
- const blockString = `${id}({target: ${target},slots: {'default': {__render: ${name}.bind(this), __ctx: ${ctxStr}}}}, key + \`${key}\`, node, ctx, Portal)`;
4821
+ const key = this.generateComponentKey();
4822
+ const blockString = `${id}({target: ${target},slots: {'default': {__render: ${name}.bind(this), __ctx: ${ctxStr}}}}, ${key}, node, ctx, Portal)`;
4809
4823
  if (block) {
4810
4824
  this.insertAnchor(block);
4811
4825
  }
@@ -5538,7 +5552,7 @@ function compile(template, options = {}) {
5538
5552
  }
5539
5553
 
5540
5554
  // do not modify manually. This file is generated by the release script.
5541
- const version = "2.2.10";
5555
+ const version = "2.3.0";
5542
5556
 
5543
5557
  // -----------------------------------------------------------------------------
5544
5558
  // Scheduler
@@ -5964,9 +5978,9 @@ TemplateSet.prototype._compileTemplate = function _compileTemplate(name, templat
5964
5978
  });
5965
5979
  };
5966
5980
 
5967
- 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, validateType, whenReady, xml };
5981
+ export { App, Component, EventBus, OwlError, __info__, batched, 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, validateType, whenReady, xml };
5968
5982
 
5969
5983
 
5970
- __info__.date = '2024-04-02T10:25:32.577Z';
5971
- __info__.hash = '97b69f1';
5984
+ __info__.date = '2024-07-25T13:13:44.371Z';
5985
+ __info__.hash = '0cde4b8';
5972
5986
  __info__.url = 'https://github.com/odoo/owl';
package/dist/owl.iife.js CHANGED
@@ -2625,7 +2625,7 @@
2625
2625
  result.catch(() => { }),
2626
2626
  new Promise((resolve) => setTimeout(() => resolve(TIMEOUT), 3000)),
2627
2627
  ]).then((res) => {
2628
- if (res === TIMEOUT && node.fiber === fiber) {
2628
+ if (res === TIMEOUT && node.fiber === fiber && node.status <= 2) {
2629
2629
  console.warn(timeoutError);
2630
2630
  }
2631
2631
  });
@@ -3515,7 +3515,7 @@
3515
3515
  const localVars = new Set();
3516
3516
  const tokens = tokenize(expr);
3517
3517
  let i = 0;
3518
- let stack = []; // to track last opening [ or {
3518
+ let stack = []; // to track last opening (, [ or {
3519
3519
  while (i < tokens.length) {
3520
3520
  let token = tokens[i];
3521
3521
  let prevToken = tokens[i - 1];
@@ -3524,10 +3524,12 @@
3524
3524
  switch (token.type) {
3525
3525
  case "LEFT_BRACE":
3526
3526
  case "LEFT_BRACKET":
3527
+ case "LEFT_PAREN":
3527
3528
  stack.push(token.type);
3528
3529
  break;
3529
3530
  case "RIGHT_BRACE":
3530
3531
  case "RIGHT_BRACKET":
3532
+ case "RIGHT_PAREN":
3531
3533
  stack.pop();
3532
3534
  }
3533
3535
  let isVar = token.type === "SYMBOL" && !RESERVED_WORDS.includes(token.value);
@@ -3639,6 +3641,13 @@
3639
3641
  }
3640
3642
  return false;
3641
3643
  }
3644
+ /**
3645
+ * Returns a template literal that evaluates to str. You can add interpolation
3646
+ * sigils into the string if required
3647
+ */
3648
+ function toStringExpression(str) {
3649
+ return `\`${str.replace(/\\/g, "\\\\").replace(/`/g, "\\`").replace(/\$\{/, "\\${")}\``;
3650
+ }
3642
3651
  // -----------------------------------------------------------------------------
3643
3652
  // BlockDescription
3644
3653
  // -----------------------------------------------------------------------------
@@ -3819,15 +3828,14 @@
3819
3828
  mainCode.push(``);
3820
3829
  for (let block of this.blocks) {
3821
3830
  if (block.dom) {
3822
- let xmlString = block.asXmlString();
3823
- xmlString = xmlString.replace(/\\/g, "\\\\").replace(/`/g, "\\`");
3831
+ let xmlString = toStringExpression(block.asXmlString());
3824
3832
  if (block.dynamicTagName) {
3825
- xmlString = xmlString.replace(/^<\w+/, `<\${tag || '${block.dom.nodeName}'}`);
3826
- xmlString = xmlString.replace(/\w+>$/, `\${tag || '${block.dom.nodeName}'}>`);
3827
- mainCode.push(`let ${block.blockName} = tag => createBlock(\`${xmlString}\`);`);
3833
+ xmlString = xmlString.replace(/^`<\w+/, `\`<\${tag || '${block.dom.nodeName}'}`);
3834
+ xmlString = xmlString.replace(/\w+>`$/, `\${tag || '${block.dom.nodeName}'}>\``);
3835
+ mainCode.push(`let ${block.blockName} = tag => createBlock(${xmlString});`);
3828
3836
  }
3829
3837
  else {
3830
- mainCode.push(`let ${block.blockName} = createBlock(\`${xmlString}\`);`);
3838
+ mainCode.push(`let ${block.blockName} = createBlock(${xmlString});`);
3831
3839
  }
3832
3840
  }
3833
3841
  }
@@ -4005,7 +4013,7 @@
4005
4013
  const isNewBlock = !block || forceNewBlock;
4006
4014
  if (isNewBlock) {
4007
4015
  block = this.createBlock(block, "comment", ctx);
4008
- this.insertBlock(`comment(\`${ast.value}\`)`, block, {
4016
+ this.insertBlock(`comment(${toStringExpression(ast.value)})`, block, {
4009
4017
  ...ctx,
4010
4018
  forceNewBlock: forceNewBlock && !block,
4011
4019
  });
@@ -4027,7 +4035,7 @@
4027
4035
  }
4028
4036
  if (!block || forceNewBlock) {
4029
4037
  block = this.createBlock(block, "text", ctx);
4030
- this.insertBlock(`text(\`${value}\`)`, block, {
4038
+ this.insertBlock(`text(${toStringExpression(value)})`, block, {
4031
4039
  ...ctx,
4032
4040
  forceNewBlock: forceNewBlock && !block,
4033
4041
  });
@@ -4248,7 +4256,8 @@
4248
4256
  expr = compileExpr(ast.expr);
4249
4257
  if (ast.defaultValue) {
4250
4258
  this.helpers.add("withDefault");
4251
- expr = `withDefault(${expr}, \`${ast.defaultValue}\`)`;
4259
+ // FIXME: defaultValue is not translated
4260
+ expr = `withDefault(${expr}, ${toStringExpression(ast.defaultValue)})`;
4252
4261
  }
4253
4262
  }
4254
4263
  if (!block || forceNewBlock) {
@@ -4501,7 +4510,7 @@
4501
4510
  this.addLine(`${ctxVar}[zero] = ${bl};`);
4502
4511
  }
4503
4512
  }
4504
- const key = `key + \`${this.generateComponentKey()}\``;
4513
+ const key = this.generateComponentKey();
4505
4514
  if (isDynamic) {
4506
4515
  const templateVar = generateId("template");
4507
4516
  if (!this.staticDefs.find((d) => d.id === "call")) {
@@ -4553,12 +4562,12 @@
4553
4562
  else {
4554
4563
  let value;
4555
4564
  if (ast.defaultValue) {
4556
- const defaultValue = ctx.translate ? this.translate(ast.defaultValue) : ast.defaultValue;
4565
+ const defaultValue = toStringExpression(ctx.translate ? this.translate(ast.defaultValue) : ast.defaultValue);
4557
4566
  if (ast.value) {
4558
- value = `withDefault(${expr}, \`${defaultValue}\`)`;
4567
+ value = `withDefault(${expr}, ${defaultValue})`;
4559
4568
  }
4560
4569
  else {
4561
- value = `\`${defaultValue}\``;
4570
+ value = defaultValue;
4562
4571
  }
4563
4572
  }
4564
4573
  else {
@@ -4569,12 +4578,12 @@
4569
4578
  }
4570
4579
  return null;
4571
4580
  }
4572
- generateComponentKey() {
4581
+ generateComponentKey(currentKey = "key") {
4573
4582
  const parts = [generateId("__")];
4574
4583
  for (let i = 0; i < this.target.loopLevel; i++) {
4575
4584
  parts.push(`\${key${i + 1}}`);
4576
4585
  }
4577
- return parts.join("__");
4586
+ return `${currentKey} + \`${parts.join("__")}\``;
4578
4587
  }
4579
4588
  /**
4580
4589
  * Formats a prop name and value into a string suitable to be inserted in the
@@ -4588,7 +4597,12 @@
4588
4597
  * "onClick.bind" "onClick" "onClick: bind(ctx, ctx['onClick'])"
4589
4598
  */
4590
4599
  formatProp(name, value) {
4591
- value = this.captureExpression(value);
4600
+ if (name.endsWith(".translate")) {
4601
+ value = toStringExpression(this.translateFn(value));
4602
+ }
4603
+ else {
4604
+ value = this.captureExpression(value);
4605
+ }
4592
4606
  if (name.includes(".")) {
4593
4607
  let [_name, suffix] = name.split(".");
4594
4608
  name = _name;
@@ -4597,6 +4611,7 @@
4597
4611
  value = `(${value}).bind(this)`;
4598
4612
  break;
4599
4613
  case "alike":
4614
+ case "translate":
4600
4615
  break;
4601
4616
  default:
4602
4617
  throw new OwlError("Invalid prop suffix");
@@ -4665,7 +4680,6 @@
4665
4680
  this.addLine(`${propVar}.slots = markRaw(Object.assign(${slotDef}, ${propVar}.slots))`);
4666
4681
  }
4667
4682
  // cmap key
4668
- const key = this.generateComponentKey();
4669
4683
  let expr;
4670
4684
  if (ast.isDynamic) {
4671
4685
  expr = generateId("Comp");
@@ -4681,7 +4695,7 @@
4681
4695
  // todo: check the forcenewblock condition
4682
4696
  this.insertAnchor(block);
4683
4697
  }
4684
- let keyArg = `key + \`${key}\``;
4698
+ let keyArg = this.generateComponentKey();
4685
4699
  if (ctx.tKeyExpr) {
4686
4700
  keyArg = `${ctx.tKeyExpr} + ${keyArg}`;
4687
4701
  }
@@ -4754,7 +4768,7 @@
4754
4768
  }
4755
4769
  let key = this.target.loopLevel ? `key${this.target.loopLevel}` : "key";
4756
4770
  if (isMultiple) {
4757
- key = `${key} + \`${this.generateComponentKey()}\``;
4771
+ key = this.generateComponentKey(key);
4758
4772
  }
4759
4773
  const props = ast.attrs ? this.formatPropObject(ast.attrs) : [];
4760
4774
  const scope = this.getPropString(props, dynProps);
@@ -4795,7 +4809,6 @@
4795
4809
  }
4796
4810
  let { block } = ctx;
4797
4811
  const name = this.compileInNewTarget("slot", ast.content, ctx);
4798
- const key = this.generateComponentKey();
4799
4812
  let ctxStr = "ctx";
4800
4813
  if (this.target.loopLevel || !this.hasSafeContext) {
4801
4814
  ctxStr = generateId("ctx");
@@ -4808,7 +4821,8 @@
4808
4821
  expr: `app.createComponent(null, false, true, false, false)`,
4809
4822
  });
4810
4823
  const target = compileExpr(ast.target);
4811
- const blockString = `${id}({target: ${target},slots: {'default': {__render: ${name}.bind(this), __ctx: ${ctxStr}}}}, key + \`${key}\`, node, ctx, Portal)`;
4824
+ const key = this.generateComponentKey();
4825
+ const blockString = `${id}({target: ${target},slots: {'default': {__render: ${name}.bind(this), __ctx: ${ctxStr}}}}, ${key}, node, ctx, Portal)`;
4812
4826
  if (block) {
4813
4827
  this.insertAnchor(block);
4814
4828
  }
@@ -5541,7 +5555,7 @@
5541
5555
  }
5542
5556
 
5543
5557
  // do not modify manually. This file is generated by the release script.
5544
- const version = "2.2.10";
5558
+ const version = "2.3.0";
5545
5559
 
5546
5560
  // -----------------------------------------------------------------------------
5547
5561
  // Scheduler
@@ -5972,6 +5986,7 @@ See https://github.com/odoo/owl/blob/${hash}/doc/reference/app.md#configuration
5972
5986
  exports.EventBus = EventBus;
5973
5987
  exports.OwlError = OwlError;
5974
5988
  exports.__info__ = __info__;
5989
+ exports.batched = batched;
5975
5990
  exports.blockDom = blockDom;
5976
5991
  exports.loadFile = loadFile;
5977
5992
  exports.markRaw = markRaw;
@@ -6006,8 +6021,8 @@ See https://github.com/odoo/owl/blob/${hash}/doc/reference/app.md#configuration
6006
6021
  Object.defineProperty(exports, '__esModule', { value: true });
6007
6022
 
6008
6023
 
6009
- __info__.date = '2024-04-02T10:25:32.577Z';
6010
- __info__.hash = '97b69f1';
6024
+ __info__.date = '2024-07-25T13:13:44.371Z';
6025
+ __info__.hash = '0cde4b8';
6011
6026
  __info__.url = 'https://github.com/odoo/owl';
6012
6027
 
6013
6028