[IMP] component: add support for callable expression in event handler

This commit is contained in:
Sébastien Theys
2021-07-01 11:12:21 +02:00
committed by Géry Debongnie
parent 3e0e8475a6
commit 7ebe0da962
4 changed files with 28 additions and 9 deletions
+1
View File
@@ -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}}`;
@@ -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;
+18
View File
@@ -149,6 +149,24 @@ describe("basic widget properties", () => {
expect(fixture.innerHTML).toBe("<div>1<button>Inc</button></div>");
});
test("support for callable expression in event handler", async () => {
class Counter extends Component {
static template = xml`
<div><t t-esc="state.value"/><input type="text" t-on-input="obj.onInput"/></div>`;
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(`<div><input type="text"></div>`);
const input = (<HTMLElement>counter.el).getElementsByTagName("input")[0];
input.value = "test";
input.dispatchEvent(new Event("input"));
await nextTick();
expect(fixture.innerHTML).toBe(`<div>test<input type="text"></div>`);
});
test("can handle empty props", async () => {
class Child extends Component {
static template = xml`<span><t t-esc="props.val"/></span>`;
+5 -5
View File
@@ -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;
}"