[FIX] qweb: allow to combine t-esc with other directives

With this rev., when a t-esc is not set on a <t> tag, we create
it inside the node on which it is set, to ensure that the t-esc
directive is always set on <t> tags.

Same applies for t-raw.

Closes #324
This commit is contained in:
Aaron Bohy
2019-10-11 10:43:27 +02:00
committed by Géry Debongnie
parent 2f27768be2
commit 0928c189f4
4 changed files with 112 additions and 23 deletions
-10
View File
@@ -80,11 +80,6 @@ QWeb.addDirective({
name: "esc", name: "esc",
priority: 70, priority: 70,
atNodeEncounter({ node, qweb, ctx }): boolean { atNodeEncounter({ node, qweb, ctx }): boolean {
if (node.nodeName !== "t") {
let nodeID = qweb._compileGenericNode(node, ctx);
ctx = ctx.withParent(nodeID);
ctx = ctx.subContext("currentKey", ctx.lastNodeKey);
}
let value = ctx.getValue(node.getAttribute("t-esc")!); let value = ctx.getValue(node.getAttribute("t-esc")!);
compileValueNode(value, node, qweb, ctx.subContext("escaping", true)); compileValueNode(value, node, qweb, ctx.subContext("escaping", true));
return true; return true;
@@ -95,11 +90,6 @@ QWeb.addDirective({
name: "raw", name: "raw",
priority: 80, priority: 80,
atNodeEncounter({ node, qweb, ctx }): boolean { atNodeEncounter({ node, qweb, ctx }): boolean {
if (node.nodeName !== "t") {
let nodeID = qweb._compileGenericNode(node, ctx);
ctx = ctx.withParent(nodeID);
ctx = ctx.subContext("currentKey", ctx.lastNodeKey);
}
let value = ctx.getValue(node.getAttribute("t-raw")!); let value = ctx.getValue(node.getAttribute("t-raw")!);
compileValueNode(value, node, qweb, ctx); compileValueNode(value, node, qweb, ctx);
return true; return true;
+10 -2
View File
@@ -449,8 +449,6 @@ export class QWeb extends EventBus {
fullName: string; fullName: string;
}[] = []; }[] = [];
let withHandlers = false;
// maybe this is not optimal: we iterate on all attributes here, and again // maybe this is not optimal: we iterate on all attributes here, and again
// just after for each directive. // just after for each directive.
for (let i = 0; i < attributes.length; i++) { for (let i = 0; i < attributes.length; i++) {
@@ -460,11 +458,21 @@ export class QWeb extends EventBus {
if (!(dName in QWeb.DIRECTIVE_NAMES)) { if (!(dName in QWeb.DIRECTIVE_NAMES)) {
throw new Error(`Unknown QWeb directive: '${attrName}'`); throw new Error(`Unknown QWeb directive: '${attrName}'`);
} }
if (node.tagName !== 't' && (attrName === 't-esc' || attrName === 't-raw')) {
const tNode = document.createElement('t');
tNode.setAttribute(attrName, node.getAttribute(attrName)!);
for (let child of Array.from(node.childNodes)) {
tNode.appendChild(child);
}
node.appendChild(tNode);
node.removeAttribute(attrName);
}
} }
} }
const DIR_N = QWeb.DIRECTIVES.length; const DIR_N = QWeb.DIRECTIVES.length;
const ATTR_N = attributes.length; const ATTR_N = attributes.length;
let withHandlers = false;
for (let i = 0; i < DIR_N; i++) { for (let i = 0; i < DIR_N; i++) {
let directive = QWeb.DIRECTIVES[i]; let directive = QWeb.DIRECTIVES[i];
let fullName; let fullName;
+63 -10
View File
@@ -614,7 +614,7 @@ exports[`misc global 1`] = `
context.value_index = i; context.value_index = i;
context.value = _3[i]; context.value = _3[i];
context.value_value = _4[i]; context.value_value = _4[i];
let c5 = [], p5 = {key:5,on:{}}; let c5 = [], p5 = {key:5};
var vn5 = h('span', p5, c5); var vn5 = h('span', p5, c5);
c1.push(vn5); c1.push(vn5);
var _6 = context['value']; var _6 = context['value'];
@@ -624,12 +624,12 @@ exports[`misc global 1`] = `
{ {
let _11 = 'bbb'; let _11 = 'bbb';
var _13 = 'agüero'; var _13 = 'agüero';
let c14 = [], p14 = {key:14,attrs:{\\"falló\\": _13},on:{}}; let c14 = [], p14 = {key:14,attrs:{\\"falló\\": _13}};
var vn14 = h('Año', p14, c14); var vn14 = h('año', p14, c14);
c1.push(vn14); c1.push(vn14);
{ {
let _15 = 'aaa'; let _15 = 'aaa';
let c16 = [], p16 = {key:16,on:{}}; let c16 = [], p16 = {key:16};
var vn16 = h('span', p16, c16); var vn16 = h('span', p16, c16);
c14.push(vn16); c14.push(vn16);
if (_15 || _15 === 0) { if (_15 || _15 === 0) {
@@ -638,7 +638,7 @@ exports[`misc global 1`] = `
c16.push({text: \`foo default\`}); c16.push({text: \`foo default\`});
} }
} }
let c17 = [], p17 = {key:17,on:{}}; let c17 = [], p17 = {key:17};
var vn17 = h('span', p17, c17); var vn17 = h('span', p17, c17);
c14.push(vn17); c14.push(vn17);
var _18 = context['foo']; var _18 = context['foo'];
@@ -648,7 +648,7 @@ exports[`misc global 1`] = `
c17.push({text: \`foo default\`}); c17.push({text: \`foo default\`});
} }
var _19 = 'bbb'; var _19 = 'bbb';
let c20 = [], p20 = {key:20,on:{}}; let c20 = [], p20 = {key:20};
var vn20 = h('span', p20, c20); var vn20 = h('span', p20, c20);
c14.push(vn20); c14.push(vn20);
if (_19 || _19 === 0) { if (_19 || _19 === 0) {
@@ -658,7 +658,7 @@ exports[`misc global 1`] = `
} }
} }
} }
let c21 = [], p21 = {key:21,on:{}}; let c21 = [], p21 = {key:21};
var vn21 = h('div', p21, c21); var vn21 = h('div', p21, c21);
c1.push(vn21); c1.push(vn21);
var _22 = context['toto']; var _22 = context['toto'];
@@ -1256,7 +1256,7 @@ exports[`t-esc escaping on a node 1`] = `
"function anonymous(context,extra "function anonymous(context,extra
) { ) {
var h = this.h; var h = this.h;
let c1 = [], p1 = {key:1,on:{}}; let c1 = [], p1 = {key:1};
var vn1 = h('span', p1, c1); var vn1 = h('span', p1, c1);
result = vn1; result = vn1;
var _2 = 'ok'; var _2 = 'ok';
@@ -1271,7 +1271,7 @@ exports[`t-esc escaping on a node with a body 1`] = `
"function anonymous(context,extra "function anonymous(context,extra
) { ) {
var h = this.h; var h = this.h;
let c1 = [], p1 = {key:1,on:{}}; let c1 = [], p1 = {key:1};
var vn1 = h('span', p1, c1); var vn1 = h('span', p1, c1);
result = vn1; result = vn1;
var _2 = 'ok'; var _2 = 'ok';
@@ -1288,7 +1288,7 @@ exports[`t-esc escaping on a node with a body, as a default 1`] = `
"function anonymous(context,extra "function anonymous(context,extra
) { ) {
var h = this.h; var h = this.h;
let c1 = [], p1 = {key:1,on:{}}; let c1 = [], p1 = {key:1};
var vn1 = h('span', p1, c1); var vn1 = h('span', p1, c1);
result = vn1; result = vn1;
var _2 = context['var']; var _2 = context['var'];
@@ -1701,6 +1701,59 @@ exports[`t-on handler is bound to proper owner 1`] = `
}" }"
`; `;
exports[`t-on t-on combined with t-esc 1`] = `
"function anonymous(context,extra
) {
let owner = context;
var h = this.h;
let c1 = [], p1 = {key:1};
var vn1 = h('div', p1, c1);
result = vn1;
let c2 = [], p2 = {key:2,on:{}};
var vn2 = h('button', p2, c2);
c1.push(vn2);
if (!context['onClick']) {
throw new Error('Missing handler \\\\'' + 'onClick' + \`\\\\' when evaluating template 'test'\`)
}
extra.handlers['click' + 2] = extra.handlers['click' + 2] || context['onClick'].bind(owner);
p2.on['click'] = extra.handlers['click' + 2];
var _3 = context['text'];
if (_3 || _3 === 0) {
c2.push({text: _3});
}
return vn1;
}"
`;
exports[`t-on t-on combined with t-raw 1`] = `
"function anonymous(context,extra
) {
let utils = this.constructor.utils;
let owner = context;
var h = this.h;
let c1 = [], p1 = {key:1};
var vn1 = h('div', p1, c1);
let c2 = [], p2 = {key:2,on:{}};
var vn2 = h('button', p2, c2);
c1.push(vn2);
if (!context['onClick']) {
throw new Error('Missing handler \\\\'' + 'onClick' + \`\\\\' when evaluating template 'test'\`)
}
extra.handlers['click' + 2] = extra.handlers['click' + 2] || context['onClick'].bind(owner);
p2.on['click'] = extra.handlers['click' + 2];
var _3 = context['html'];
if (_3 || _3 === 0) {
var frag4 = utils.getFragment(_3)
var p5 = {hook: {
insert: n => n.elm.parentNode.replaceChild(frag4, n.elm),
}};
var vn5 = h('div', p5)
c2.push(vn5);
}
return vn1;
}"
`;
exports[`t-on t-on with prevent and self modifiers (order matters) 1`] = ` exports[`t-on t-on with prevent and self modifiers (order matters) 1`] = `
"function anonymous(context,extra "function anonymous(context,extra
) { ) {
+39 -1
View File
@@ -778,7 +778,7 @@ describe("foreach", () => {
describe("misc", () => { describe("misc", () => {
test("global", () => { test("global", () => {
qweb.addTemplate("_callee-asc", `<Año t-att-falló="'agüero'" t-raw="0"/>`); qweb.addTemplate("_callee-asc", `<año t-att-falló="'agüero'" t-raw="0"/>`);
qweb.addTemplate("_callee-uses-foo", `<span t-esc="foo">foo default</span>`); qweb.addTemplate("_callee-uses-foo", `<span t-esc="foo">foo default</span>`);
qweb.addTemplate("_callee-asc-toto", `<div t-raw="toto">toto default</div>`); qweb.addTemplate("_callee-asc-toto", `<div t-raw="toto">toto default</div>`);
qweb.addTemplate( qweb.addTemplate(
@@ -1118,6 +1118,44 @@ describe("t-on", () => {
expect(steps).toEqual([1, 2]); expect(steps).toEqual([1, 2]);
}); });
test("t-on combined with t-esc", async () => {
expect.assertions(3);
qweb.addTemplate("test", `<div><button t-on-click="onClick" t-esc="text"/></div>`);
const steps:string[] = [];
const owner = {
text: 'Click here',
onClick() {
steps.push('onClick');
},
};
const node = <HTMLElement>renderToDOM(qweb, "test", owner, { handlers: [] });
expect(node.outerHTML).toBe(`<div><button>Click here</button></div>`);
node.querySelector("button")!.click();
expect(steps).toEqual(['onClick']);
});
test("t-on combined with t-raw", async () => {
expect.assertions(3);
qweb.addTemplate("test", `<div><button t-on-click="onClick" t-raw="html"/></div>`);
const steps:string[] = [];
const owner = {
html: 'Click <b>here</b>',
onClick() {
steps.push('onClick');
},
};
const node = <HTMLElement>renderToDOM(qweb, "test", owner, { handlers: [] });
expect(node.outerHTML).toBe(`<div><button>Click <b>here</b></button></div>`);
node.querySelector("button")!.click();
expect(steps).toEqual(['onClick']);
});
}); });
describe("t-ref", () => { describe("t-ref", () => {