@odoo/owl 2.0.0-beta-20 → 2.0.0-beta-22

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/README.md CHANGED
@@ -124,5 +124,5 @@ npm install @odoo/owl
124
124
 
125
125
  If you want to use a simple `<script>` tag, the last release can be downloaded here:
126
126
 
127
- - [owl-1.4.10](https://github.com/odoo/owl/releases/tag/v1.4.10)
127
+ - [owl](https://github.com/odoo/owl/releases/latest)
128
128
 
package/dist/owl.cjs.js CHANGED
@@ -676,6 +676,15 @@ function buildTree(node, parent = null, domParentTree = null) {
676
676
  : document.createElement(tagName);
677
677
  }
678
678
  if (el instanceof Element) {
679
+ if (!domParentTree) {
680
+ // some html elements may have side effects when setting their attributes.
681
+ // For example, setting the src attribute of an <img/> will trigger a
682
+ // request to get the corresponding image. This is something that we
683
+ // don't want at compile time. We avoid that by putting the content of
684
+ // the block in a <template/> element
685
+ const fragment = document.createElement("template").content;
686
+ fragment.appendChild(el);
687
+ }
679
688
  for (let i = 0; i < attrs.length; i++) {
680
689
  const attrName = attrs[i].name;
681
690
  const attrValue = attrs[i].value;
@@ -2600,67 +2609,71 @@ Component.template = "";
2600
2609
 
2601
2610
  const VText = text("").constructor;
2602
2611
  class VPortal extends VText {
2603
- constructor(selector, realBDom) {
2612
+ constructor(selector, content) {
2604
2613
  super("");
2605
2614
  this.target = null;
2606
2615
  this.selector = selector;
2607
- this.realBDom = realBDom;
2616
+ this.content = content;
2608
2617
  }
2609
2618
  mount(parent, anchor) {
2610
2619
  super.mount(parent, anchor);
2611
2620
  this.target = document.querySelector(this.selector);
2612
- if (!this.target) {
2613
- let el = this.el;
2614
- while (el && el.parentElement instanceof HTMLElement) {
2615
- el = el.parentElement;
2616
- }
2617
- this.target = el && el.querySelector(this.selector);
2618
- if (!this.target) {
2619
- throw new OwlError("invalid portal target");
2620
- }
2621
+ if (this.target) {
2622
+ this.content.mount(this.target, null);
2623
+ }
2624
+ else {
2625
+ this.content.mount(parent, anchor);
2621
2626
  }
2622
- this.realBDom.mount(this.target, null);
2623
2627
  }
2624
2628
  beforeRemove() {
2625
- this.realBDom.beforeRemove();
2629
+ this.content.beforeRemove();
2626
2630
  }
2627
2631
  remove() {
2628
- if (this.realBDom) {
2632
+ if (this.content) {
2629
2633
  super.remove();
2630
- this.realBDom.remove();
2631
- this.realBDom = null;
2634
+ this.content.remove();
2635
+ this.content = null;
2632
2636
  }
2633
2637
  }
2634
2638
  patch(other) {
2635
2639
  super.patch(other);
2636
- if (this.realBDom) {
2637
- this.realBDom.patch(other.realBDom, true);
2640
+ if (this.content) {
2641
+ this.content.patch(other.content, true);
2638
2642
  }
2639
2643
  else {
2640
- this.realBDom = other.realBDom;
2641
- this.realBDom.mount(this.target, null);
2644
+ this.content = other.content;
2645
+ this.content.mount(this.target, null);
2642
2646
  }
2643
2647
  }
2644
2648
  }
2645
2649
  /**
2646
- * <t t-slot="default"/>
2650
+ * kind of similar to <t t-slot="default"/>, but it wraps it around a VPortal
2647
2651
  */
2648
2652
  function portalTemplate(app, bdom, helpers) {
2649
2653
  let { callSlot } = helpers;
2650
2654
  return function template(ctx, node, key = "") {
2651
- return callSlot(ctx, node, key, "default", false, null);
2655
+ return new VPortal(ctx.props.target, callSlot(ctx, node, key, "default", false, null));
2652
2656
  };
2653
2657
  }
2654
2658
  class Portal extends Component {
2655
2659
  setup() {
2656
2660
  const node = this.__owl__;
2657
- const renderFn = node.renderFn;
2658
- node.renderFn = () => new VPortal(this.props.target, renderFn());
2659
- onWillUnmount(() => {
2660
- if (node.bdom) {
2661
- node.bdom.remove();
2661
+ onMounted(() => {
2662
+ const portal = node.bdom;
2663
+ if (!portal.target) {
2664
+ const target = document.querySelector(this.props.target);
2665
+ if (target) {
2666
+ portal.content.moveBefore(target, null);
2667
+ }
2668
+ else {
2669
+ throw new OwlError("invalid portal target");
2670
+ }
2662
2671
  }
2663
2672
  });
2673
+ onWillUnmount(() => {
2674
+ const portal = node.bdom;
2675
+ portal.remove();
2676
+ });
2664
2677
  }
2665
2678
  }
2666
2679
  Portal.template = "__portal__";
@@ -2894,14 +2907,15 @@ function shallowEqual(l1, l2) {
2894
2907
  return true;
2895
2908
  }
2896
2909
  class LazyValue {
2897
- constructor(fn, ctx, component, node) {
2910
+ constructor(fn, ctx, component, node, key) {
2898
2911
  this.fn = fn;
2899
2912
  this.ctx = capture(ctx);
2900
2913
  this.component = component;
2901
2914
  this.node = node;
2915
+ this.key = key;
2902
2916
  }
2903
2917
  evaluate() {
2904
- return this.fn.call(this.component, this.ctx, this.node);
2918
+ return this.fn.call(this.component, this.ctx, this.node, this.key);
2905
2919
  }
2906
2920
  toString() {
2907
2921
  return this.evaluate().toString();
@@ -2983,10 +2997,10 @@ function multiRefSetter(refs, name) {
2983
2997
  * visit recursively the props and all the children to check if they are valid.
2984
2998
  * This is why it is only done in 'dev' mode.
2985
2999
  */
2986
- function validateProps(name, props, parent) {
3000
+ function validateProps(name, props, comp) {
2987
3001
  const ComponentClass = typeof name !== "string"
2988
3002
  ? name
2989
- : parent.constructor.components[name];
3003
+ : comp.constructor.components[name];
2990
3004
  if (!ComponentClass) {
2991
3005
  // this is an error, wrong component. We silently return here instead so the
2992
3006
  // error is triggered by the usual path ('component' function)
@@ -2994,7 +3008,7 @@ function validateProps(name, props, parent) {
2994
3008
  }
2995
3009
  const schema = ComponentClass.props;
2996
3010
  if (!schema) {
2997
- if (parent.__owl__.app.warnIfNoStaticProps) {
3011
+ if (comp.__owl__.app.warnIfNoStaticProps) {
2998
3012
  console.warn(`Component '${ComponentClass.name}' does not have a static props description`);
2999
3013
  }
3000
3014
  return;
@@ -3587,6 +3601,13 @@ class CodeTarget {
3587
3601
  result.push(`}`);
3588
3602
  return result.join("\n ");
3589
3603
  }
3604
+ currentKey(ctx) {
3605
+ let key = this.loopLevel ? `key${this.loopLevel}` : "key";
3606
+ if (ctx.tKeyExpr) {
3607
+ key = `${ctx.tKeyExpr} + ${key}`;
3608
+ }
3609
+ return key;
3610
+ }
3590
3611
  }
3591
3612
  const TRANSLATABLE_ATTRS = ["label", "title", "placeholder", "alt"];
3592
3613
  const translationRE = /^(\s*)([\s\S]+?)(\s*)$/;
@@ -3716,18 +3737,14 @@ class CodeGenerator {
3716
3737
  }
3717
3738
  insertBlock(expression, block, ctx) {
3718
3739
  let blockExpr = block.generateExpr(expression);
3719
- const tKeyExpr = ctx.tKeyExpr;
3720
3740
  if (block.parentVar) {
3721
- let keyArg = `key${this.target.loopLevel}`;
3722
- if (tKeyExpr) {
3723
- keyArg = `${tKeyExpr} + ${keyArg}`;
3724
- }
3741
+ let key = this.target.currentKey(ctx);
3725
3742
  this.helpers.add("withKey");
3726
- this.addLine(`${block.parentVar}[${ctx.index}] = withKey(${blockExpr}, ${keyArg});`);
3743
+ this.addLine(`${block.parentVar}[${ctx.index}] = withKey(${blockExpr}, ${key});`);
3727
3744
  return;
3728
3745
  }
3729
- if (tKeyExpr) {
3730
- blockExpr = `toggler(${tKeyExpr}, ${blockExpr})`;
3746
+ if (ctx.tKeyExpr) {
3747
+ blockExpr = `toggler(${ctx.tKeyExpr}, ${blockExpr})`;
3731
3748
  }
3732
3749
  if (block.isRoot && !ctx.preventRoot) {
3733
3750
  if (this.target.on) {
@@ -3772,74 +3789,62 @@ class CodeGenerator {
3772
3789
  })
3773
3790
  .join("");
3774
3791
  }
3792
+ /**
3793
+ * @returns the newly created block name, if any
3794
+ */
3775
3795
  compileAST(ast, ctx) {
3776
3796
  switch (ast.type) {
3777
3797
  case 1 /* Comment */:
3778
- this.compileComment(ast, ctx);
3779
- break;
3798
+ return this.compileComment(ast, ctx);
3780
3799
  case 0 /* Text */:
3781
- this.compileText(ast, ctx);
3782
- break;
3800
+ return this.compileText(ast, ctx);
3783
3801
  case 2 /* DomNode */:
3784
- this.compileTDomNode(ast, ctx);
3785
- break;
3802
+ return this.compileTDomNode(ast, ctx);
3786
3803
  case 4 /* TEsc */:
3787
- this.compileTEsc(ast, ctx);
3788
- break;
3804
+ return this.compileTEsc(ast, ctx);
3789
3805
  case 8 /* TOut */:
3790
- this.compileTOut(ast, ctx);
3791
- break;
3806
+ return this.compileTOut(ast, ctx);
3792
3807
  case 5 /* TIf */:
3793
- this.compileTIf(ast, ctx);
3794
- break;
3808
+ return this.compileTIf(ast, ctx);
3795
3809
  case 9 /* TForEach */:
3796
- this.compileTForeach(ast, ctx);
3797
- break;
3810
+ return this.compileTForeach(ast, ctx);
3798
3811
  case 10 /* TKey */:
3799
- this.compileTKey(ast, ctx);
3800
- break;
3812
+ return this.compileTKey(ast, ctx);
3801
3813
  case 3 /* Multi */:
3802
- this.compileMulti(ast, ctx);
3803
- break;
3814
+ return this.compileMulti(ast, ctx);
3804
3815
  case 7 /* TCall */:
3805
- this.compileTCall(ast, ctx);
3806
- break;
3816
+ return this.compileTCall(ast, ctx);
3807
3817
  case 15 /* TCallBlock */:
3808
- this.compileTCallBlock(ast, ctx);
3809
- break;
3818
+ return this.compileTCallBlock(ast, ctx);
3810
3819
  case 6 /* TSet */:
3811
- this.compileTSet(ast, ctx);
3812
- break;
3820
+ return this.compileTSet(ast, ctx);
3813
3821
  case 11 /* TComponent */:
3814
- this.compileComponent(ast, ctx);
3815
- break;
3822
+ return this.compileComponent(ast, ctx);
3816
3823
  case 12 /* TDebug */:
3817
- this.compileDebug(ast, ctx);
3818
- break;
3824
+ return this.compileDebug(ast, ctx);
3819
3825
  case 13 /* TLog */:
3820
- this.compileLog(ast, ctx);
3821
- break;
3826
+ return this.compileLog(ast, ctx);
3822
3827
  case 14 /* TSlot */:
3823
- this.compileTSlot(ast, ctx);
3824
- break;
3828
+ return this.compileTSlot(ast, ctx);
3825
3829
  case 16 /* TTranslation */:
3826
- this.compileTTranslation(ast, ctx);
3827
- break;
3830
+ return this.compileTTranslation(ast, ctx);
3828
3831
  case 17 /* TPortal */:
3829
- this.compileTPortal(ast, ctx);
3832
+ return this.compileTPortal(ast, ctx);
3830
3833
  }
3831
3834
  }
3832
3835
  compileDebug(ast, ctx) {
3833
3836
  this.addLine(`debugger;`);
3834
3837
  if (ast.content) {
3835
- this.compileAST(ast.content, ctx);
3838
+ return this.compileAST(ast.content, ctx);
3836
3839
  }
3840
+ return null;
3837
3841
  }
3838
3842
  compileLog(ast, ctx) {
3839
3843
  this.addLine(`console.log(${compileExpr(ast.expr)});`);
3840
3844
  if (ast.content) {
3841
- this.compileAST(ast.content, ctx);
3845
+ return this.compileAST(ast.content, ctx);
3842
3846
  }
3847
+ return null;
3843
3848
  }
3844
3849
  compileComment(ast, ctx) {
3845
3850
  let { block, forceNewBlock } = ctx;
@@ -3855,6 +3860,7 @@ class CodeGenerator {
3855
3860
  const text = xmlDoc.createComment(ast.value);
3856
3861
  block.insert(text);
3857
3862
  }
3863
+ return block.varName;
3858
3864
  }
3859
3865
  compileText(ast, ctx) {
3860
3866
  let { block, forceNewBlock } = ctx;
@@ -3874,6 +3880,7 @@ class CodeGenerator {
3874
3880
  const createFn = ast.type === 0 /* Text */ ? xmlDoc.createTextNode : xmlDoc.createComment;
3875
3881
  block.insert(createFn.call(xmlDoc, value));
3876
3882
  }
3883
+ return block.varName;
3877
3884
  }
3878
3885
  generateHandlerCode(rawEvent, handler) {
3879
3886
  const modifiers = rawEvent
@@ -4066,6 +4073,7 @@ class CodeGenerator {
4066
4073
  this.addLine(`let ${block.children.map((c) => c.varName)};`, codeIdx);
4067
4074
  }
4068
4075
  }
4076
+ return block.varName;
4069
4077
  }
4070
4078
  compileTEsc(ast, ctx) {
4071
4079
  let { block, forceNewBlock } = ctx;
@@ -4090,6 +4098,7 @@ class CodeGenerator {
4090
4098
  const text = xmlDoc.createElement(`block-text-${idx}`);
4091
4099
  block.insert(text);
4092
4100
  }
4101
+ return block.varName;
4093
4102
  }
4094
4103
  compileTOut(ast, ctx) {
4095
4104
  let { block } = ctx;
@@ -4115,6 +4124,7 @@ class CodeGenerator {
4115
4124
  blockStr = `safeOutput(${compileExpr(ast.expr)})`;
4116
4125
  }
4117
4126
  this.insertBlock(blockStr, block, ctx);
4127
+ return block.varName;
4118
4128
  }
4119
4129
  compileTIfBranch(content, block, ctx) {
4120
4130
  this.target.indentLevel++;
@@ -4169,6 +4179,7 @@ class CodeGenerator {
4169
4179
  const args = block.children.map((c) => c.varName).join(", ");
4170
4180
  this.insertBlock(`multi([${args}])`, block, ctx);
4171
4181
  }
4182
+ return block.varName;
4172
4183
  }
4173
4184
  compileTForeach(ast, ctx) {
4174
4185
  let { block } = ctx;
@@ -4241,6 +4252,7 @@ class CodeGenerator {
4241
4252
  this.addLine(`ctx = ctx.__proto__;`);
4242
4253
  }
4243
4254
  this.insertBlock("l", block, ctx);
4255
+ return block.varName;
4244
4256
  }
4245
4257
  compileTKey(ast, ctx) {
4246
4258
  const tKeyExpr = generateId("tKey_");
@@ -4250,7 +4262,7 @@ class CodeGenerator {
4250
4262
  block: ctx.block,
4251
4263
  index: ctx.index,
4252
4264
  });
4253
- this.compileAST(ast.content, ctx);
4265
+ return this.compileAST(ast.content, ctx);
4254
4266
  }
4255
4267
  compileMulti(ast, ctx) {
4256
4268
  let { block, forceNewBlock } = ctx;
@@ -4258,11 +4270,13 @@ class CodeGenerator {
4258
4270
  let codeIdx = this.target.code.length;
4259
4271
  if (isNewBlock) {
4260
4272
  const n = ast.content.filter((c) => c.type !== 6 /* TSet */).length;
4273
+ let result = null;
4261
4274
  if (n <= 1) {
4262
4275
  for (let child of ast.content) {
4263
- this.compileAST(child, ctx);
4276
+ const blockName = this.compileAST(child, ctx);
4277
+ result = result || blockName;
4264
4278
  }
4265
- return;
4279
+ return result;
4266
4280
  }
4267
4281
  block = this.createBlock(block, "multi", ctx);
4268
4282
  }
@@ -4302,6 +4316,7 @@ class CodeGenerator {
4302
4316
  const args = block.children.map((c) => c.varName).join(", ");
4303
4317
  this.insertBlock(`multi([${args}])`, block, ctx);
4304
4318
  }
4319
+ return block.varName;
4305
4320
  }
4306
4321
  compileTCall(ast, ctx) {
4307
4322
  let { block, forceNewBlock } = ctx;
@@ -4314,12 +4329,11 @@ class CodeGenerator {
4314
4329
  this.addLine(`${ctxVar} = Object.create(${ctxVar});`);
4315
4330
  this.addLine(`${ctxVar}[isBoundary] = 1;`);
4316
4331
  this.helpers.add("isBoundary");
4317
- const nextId = BlockDescription.nextBlockId;
4318
4332
  const subCtx = createContext(ctx, { preventRoot: true, ctxVar });
4319
- this.compileAST({ type: 3 /* Multi */, content: ast.body }, subCtx);
4320
- if (nextId !== BlockDescription.nextBlockId) {
4333
+ const bl = this.compileMulti({ type: 3 /* Multi */, content: ast.body }, subCtx);
4334
+ if (bl) {
4321
4335
  this.helpers.add("zero");
4322
- this.addLine(`${ctxVar}[zero] = b${nextId};`);
4336
+ this.addLine(`${ctxVar}[zero] = ${bl};`);
4323
4337
  }
4324
4338
  }
4325
4339
  const isDynamic = INTERP_REGEXP.test(ast.name);
@@ -4354,6 +4368,7 @@ class CodeGenerator {
4354
4368
  if (ast.body && !ctx.isLast) {
4355
4369
  this.addLine(`${ctxVar} = ${ctxVar}.__proto__;`);
4356
4370
  }
4371
+ return block.varName;
4357
4372
  }
4358
4373
  compileTCallBlock(ast, ctx) {
4359
4374
  let { block, forceNewBlock } = ctx;
@@ -4364,6 +4379,7 @@ class CodeGenerator {
4364
4379
  }
4365
4380
  block = this.createBlock(block, "multi", ctx);
4366
4381
  this.insertBlock(compileExpr(ast.name), block, { ...ctx, forceNewBlock: !block });
4382
+ return block.varName;
4367
4383
  }
4368
4384
  compileTSet(ast, ctx) {
4369
4385
  this.target.shouldProtectScope = true;
@@ -4373,7 +4389,8 @@ class CodeGenerator {
4373
4389
  this.helpers.add("LazyValue");
4374
4390
  const bodyAst = { type: 3 /* Multi */, content: ast.body };
4375
4391
  const name = this.compileInNewTarget("value", bodyAst, ctx);
4376
- let value = `new LazyValue(${name}, ctx, this, node)`;
4392
+ let key = this.target.currentKey(ctx);
4393
+ let value = `new LazyValue(${name}, ctx, this, node, ${key})`;
4377
4394
  value = ast.value ? (value ? `withDefault(${expr}, ${value})` : expr) : value;
4378
4395
  this.addLine(`ctx[\`${ast.name}\`] = ${value};`);
4379
4396
  }
@@ -4393,6 +4410,7 @@ class CodeGenerator {
4393
4410
  this.helpers.add("setContextValue");
4394
4411
  this.addLine(`setContextValue(${ctx.ctxVar || "ctx"}, "${ast.name}", ${value});`);
4395
4412
  }
4413
+ return null;
4396
4414
  }
4397
4415
  generateComponentKey() {
4398
4416
  const parts = [generateId("__")];
@@ -4498,7 +4516,7 @@ class CodeGenerator {
4498
4516
  expr = `\`${ast.name}\``;
4499
4517
  }
4500
4518
  if (this.dev) {
4501
- this.addLine(`helpers.validateProps(${expr}, ${propVar}, ctx);`);
4519
+ this.addLine(`helpers.validateProps(${expr}, ${propVar}, this);`);
4502
4520
  }
4503
4521
  if (block && (ctx.forceNewBlock === false || ctx.tKeyExpr)) {
4504
4522
  // todo: check the forcenewblock condition
@@ -4523,6 +4541,7 @@ class CodeGenerator {
4523
4541
  }
4524
4542
  block = this.createBlock(block, "multi", ctx);
4525
4543
  this.insertBlock(blockExpr, block, ctx);
4544
+ return block.varName;
4526
4545
  }
4527
4546
  wrapWithEventCatcher(expr, on) {
4528
4547
  this.helpers.add("createCatcher");
@@ -4589,11 +4608,13 @@ class CodeGenerator {
4589
4608
  }
4590
4609
  block = this.createBlock(block, "multi", ctx);
4591
4610
  this.insertBlock(blockString, block, { ...ctx, forceNewBlock: false });
4611
+ return block.varName;
4592
4612
  }
4593
4613
  compileTTranslation(ast, ctx) {
4594
4614
  if (ast.content) {
4595
- this.compileAST(ast.content, Object.assign({}, ctx, { translate: false }));
4615
+ return this.compileAST(ast.content, Object.assign({}, ctx, { translate: false }));
4596
4616
  }
4617
+ return null;
4597
4618
  }
4598
4619
  compileTPortal(ast, ctx) {
4599
4620
  if (!this.staticDefs.find((d) => d.id === "Portal")) {
@@ -4620,6 +4641,7 @@ class CodeGenerator {
4620
4641
  }
4621
4642
  block = this.createBlock(block, "multi", ctx);
4622
4643
  this.insertBlock(blockString, block, { ...ctx, forceNewBlock: false });
4644
+ return block.varName;
4623
4645
  }
4624
4646
  }
4625
4647
 
@@ -5787,7 +5809,7 @@ exports.whenReady = whenReady;
5787
5809
  exports.xml = xml;
5788
5810
 
5789
5811
 
5790
- __info__.version = '2.0.0-beta-20';
5791
- __info__.date = '2022-09-09T07:26:24.123Z';
5792
- __info__.hash = 'b51756f';
5812
+ __info__.version = '2.0.0-beta-22';
5813
+ __info__.date = '2022-09-29T07:17:18.044Z';
5814
+ __info__.hash = '64bad25';
5793
5815
  __info__.url = 'https://github.com/odoo/owl';