From 7ebe0da9624b72b552c5464359691570779ec3bd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Theys?= Date: Thu, 1 Jul 2021 11:12:21 +0200 Subject: [PATCH] [IMP] component: add support for callable expression in event handler --- src/qweb/extensions.ts | 1 + .../__snapshots__/component.test.ts.snap | 8 ++++---- tests/component/component.test.ts | 18 ++++++++++++++++++ tests/qweb/__snapshots__/qweb.test.ts.snap | 10 +++++----- 4 files changed, 28 insertions(+), 9 deletions(-) diff --git a/src/qweb/extensions.ts b/src/qweb/extensions.ts index dc0f4fc5..33c618c8 100644 --- a/src/qweb/extensions.ts +++ b/src/qweb/extensions.ts @@ -75,6 +75,7 @@ export function makeHandlerCode( // we need to capture every variable in it putInCache = false; code = ctx.captureExpression(value); + code = `const res = (() => { return ${code} })(); if (typeof res === 'function') { res(e) }`; } const modCode = mods.map((mod) => modcodes[mod]).join(""); let handler = `function (e) {if (context.__owl__.status === ${STATUS.DESTROYED}){return}${modCode}${code}}`; diff --git a/tests/component/__snapshots__/component.test.ts.snap b/tests/component/__snapshots__/component.test.ts.snap index 19838a13..17760c9e 100644 --- a/tests/component/__snapshots__/component.test.ts.snap +++ b/tests/component/__snapshots__/component.test.ts.snap @@ -579,7 +579,7 @@ exports[`other directives with t-component t-on expression captured in t-foreach c6.push(vn7); const otherState_8 = scope['otherState']; const iter_8 = scope.iter; - p7.on['click'] = function (e) {if (context.__owl__.status === 5){return}otherState_8.vals.push(iter_8+'_'+iter_8)}; + p7.on['click'] = function (e) {if (context.__owl__.status === 5){return}const res = (() => { return otherState_8.vals.push(iter_8+'_'+iter_8) })(); if (typeof res === 'function') { res(e) }}; c7.push({text: \`expr\`}); utils.getScope(scope, 'iter').iter = scope.iter+1; } @@ -630,7 +630,7 @@ exports[`other directives with t-component t-on expression in t-foreach 1`] = ` c6.push(vn9); const otherState_10 = scope['otherState']; const val_10 = scope['val']; - p9.on['click'] = function (e) {if (context.__owl__.status === 5){return}otherState_10.vals.push(val_10)}; + p9.on['click'] = function (e) {if (context.__owl__.status === 5){return}const res = (() => { return otherState_10.vals.push(val_10) })(); if (typeof res === 'function') { res(e) }}; c9.push({text: \`Expr\`}); } scope = _origScope5; @@ -684,7 +684,7 @@ exports[`other directives with t-component t-on expression in t-foreach with t-s const otherState_10 = scope['otherState']; const val_10 = scope['val']; const bossa_10 = scope.bossa; - p9.on['click'] = function (e) {if (context.__owl__.status === 5){return}otherState_10.vals.push(val_10+'_'+bossa_10)}; + p9.on['click'] = function (e) {if (context.__owl__.status === 5){return}const res = (() => { return otherState_10.vals.push(val_10+'_'+bossa_10) })(); if (typeof res === 'function') { res(e) }}; c9.push({text: \`Expr\`}); } scope = _origScope5; @@ -1011,7 +1011,7 @@ exports[`other directives with t-component t-on with inline statement 1`] = ` if (!W3) {throw new Error('Cannot find the definition of component \\"' + componentKey3 + '\\"')} w3 = new W3(parent, props3); parent.__owl__.cmap['__4__'] = w3.__owl__.id; - let fiber = w3.__prepare(extra.fiber, undefined, () => { const vnode = fiber.vnode; pvnode.sel = vnode.sel; utils.assignHooks(vnode.data, {create(_, vn){vn.elm.addEventListener('ev', function (e) {if (context.__owl__.status === 5){return}state_5.counter++});}});}); + let fiber = w3.__prepare(extra.fiber, undefined, () => { const vnode = fiber.vnode; pvnode.sel = vnode.sel; utils.assignHooks(vnode.data, {create(_, vn){vn.elm.addEventListener('ev', function (e) {if (context.__owl__.status === 5){return}const res = (() => { return state_5.counter++ })(); if (typeof res === 'function') { res(e) }});}});}); let pvnode = h('dummy', {key: '__4__', hook: {remove() {},destroy(vn) {w3.destroy();}}}); c1.push(pvnode); w3.__owl__.pvnode = pvnode; diff --git a/tests/component/component.test.ts b/tests/component/component.test.ts index 053b0e21..1610541e 100644 --- a/tests/component/component.test.ts +++ b/tests/component/component.test.ts @@ -149,6 +149,24 @@ describe("basic widget properties", () => { expect(fixture.innerHTML).toBe("
1
"); }); + test("support for callable expression in event handler", async () => { + class Counter extends Component { + static template = xml` +
`; + state = useState({ value: "" }); + obj = { onInput: (ev) => (this.state.value = ev.target.value) }; + } + + const counter = await mount(Counter, { target: fixture }); + await nextTick(); + expect(fixture.innerHTML).toBe(`
`); + const input = (counter.el).getElementsByTagName("input")[0]; + input.value = "test"; + input.dispatchEvent(new Event("input")); + await nextTick(); + expect(fixture.innerHTML).toBe(`
test
`); + }); + test("can handle empty props", async () => { class Child extends Component { static template = xml``; diff --git a/tests/qweb/__snapshots__/qweb.test.ts.snap b/tests/qweb/__snapshots__/qweb.test.ts.snap index 50d08dd2..fa717f67 100644 --- a/tests/qweb/__snapshots__/qweb.test.ts.snap +++ b/tests/qweb/__snapshots__/qweb.test.ts.snap @@ -2950,7 +2950,7 @@ exports[`t-on t-on with empty handler (only modifiers) 1`] = ` let c2 = [], p2 = {key:2,on:{}}; let vn2 = h('button', p2, c2); c1.push(vn2); - p2.on['click'] = function (e) {if (context.__owl__.status === 5){return}e.preventDefault();}; + p2.on['click'] = function (e) {if (context.__owl__.status === 5){return}e.preventDefault();const res = (() => { return })(); if (typeof res === 'function') { res(e) }}; c2.push({text: \`Button\`}); return vn1; }" @@ -2965,7 +2965,7 @@ exports[`t-on t-on with inline statement (function call) 1`] = ` let c1 = [], p1 = {key:1,on:{}}; let vn1 = h('button', p1, c1); const state_2 = scope['state']; - p1.on['click'] = function (e) {if (context.__owl__.status === 5){return}state_2.incrementCounter(2)}; + p1.on['click'] = function (e) {if (context.__owl__.status === 5){return}const res = (() => { return state_2.incrementCounter(2) })(); if (typeof res === 'function') { res(e) }}; c1.push({text: \`Click\`}); return vn1; }" @@ -2980,7 +2980,7 @@ exports[`t-on t-on with inline statement 1`] = ` let c1 = [], p1 = {key:1,on:{}}; let vn1 = h('button', p1, c1); const state_2 = scope['state']; - p1.on['click'] = function (e) {if (context.__owl__.status === 5){return}state_2.counter++}; + p1.on['click'] = function (e) {if (context.__owl__.status === 5){return}const res = (() => { return state_2.counter++ })(); if (typeof res === 'function') { res(e) }}; c1.push({text: \`Click\`}); return vn1; }" @@ -2995,7 +2995,7 @@ exports[`t-on t-on with inline statement, part 2 1`] = ` let c1 = [], p1 = {key:1,on:{}}; let vn1 = h('button', p1, c1); const state_2 = scope['state']; - p1.on['click'] = function (e) {if (context.__owl__.status === 5){return}state_2.flag=!state_2.flag}; + p1.on['click'] = function (e) {if (context.__owl__.status === 5){return}const res = (() => { return state_2.flag=!state_2.flag })(); if (typeof res === 'function') { res(e) }}; c1.push({text: \`Toggle\`}); return vn1; }" @@ -3011,7 +3011,7 @@ exports[`t-on t-on with inline statement, part 3 1`] = ` let vn1 = h('button', p1, c1); const state_2 = scope['state']; const someFunction_2 = scope['someFunction']; - p1.on['click'] = function (e) {if (context.__owl__.status === 5){return}state_2.n=someFunction_2(3)}; + p1.on['click'] = function (e) {if (context.__owl__.status === 5){return}const res = (() => { return state_2.n=someFunction_2(3) })(); if (typeof res === 'function') { res(e) }}; c1.push({text: \`Toggle\`}); return vn1; }"