[FIX] qweb: properly handle empty class attribute

The classList.add method actually crashes when given an empty string (or
a string with just white spaces).

closes #530
This commit is contained in:
Géry Debongnie
2019-12-03 14:02:58 +01:00
committed by aab-odoo
parent 286090efca
commit f12d3373c9
5 changed files with 91 additions and 8 deletions
+8 -7
View File
@@ -650,13 +650,14 @@ export class QWeb extends EventBus {
if (!name.startsWith("t-") && !(<Element>node).getAttribute("t-attf-" + name)) {
const attID = ctx.generateID();
if (name === "class") {
let classDef = value
.trim()
.split(/\s+/)
.map(a => `'${a}':true`)
.join(",");
classObj = `_${ctx.generateID()}`;
ctx.addLine(`let ${classObj} = {${classDef}};`);
if (value = value.trim()) {
let classDef = value
.split(/\s+/)
.map(a => `'${a}':true`)
.join(",");
classObj = `_${ctx.generateID()}`;
ctx.addLine(`let ${classObj} = {${classDef}};`);
}
} else {
ctx.addLine(`var _${attID} = '${value}';`);
if (!name.match(/^[a-zA-Z]+$/)) {
+1 -1
View File
@@ -219,7 +219,7 @@ function updateClass(oldVnode: VNode, vnode: VNode): void {
elm = vnode.elm as Element;
for (name in oldClass) {
if (!klass[name]) {
if (name && !klass[name]) {
elm.classList.remove(name);
}
}
+13
View File
@@ -1614,6 +1614,19 @@ describe("class and style attributes with t-component", () => {
expect(fixture.innerHTML).toBe(`<div><div class="c a b"></div></div>`);
});
test("empty class attribute is not added on widget root el", async () => {
class Child extends Component<any, any> {
static template = xml`<span/>`;
}
class Parent extends Component<any, any> {
static template = xml`<div><Child class=""/></div>`;
static components = { Child };
}
const widget = new Parent();
await widget.mount(fixture);
expect(fixture.innerHTML).toBe(`<div><span></span></div>`);
});
test("t-att-class is properly added/removed on widget root el", async () => {
class Child extends Widget {
static template = xml`<div class="c"/>`;
@@ -44,6 +44,30 @@ exports[`attributes dynamic attributes 1`] = `
}"
`;
exports[`attributes dynamic class attribute 1`] = `
"function anonymous(context,extra
) {
let utils = this.constructor.utils;
var h = this.h;
let _1 = utils.toObj(context['c']);
let c2 = [], p2 = {key:2,class:_1};
var vn2 = h('div', p2, c2);
return vn2;
}"
`;
exports[`attributes dynamic empty class attribute 1`] = `
"function anonymous(context,extra
) {
let utils = this.constructor.utils;
var h = this.h;
let _1 = utils.toObj(context['c']);
let c2 = [], p2 = {key:2,class:_1};
var vn2 = h('div', p2, c2);
return vn2;
}"
`;
exports[`attributes dynamic formatted attributes with a dash 1`] = `
"function anonymous(context,extra
) {
@@ -787,6 +811,29 @@ exports[`special cases for some boolean html attributes/properties various boole
}"
`;
exports[`static templates div with a class attribute 1`] = `
"function anonymous(context,extra
) {
var h = this.h;
let _2 = {'abc':true};
let c3 = [], p3 = {key:3,class:_2};
var vn3 = h('div', p3, c3);
c3.push({text: \`word\`});
return vn3;
}"
`;
exports[`static templates div with a empty class attribute 1`] = `
"function anonymous(context,extra
) {
var h = this.h;
let c2 = [], p2 = {key:2};
var vn2 = h('div', p2, c2);
c2.push({text: \`word\`});
return vn2;
}"
`;
exports[`static templates div with a span child node 1`] = `
"function anonymous(context,extra
) {
+22
View File
@@ -46,6 +46,16 @@ describe("static templates", () => {
expect(renderToString(qweb, "test")).toBe("<div>word</div>");
});
test("div with a class attribute", () => {
qweb.addTemplate("test", `<div class="abc">word</div>`);
expect(renderToString(qweb, "test")).toBe(`<div class="abc">word</div>`);
});
test("div with a empty class attribute", () => {
qweb.addTemplate("test", `<div class="">word</div>`);
expect(renderToString(qweb, "test")).toBe(`<div>word</div>`);
});
test("div with a span child node", () => {
qweb.addTemplate("test", "<div><span>word</span></div>");
expect(renderToString(qweb, "test")).toBe("<div><span>word</span></div>");
@@ -432,6 +442,18 @@ describe("attributes", () => {
expect(result).toBe(`<div foo="bar"></div>`);
});
test("dynamic class attribute", () => {
qweb.addTemplate("test", `<div t-att-class="c"/>`);
const result = renderToString(qweb, "test", { c: "abc" });
expect(result).toBe(`<div class="abc"></div>`);
});
test("dynamic empty class attribute", () => {
qweb.addTemplate("test", `<div t-att-class="c"/>`);
const result = renderToString(qweb, "test", { c: "" });
expect(result).toBe(`<div></div>`);
});
test("dynamic attribute with a dash", () => {
qweb.addTemplate("test", `<div t-att-data-action-id="id"/>`);
const result = renderToString(qweb, "test", { id: 32 });