diff --git a/src/qweb/base_directives.ts b/src/qweb/base_directives.ts index e49f8a2f..5fbb277e 100644 --- a/src/qweb/base_directives.ts +++ b/src/qweb/base_directives.ts @@ -80,11 +80,6 @@ QWeb.addDirective({ name: "esc", priority: 70, 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")!); compileValueNode(value, node, qweb, ctx.subContext("escaping", true)); return true; @@ -95,11 +90,6 @@ QWeb.addDirective({ name: "raw", priority: 80, 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")!); compileValueNode(value, node, qweb, ctx); return true; diff --git a/src/qweb/qweb.ts b/src/qweb/qweb.ts index 2da41059..992ff18a 100644 --- a/src/qweb/qweb.ts +++ b/src/qweb/qweb.ts @@ -449,8 +449,6 @@ export class QWeb extends EventBus { fullName: string; }[] = []; - let withHandlers = false; - // maybe this is not optimal: we iterate on all attributes here, and again // just after for each directive. for (let i = 0; i < attributes.length; i++) { @@ -460,11 +458,21 @@ export class QWeb extends EventBus { if (!(dName in QWeb.DIRECTIVE_NAMES)) { 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 ATTR_N = attributes.length; + let withHandlers = false; for (let i = 0; i < DIR_N; i++) { let directive = QWeb.DIRECTIVES[i]; let fullName; diff --git a/tests/qweb/__snapshots__/qweb.test.ts.snap b/tests/qweb/__snapshots__/qweb.test.ts.snap index 245fc12e..c7bf2d14 100644 --- a/tests/qweb/__snapshots__/qweb.test.ts.snap +++ b/tests/qweb/__snapshots__/qweb.test.ts.snap @@ -614,7 +614,7 @@ exports[`misc global 1`] = ` context.value_index = i; context.value = _3[i]; context.value_value = _4[i]; - let c5 = [], p5 = {key:5,on:{}}; + let c5 = [], p5 = {key:5}; var vn5 = h('span', p5, c5); c1.push(vn5); var _6 = context['value']; @@ -624,12 +624,12 @@ exports[`misc global 1`] = ` { let _11 = 'bbb'; var _13 = 'agüero'; - let c14 = [], p14 = {key:14,attrs:{\\"falló\\": _13},on:{}}; - var vn14 = h('Año', p14, c14); + let c14 = [], p14 = {key:14,attrs:{\\"falló\\": _13}}; + var vn14 = h('año', p14, c14); c1.push(vn14); { let _15 = 'aaa'; - let c16 = [], p16 = {key:16,on:{}}; + let c16 = [], p16 = {key:16}; var vn16 = h('span', p16, c16); c14.push(vn16); if (_15 || _15 === 0) { @@ -638,7 +638,7 @@ exports[`misc global 1`] = ` c16.push({text: \`foo default\`}); } } - let c17 = [], p17 = {key:17,on:{}}; + let c17 = [], p17 = {key:17}; var vn17 = h('span', p17, c17); c14.push(vn17); var _18 = context['foo']; @@ -648,7 +648,7 @@ exports[`misc global 1`] = ` c17.push({text: \`foo default\`}); } var _19 = 'bbb'; - let c20 = [], p20 = {key:20,on:{}}; + let c20 = [], p20 = {key:20}; var vn20 = h('span', p20, c20); c14.push(vn20); 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); c1.push(vn21); var _22 = context['toto']; @@ -1256,7 +1256,7 @@ exports[`t-esc escaping on a node 1`] = ` "function anonymous(context,extra ) { var h = this.h; - let c1 = [], p1 = {key:1,on:{}}; + let c1 = [], p1 = {key:1}; var vn1 = h('span', p1, c1); result = vn1; var _2 = 'ok'; @@ -1271,7 +1271,7 @@ exports[`t-esc escaping on a node with a body 1`] = ` "function anonymous(context,extra ) { var h = this.h; - let c1 = [], p1 = {key:1,on:{}}; + let c1 = [], p1 = {key:1}; var vn1 = h('span', p1, c1); result = vn1; 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 ) { var h = this.h; - let c1 = [], p1 = {key:1,on:{}}; + let c1 = [], p1 = {key:1}; var vn1 = h('span', p1, c1); result = vn1; 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`] = ` "function anonymous(context,extra ) { diff --git a/tests/qweb/qweb.test.ts b/tests/qweb/qweb.test.ts index 0849de7e..451e20fb 100644 --- a/tests/qweb/qweb.test.ts +++ b/tests/qweb/qweb.test.ts @@ -778,7 +778,7 @@ describe("foreach", () => { describe("misc", () => { test("global", () => { - qweb.addTemplate("_callee-asc", ``); + qweb.addTemplate("_callee-asc", ``); qweb.addTemplate("_callee-uses-foo", `foo default`); qweb.addTemplate("_callee-asc-toto", `
toto default
`); qweb.addTemplate( @@ -1118,6 +1118,44 @@ describe("t-on", () => { expect(steps).toEqual([1, 2]); }); + + test("t-on combined with t-esc", async () => { + expect.assertions(3); + qweb.addTemplate("test", `
`); + const steps:string[] = []; + const owner = { + text: 'Click here', + onClick() { + steps.push('onClick'); + }, + }; + + const node = renderToDOM(qweb, "test", owner, { handlers: [] }); + expect(node.outerHTML).toBe(`
`); + + node.querySelector("button")!.click(); + + expect(steps).toEqual(['onClick']); + }); + + test("t-on combined with t-raw", async () => { + expect.assertions(3); + qweb.addTemplate("test", `
`); + const steps:string[] = []; + const owner = { + html: 'Click here', + onClick() { + steps.push('onClick'); + }, + }; + + const node = renderToDOM(qweb, "test", owner, { handlers: [] }); + expect(node.outerHTML).toBe(`
`); + + node.querySelector("button")!.click(); + + expect(steps).toEqual(['onClick']); + }); }); describe("t-ref", () => {