@odoo/owl 2.5.3 → 2.6.1
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/compile_templates.mjs +107 -23
- package/dist/owl-devtools.zip +0 -0
- package/dist/owl.cjs.js +111 -34
- package/dist/owl.es.js +111 -34
- package/dist/owl.iife.js +111 -34
- package/dist/owl.iife.min.js +1 -1
- package/dist/types/compiler/code_generator.d.ts +12 -6
- package/dist/types/compiler/parser.d.ts +14 -2
- package/dist/types/owl.d.ts +3 -3
- package/dist/types/runtime/app.d.ts +0 -1
- package/dist/types/runtime/template_set.d.ts +2 -2
- package/dist/types/version.d.ts +1 -1
- package/package.json +1 -1
package/dist/owl.es.js
CHANGED
|
@@ -3738,6 +3738,7 @@ function createContext(parentCtx, params) {
|
|
|
3738
3738
|
index: 0,
|
|
3739
3739
|
forceNewBlock: true,
|
|
3740
3740
|
translate: parentCtx.translate,
|
|
3741
|
+
translationCtx: parentCtx.translationCtx,
|
|
3741
3742
|
tKeyExpr: null,
|
|
3742
3743
|
nameSpace: parentCtx.nameSpace,
|
|
3743
3744
|
tModelSelectedExpr: parentCtx.tModelSelectedExpr,
|
|
@@ -3840,6 +3841,7 @@ class CodeGenerator {
|
|
|
3840
3841
|
forceNewBlock: false,
|
|
3841
3842
|
isLast: true,
|
|
3842
3843
|
translate: true,
|
|
3844
|
+
translationCtx: "",
|
|
3843
3845
|
tKeyExpr: null,
|
|
3844
3846
|
});
|
|
3845
3847
|
// define blocks and utility functions
|
|
@@ -3977,9 +3979,9 @@ class CodeGenerator {
|
|
|
3977
3979
|
})
|
|
3978
3980
|
.join("");
|
|
3979
3981
|
}
|
|
3980
|
-
translate(str) {
|
|
3982
|
+
translate(str, translationCtx) {
|
|
3981
3983
|
const match = translationRE.exec(str);
|
|
3982
|
-
return match[1] + this.translateFn(match[2]) + match[3];
|
|
3984
|
+
return match[1] + this.translateFn(match[2], translationCtx) + match[3];
|
|
3983
3985
|
}
|
|
3984
3986
|
/**
|
|
3985
3987
|
* @returns the newly created block name, if any
|
|
@@ -4020,7 +4022,9 @@ class CodeGenerator {
|
|
|
4020
4022
|
return this.compileTSlot(ast, ctx);
|
|
4021
4023
|
case 16 /* TTranslation */:
|
|
4022
4024
|
return this.compileTTranslation(ast, ctx);
|
|
4023
|
-
case 17 /*
|
|
4025
|
+
case 17 /* TTranslationContext */:
|
|
4026
|
+
return this.compileTTranslationContext(ast, ctx);
|
|
4027
|
+
case 18 /* TPortal */:
|
|
4024
4028
|
return this.compileTPortal(ast, ctx);
|
|
4025
4029
|
}
|
|
4026
4030
|
}
|
|
@@ -4058,7 +4062,7 @@ class CodeGenerator {
|
|
|
4058
4062
|
let { block, forceNewBlock } = ctx;
|
|
4059
4063
|
let value = ast.value;
|
|
4060
4064
|
if (value && ctx.translate !== false) {
|
|
4061
|
-
value = this.translate(value);
|
|
4065
|
+
value = this.translate(value, ctx.translationCtx);
|
|
4062
4066
|
}
|
|
4063
4067
|
if (!ctx.inPreTag) {
|
|
4064
4068
|
value = value.replace(whitespaceRE, " ");
|
|
@@ -4093,6 +4097,7 @@ class CodeGenerator {
|
|
|
4093
4097
|
return `[${modifiersCode}${this.captureExpression(handler)}, ctx]`;
|
|
4094
4098
|
}
|
|
4095
4099
|
compileTDomNode(ast, ctx) {
|
|
4100
|
+
var _a;
|
|
4096
4101
|
let { block, forceNewBlock } = ctx;
|
|
4097
4102
|
const isNewBlock = !block || forceNewBlock || ast.dynamicTag !== null || ast.ns;
|
|
4098
4103
|
let codeIdx = this.target.code.length;
|
|
@@ -4148,7 +4153,8 @@ class CodeGenerator {
|
|
|
4148
4153
|
}
|
|
4149
4154
|
}
|
|
4150
4155
|
else if (this.translatableAttributes.includes(key)) {
|
|
4151
|
-
|
|
4156
|
+
const attrTranslationCtx = ((_a = ast.attrsTranslationCtx) === null || _a === void 0 ? void 0 : _a[key]) || ctx.translationCtx;
|
|
4157
|
+
attrs[key] = this.translateFn(ast.attrs[key], attrTranslationCtx);
|
|
4152
4158
|
}
|
|
4153
4159
|
else {
|
|
4154
4160
|
expr = `"${ast.attrs[key]}"`;
|
|
@@ -4592,7 +4598,7 @@ class CodeGenerator {
|
|
|
4592
4598
|
else {
|
|
4593
4599
|
let value;
|
|
4594
4600
|
if (ast.defaultValue) {
|
|
4595
|
-
const defaultValue = toStringExpression(ctx.translate ? this.translate(ast.defaultValue) : ast.defaultValue);
|
|
4601
|
+
const defaultValue = toStringExpression(ctx.translate ? this.translate(ast.defaultValue, ctx.translationCtx) : ast.defaultValue);
|
|
4596
4602
|
if (ast.value) {
|
|
4597
4603
|
value = `withDefault(${expr}, ${defaultValue})`;
|
|
4598
4604
|
}
|
|
@@ -4626,9 +4632,10 @@ class CodeGenerator {
|
|
|
4626
4632
|
* "some-prop" "state" "'some-prop': ctx['state']"
|
|
4627
4633
|
* "onClick.bind" "onClick" "onClick: bind(ctx, ctx['onClick'])"
|
|
4628
4634
|
*/
|
|
4629
|
-
formatProp(name, value) {
|
|
4635
|
+
formatProp(name, value, attrsTranslationCtx, translationCtx) {
|
|
4630
4636
|
if (name.endsWith(".translate")) {
|
|
4631
|
-
|
|
4637
|
+
const attrTranslationCtx = (attrsTranslationCtx === null || attrsTranslationCtx === void 0 ? void 0 : attrsTranslationCtx[name]) || translationCtx;
|
|
4638
|
+
value = toStringExpression(this.translateFn(value, attrTranslationCtx));
|
|
4632
4639
|
}
|
|
4633
4640
|
else {
|
|
4634
4641
|
value = this.captureExpression(value);
|
|
@@ -4650,8 +4657,8 @@ class CodeGenerator {
|
|
|
4650
4657
|
name = /^[a-z_]+$/i.test(name) ? name : `'${name}'`;
|
|
4651
4658
|
return `${name}: ${value || undefined}`;
|
|
4652
4659
|
}
|
|
4653
|
-
formatPropObject(obj) {
|
|
4654
|
-
return Object.entries(obj).map(([k, v]) => this.formatProp(k, v));
|
|
4660
|
+
formatPropObject(obj, attrsTranslationCtx, translationCtx) {
|
|
4661
|
+
return Object.entries(obj).map(([k, v]) => this.formatProp(k, v, attrsTranslationCtx, translationCtx));
|
|
4655
4662
|
}
|
|
4656
4663
|
getPropString(props, dynProps) {
|
|
4657
4664
|
let propString = `{${props.join(",")}}`;
|
|
@@ -4664,7 +4671,9 @@ class CodeGenerator {
|
|
|
4664
4671
|
let { block } = ctx;
|
|
4665
4672
|
// props
|
|
4666
4673
|
const hasSlotsProp = "slots" in (ast.props || {});
|
|
4667
|
-
const props = ast.props
|
|
4674
|
+
const props = ast.props
|
|
4675
|
+
? this.formatPropObject(ast.props, ast.propsTranslationCtx, ctx.translationCtx)
|
|
4676
|
+
: [];
|
|
4668
4677
|
// slots
|
|
4669
4678
|
let slotDef = "";
|
|
4670
4679
|
if (ast.slots) {
|
|
@@ -4687,7 +4696,7 @@ class CodeGenerator {
|
|
|
4687
4696
|
params.push(`__scope: "${scope}"`);
|
|
4688
4697
|
}
|
|
4689
4698
|
if (ast.slots[slotName].attrs) {
|
|
4690
|
-
params.push(...this.formatPropObject(ast.slots[slotName].attrs));
|
|
4699
|
+
params.push(...this.formatPropObject(ast.slots[slotName].attrs, ast.slots[slotName].attrsTranslationCtx, ctx.translationCtx));
|
|
4691
4700
|
}
|
|
4692
4701
|
const slotInfo = `{${params.join(", ")}}`;
|
|
4693
4702
|
slotStr.push(`'${slotName}': ${slotInfo}`);
|
|
@@ -4792,15 +4801,16 @@ class CodeGenerator {
|
|
|
4792
4801
|
isMultiple = isMultiple || this.slotNames.has(ast.name);
|
|
4793
4802
|
this.slotNames.add(ast.name);
|
|
4794
4803
|
}
|
|
4795
|
-
const
|
|
4796
|
-
|
|
4797
|
-
|
|
4798
|
-
}
|
|
4804
|
+
const attrs = { ...ast.attrs };
|
|
4805
|
+
const dynProps = attrs["t-props"];
|
|
4806
|
+
delete attrs["t-props"];
|
|
4799
4807
|
let key = this.target.loopLevel ? `key${this.target.loopLevel}` : "key";
|
|
4800
4808
|
if (isMultiple) {
|
|
4801
4809
|
key = this.generateComponentKey(key);
|
|
4802
4810
|
}
|
|
4803
|
-
const props = ast.attrs
|
|
4811
|
+
const props = ast.attrs
|
|
4812
|
+
? this.formatPropObject(attrs, ast.attrsTranslationCtx, ctx.translationCtx)
|
|
4813
|
+
: [];
|
|
4804
4814
|
const scope = this.getPropString(props, dynProps);
|
|
4805
4815
|
if (ast.defaultContent) {
|
|
4806
4816
|
const name = this.compileInNewTarget("defaultContent", ast.defaultContent, ctx);
|
|
@@ -4833,6 +4843,12 @@ class CodeGenerator {
|
|
|
4833
4843
|
}
|
|
4834
4844
|
return null;
|
|
4835
4845
|
}
|
|
4846
|
+
compileTTranslationContext(ast, ctx) {
|
|
4847
|
+
if (ast.content) {
|
|
4848
|
+
return this.compileAST(ast.content, Object.assign({}, ctx, { translationCtx: ast.translationCtx }));
|
|
4849
|
+
}
|
|
4850
|
+
return null;
|
|
4851
|
+
}
|
|
4836
4852
|
compileTPortal(ast, ctx) {
|
|
4837
4853
|
if (!this.staticDefs.find((d) => d.id === "Portal")) {
|
|
4838
4854
|
this.staticDefs.push({ id: "Portal", expr: `app.Portal` });
|
|
@@ -4902,6 +4918,7 @@ function parseNode(node, ctx) {
|
|
|
4902
4918
|
parseTOutNode(node, ctx) ||
|
|
4903
4919
|
parseTKey(node, ctx) ||
|
|
4904
4920
|
parseTTranslation(node, ctx) ||
|
|
4921
|
+
parseTTranslationContext(node, ctx) ||
|
|
4905
4922
|
parseTSlot(node, ctx) ||
|
|
4906
4923
|
parseComponent(node, ctx) ||
|
|
4907
4924
|
parseDOMNode(node, ctx) ||
|
|
@@ -5010,6 +5027,7 @@ function parseDOMNode(node, ctx) {
|
|
|
5010
5027
|
node.removeAttribute("t-ref");
|
|
5011
5028
|
const nodeAttrsNames = node.getAttributeNames();
|
|
5012
5029
|
let attrs = null;
|
|
5030
|
+
let attrsTranslationCtx = null;
|
|
5013
5031
|
let on = null;
|
|
5014
5032
|
let model = null;
|
|
5015
5033
|
for (let attr of nodeAttrsNames) {
|
|
@@ -5070,6 +5088,11 @@ function parseDOMNode(node, ctx) {
|
|
|
5070
5088
|
else if (attr === "xmlns") {
|
|
5071
5089
|
ns = value;
|
|
5072
5090
|
}
|
|
5091
|
+
else if (attr.startsWith("t-translation-context-")) {
|
|
5092
|
+
const attrName = attr.slice(22);
|
|
5093
|
+
attrsTranslationCtx = attrsTranslationCtx || {};
|
|
5094
|
+
attrsTranslationCtx[attrName] = value;
|
|
5095
|
+
}
|
|
5073
5096
|
else if (attr !== "t-name") {
|
|
5074
5097
|
if (attr.startsWith("t-") && !attr.startsWith("t-att")) {
|
|
5075
5098
|
throw new OwlError(`Unknown QWeb directive: '${attr}'`);
|
|
@@ -5091,6 +5114,7 @@ function parseDOMNode(node, ctx) {
|
|
|
5091
5114
|
tag: tagName,
|
|
5092
5115
|
dynamicTag,
|
|
5093
5116
|
attrs,
|
|
5117
|
+
attrsTranslationCtx,
|
|
5094
5118
|
on,
|
|
5095
5119
|
ref,
|
|
5096
5120
|
content: children,
|
|
@@ -5231,7 +5255,15 @@ function parseTCall(node, ctx) {
|
|
|
5231
5255
|
if (ast && ast.type === 11 /* TComponent */) {
|
|
5232
5256
|
return {
|
|
5233
5257
|
...ast,
|
|
5234
|
-
slots: {
|
|
5258
|
+
slots: {
|
|
5259
|
+
default: {
|
|
5260
|
+
content: tcall,
|
|
5261
|
+
scope: null,
|
|
5262
|
+
on: null,
|
|
5263
|
+
attrs: null,
|
|
5264
|
+
attrsTranslationCtx: null,
|
|
5265
|
+
},
|
|
5266
|
+
},
|
|
5235
5267
|
};
|
|
5236
5268
|
}
|
|
5237
5269
|
}
|
|
@@ -5346,9 +5378,15 @@ function parseComponent(node, ctx) {
|
|
|
5346
5378
|
node.removeAttribute("t-slot-scope");
|
|
5347
5379
|
let on = null;
|
|
5348
5380
|
let props = null;
|
|
5381
|
+
let propsTranslationCtx = null;
|
|
5349
5382
|
for (let name of node.getAttributeNames()) {
|
|
5350
5383
|
const value = node.getAttribute(name);
|
|
5351
|
-
if (name.startsWith("t-")) {
|
|
5384
|
+
if (name.startsWith("t-translation-context-")) {
|
|
5385
|
+
const attrName = name.slice(22);
|
|
5386
|
+
propsTranslationCtx = propsTranslationCtx || {};
|
|
5387
|
+
propsTranslationCtx[attrName] = value;
|
|
5388
|
+
}
|
|
5389
|
+
else if (name.startsWith("t-")) {
|
|
5352
5390
|
if (name.startsWith("t-on-")) {
|
|
5353
5391
|
on = on || {};
|
|
5354
5392
|
on[name.slice(5)] = value;
|
|
@@ -5392,6 +5430,7 @@ function parseComponent(node, ctx) {
|
|
|
5392
5430
|
const slotAst = parseNode(slotNode, ctx);
|
|
5393
5431
|
let on = null;
|
|
5394
5432
|
let attrs = null;
|
|
5433
|
+
let attrsTranslationCtx = null;
|
|
5395
5434
|
let scope = null;
|
|
5396
5435
|
for (let attributeName of slotNode.getAttributeNames()) {
|
|
5397
5436
|
const value = slotNode.getAttribute(attributeName);
|
|
@@ -5399,6 +5438,11 @@ function parseComponent(node, ctx) {
|
|
|
5399
5438
|
scope = value;
|
|
5400
5439
|
continue;
|
|
5401
5440
|
}
|
|
5441
|
+
else if (attributeName.startsWith("t-translation-context-")) {
|
|
5442
|
+
const attrName = attributeName.slice(22);
|
|
5443
|
+
attrsTranslationCtx = attrsTranslationCtx || {};
|
|
5444
|
+
attrsTranslationCtx[attrName] = value;
|
|
5445
|
+
}
|
|
5402
5446
|
else if (attributeName.startsWith("t-on-")) {
|
|
5403
5447
|
on = on || {};
|
|
5404
5448
|
on[attributeName.slice(5)] = value;
|
|
@@ -5409,17 +5453,32 @@ function parseComponent(node, ctx) {
|
|
|
5409
5453
|
}
|
|
5410
5454
|
}
|
|
5411
5455
|
slots = slots || {};
|
|
5412
|
-
slots[name] = { content: slotAst, on, attrs, scope };
|
|
5456
|
+
slots[name] = { content: slotAst, on, attrs, attrsTranslationCtx, scope };
|
|
5413
5457
|
}
|
|
5414
5458
|
// default slot
|
|
5415
5459
|
const defaultContent = parseChildNodes(clone, ctx);
|
|
5416
5460
|
slots = slots || {};
|
|
5417
5461
|
// t-set-slot="default" has priority over content
|
|
5418
5462
|
if (defaultContent && !slots.default) {
|
|
5419
|
-
slots.default = {
|
|
5463
|
+
slots.default = {
|
|
5464
|
+
content: defaultContent,
|
|
5465
|
+
on,
|
|
5466
|
+
attrs: null,
|
|
5467
|
+
attrsTranslationCtx: null,
|
|
5468
|
+
scope: defaultSlotScope,
|
|
5469
|
+
};
|
|
5420
5470
|
}
|
|
5421
5471
|
}
|
|
5422
|
-
return {
|
|
5472
|
+
return {
|
|
5473
|
+
type: 11 /* TComponent */,
|
|
5474
|
+
name,
|
|
5475
|
+
isDynamic,
|
|
5476
|
+
dynamicProps,
|
|
5477
|
+
props,
|
|
5478
|
+
propsTranslationCtx,
|
|
5479
|
+
slots,
|
|
5480
|
+
on,
|
|
5481
|
+
};
|
|
5423
5482
|
}
|
|
5424
5483
|
// -----------------------------------------------------------------------------
|
|
5425
5484
|
// Slots
|
|
@@ -5431,6 +5490,7 @@ function parseTSlot(node, ctx) {
|
|
|
5431
5490
|
const name = node.getAttribute("t-slot");
|
|
5432
5491
|
node.removeAttribute("t-slot");
|
|
5433
5492
|
let attrs = null;
|
|
5493
|
+
let attrsTranslationCtx = null;
|
|
5434
5494
|
let on = null;
|
|
5435
5495
|
for (let attributeName of node.getAttributeNames()) {
|
|
5436
5496
|
const value = node.getAttribute(attributeName);
|
|
@@ -5438,6 +5498,11 @@ function parseTSlot(node, ctx) {
|
|
|
5438
5498
|
on = on || {};
|
|
5439
5499
|
on[attributeName.slice(5)] = value;
|
|
5440
5500
|
}
|
|
5501
|
+
else if (attributeName.startsWith("t-translation-context-")) {
|
|
5502
|
+
const attrName = attributeName.slice(22);
|
|
5503
|
+
attrsTranslationCtx = attrsTranslationCtx || {};
|
|
5504
|
+
attrsTranslationCtx[attrName] = value;
|
|
5505
|
+
}
|
|
5441
5506
|
else {
|
|
5442
5507
|
attrs = attrs || {};
|
|
5443
5508
|
attrs[attributeName] = value;
|
|
@@ -5447,10 +5512,14 @@ function parseTSlot(node, ctx) {
|
|
|
5447
5512
|
type: 14 /* TSlot */,
|
|
5448
5513
|
name,
|
|
5449
5514
|
attrs,
|
|
5515
|
+
attrsTranslationCtx,
|
|
5450
5516
|
on,
|
|
5451
5517
|
defaultContent: parseChildNodes(node, ctx),
|
|
5452
5518
|
};
|
|
5453
5519
|
}
|
|
5520
|
+
// -----------------------------------------------------------------------------
|
|
5521
|
+
// Translation
|
|
5522
|
+
// -----------------------------------------------------------------------------
|
|
5454
5523
|
function parseTTranslation(node, ctx) {
|
|
5455
5524
|
if (node.getAttribute("t-translation") !== "off") {
|
|
5456
5525
|
return null;
|
|
@@ -5462,6 +5531,21 @@ function parseTTranslation(node, ctx) {
|
|
|
5462
5531
|
};
|
|
5463
5532
|
}
|
|
5464
5533
|
// -----------------------------------------------------------------------------
|
|
5534
|
+
// Translation Context
|
|
5535
|
+
// -----------------------------------------------------------------------------
|
|
5536
|
+
function parseTTranslationContext(node, ctx) {
|
|
5537
|
+
const translationCtx = node.getAttribute("t-translation-context");
|
|
5538
|
+
if (!translationCtx) {
|
|
5539
|
+
return null;
|
|
5540
|
+
}
|
|
5541
|
+
node.removeAttribute("t-translation-context");
|
|
5542
|
+
return {
|
|
5543
|
+
type: 17 /* TTranslationContext */,
|
|
5544
|
+
content: parseNode(node, ctx),
|
|
5545
|
+
translationCtx,
|
|
5546
|
+
};
|
|
5547
|
+
}
|
|
5548
|
+
// -----------------------------------------------------------------------------
|
|
5465
5549
|
// Portal
|
|
5466
5550
|
// -----------------------------------------------------------------------------
|
|
5467
5551
|
function parseTPortal(node, ctx) {
|
|
@@ -5478,7 +5562,7 @@ function parseTPortal(node, ctx) {
|
|
|
5478
5562
|
};
|
|
5479
5563
|
}
|
|
5480
5564
|
return {
|
|
5481
|
-
type:
|
|
5565
|
+
type: 18 /* TPortal */,
|
|
5482
5566
|
target,
|
|
5483
5567
|
content,
|
|
5484
5568
|
};
|
|
@@ -5620,7 +5704,7 @@ function compile(template, options = {
|
|
|
5620
5704
|
}
|
|
5621
5705
|
|
|
5622
5706
|
// do not modify manually. This file is generated by the release script.
|
|
5623
|
-
const version = "2.
|
|
5707
|
+
const version = "2.6.1";
|
|
5624
5708
|
|
|
5625
5709
|
// -----------------------------------------------------------------------------
|
|
5626
5710
|
// Scheduler
|
|
@@ -5715,13 +5799,6 @@ class Scheduler {
|
|
|
5715
5799
|
Scheduler.requestAnimationFrame = window.requestAnimationFrame.bind(window);
|
|
5716
5800
|
|
|
5717
5801
|
let hasBeenLogged = false;
|
|
5718
|
-
const DEV_MSG = () => {
|
|
5719
|
-
const hash = window.owl ? window.owl.__info__.hash : "master";
|
|
5720
|
-
return `Owl is running in 'dev' mode.
|
|
5721
|
-
|
|
5722
|
-
This is not suitable for production use.
|
|
5723
|
-
See https://github.com/odoo/owl/blob/${hash}/doc/reference/app.md#configuration for more information.`;
|
|
5724
|
-
};
|
|
5725
5802
|
const apps = new Set();
|
|
5726
5803
|
window.__OWL_DEVTOOLS__ || (window.__OWL_DEVTOOLS__ = { apps, Fiber, RootFiber, toRaw, reactive });
|
|
5727
5804
|
class App extends TemplateSet {
|
|
@@ -5738,7 +5815,7 @@ class App extends TemplateSet {
|
|
|
5738
5815
|
}
|
|
5739
5816
|
this.warnIfNoStaticProps = config.warnIfNoStaticProps || false;
|
|
5740
5817
|
if (this.dev && !config.test && !hasBeenLogged) {
|
|
5741
|
-
console.info(
|
|
5818
|
+
console.info(`Owl is running in 'dev' mode.`);
|
|
5742
5819
|
hasBeenLogged = true;
|
|
5743
5820
|
}
|
|
5744
5821
|
const env = config.env || {};
|
|
@@ -6098,6 +6175,6 @@ TemplateSet.prototype._compileTemplate = function _compileTemplate(name, templat
|
|
|
6098
6175
|
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 };
|
|
6099
6176
|
|
|
6100
6177
|
|
|
6101
|
-
__info__.date = '2025-
|
|
6102
|
-
__info__.hash = '
|
|
6178
|
+
__info__.date = '2025-03-05T08:37:58.580Z';
|
|
6179
|
+
__info__.hash = '2b5cea9';
|
|
6103
6180
|
__info__.url = 'https://github.com/odoo/owl';
|