Compare commits

...

6 Commits

Author SHA1 Message Date
Géry Debongnie b3181f119d [REL] v1.4.4
# v1.4.4

fix: overlapping multi-class in t-att-class
2021-09-03 09:57:00 +02:00
Géry Debongnie 1e1e05350a [REF] run prettier on codebase 2021-09-03 09:56:09 +02:00
Samuel Degueldre b242230e20 [FIX] qweb: fix overlapping multi-class in t-att-class
Previously, if two attributes in t-att-class shared some classes, their
presence would be determined by the last attribute declared, instead of
being present if any attribute containing it evaluates to true. This
commit fixes that.
2021-09-01 11:58:45 +02:00
Géry Debongnie 9fe2da704e [REL] v1.4.3
# v1.4.3

- fix: another scoping issue with t-slots
2021-07-08 11:54:32 +02:00
Géry Debongnie 21b1661d39 [CLEANUP] run prettier on codebase 2021-07-08 11:53:48 +02:00
Géry Debongnie ec05b1f5e3 [FIX] slots: fix bad interaction between t-call and slots
The previous changes in the combine method (used to copy all the
variables defined in the current scope for use in a slot) had the effect
of squashing the prototype chain: instead of `Component -> Obj1 ->
Obj2 -> Obj3`, the combined scope had: `Component -> Obj1'`.

This has an unfortunate interaction with the way t-call is implemented,
which uses the fact that we are in a subscope to add a own
__access_mode__. It depends specifially on the prototype chain, and that
the parent scope may have a different value for that property. But with
the way combine was implemented, we lost all that subtlety since
everything is squashed.

In this commit, we reimplement that function in a way to make sure we
keep the prototype chain structure
2021-07-08 11:49:25 +02:00
7 changed files with 125 additions and 7 deletions
+1 -1
View File
@@ -120,7 +120,7 @@ npm install @odoo/owl
If you want to use a simple `<script>` tag, the last release can be downloaded here:
- [owl-1.4.2](https://github.com/odoo/owl/releases/tag/v1.4.2)
- [owl-1.4.4](https://github.com/odoo/owl/releases/tag/v1.4.4)
## License
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "@odoo/owl",
"version": "1.4.2",
"version": "1.4.4",
"description": "Odoo Web Library (OWL)",
"main": "dist/owl.cjs.js",
"browser": "dist/owl.iife.js",
+1 -1
View File
@@ -1,6 +1,6 @@
# 🦉 OWL Roadmap 🦉
- Current version: 1.4.2
- Current version: 1.4.4
- Status: stable
This roadmap is only an attempt at predicting Owl's future. Everything may
+18 -4
View File
@@ -127,22 +127,36 @@ const UTILS: Utils = {
return result;
}
// this is already an object, but we may need to split keys:
// {'a': true, 'b c': true} should become {a: true, b: true, c: true}
// {'a b': true, 'a c': false} should become {a: true, b: true, c: false}
for (let key in expr) {
const value = expr[key];
const words = key.split(/\s+/);
for (let word of words) {
result[word] = value;
result[word] = result[word] || value;
}
}
return result;
},
/**
* This method combines the current context with the variables defined in a
* scope for use in a slot.
*
* The implementation is kind of tricky because we want to preserve the
* prototype chain structure of the cloned result. So we need to traverse the
* prototype chain, cloning each level respectively.
*/
combine(context, scope) {
const clone = Object.create(context);
let clone = context;
const scopeStack = [];
while (!isComponent(scope)) {
Object.assign(clone, scope);
scopeStack.push(scope);
scope = scope.__proto__;
}
while (scopeStack.length) {
let scope = scopeStack.pop();
clone = Object.create(clone);
Object.assign(clone, scope);
}
return clone;
},
shallowEqual,
+67
View File
@@ -1303,4 +1303,71 @@ describe("t-slot directive", () => {
document.querySelector("button").click();
await nextTick();
});
test("t-slot in recursive templates", async () => {
QWeb.registerTemplate(
"_test_recursive_template",
`
<Wrapper>
<t t-esc="name" />
<t t-foreach="items" t-as="item">
<t t-if="!item.children.length">
<t t-esc="item.name" />
</t>
<t t-else="" t-call="_test_recursive_template">
<t t-set="name" t-value="item.name" />
<t t-set="items" t-value="item.children" />
</t>
</t>
</Wrapper>`
);
class Wrapper extends Component {
static template = xml`
<wrapper>
<t t-slot="default"/>
</wrapper>`;
}
class Parent extends Component {
static template = "_test_recursive_template";
static components = { Wrapper };
name = "foo";
items = [
{
name: "foo-0",
children: [
{ name: "foo-00", children: [] },
{
name: "foo-01",
children: [
{ name: "foo-010", children: [] },
{ name: "foo-011", children: [] },
{
name: "foo-012",
children: [
{ name: "foo-0120", children: [] },
{ name: "foo-0121", children: [] },
{ name: "foo-0122", children: [] },
],
},
],
},
{ name: "foo-02", children: [] },
],
},
{ name: "foo-1", children: [] },
{ name: "foo-2", children: [] },
];
}
await mount(Parent, { target: fixture });
expect(fixture.innerHTML).toBe(
"<wrapper>foo<wrapper>foo-0foo-00<wrapper>foo-01foo-010foo-011<wrapper>foo-012foo-0120foo-0121foo-0122</wrapper></wrapper>foo-02</wrapper>foo-1foo-2</wrapper>"
);
});
});
@@ -27,3 +27,31 @@ exports[`qweb t-att t-att-class with multiple classes 2`] = `
return vn4;
}"
`;
exports[`qweb t-att t-att-class with multiple classes, some of which are duplicate 1`] = `
"function anonymous(context, extra
) {
// Template name: \\"test\\"
let utils = this.constructor.utils;
let scope = Object.create(context);
let h = this.h;
let _1 = utils.toClassObj({'a b c':scope['value'],'a b d':!scope['value']});
let c2 = [], p2 = {key:2,class:_1};
let vn2 = h('div', p2, c2);
return vn2;
}"
`;
exports[`qweb t-att t-att-class with multiple classes, some of which are duplicate 2`] = `
"function anonymous(context, extra
) {
// Template name: \\"test\\"
let utils = this.constructor.utils;
let scope = Object.create(context);
let h = this.h;
let _3 = utils.toClassObj({'a b c':scope['value'],'a b d':!scope['value']});
let c4 = [], p4 = {key:4,class:_3};
let vn4 = h('div', p4, c4);
return vn4;
}"
`;
+9
View File
@@ -24,4 +24,13 @@ describe("qweb t-att", () => {
'<div class="a b c"></div>'
);
});
test("t-att-class with multiple classes, some of which are duplicate", () => {
expect(render(`<div t-att-class="{'a b c': value, 'a b d': !value}" />`, { value: true })).toBe(
'<div class="a b c"></div>'
);
expect(
render(`<div t-att-class="{'a b c': value, 'a b d': !value}" />`, { value: false })
).toBe('<div class="a b d"></div>');
});
});