From 4e22dbcad6305c09cf372242bfbeb7397bfdd563 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?G=C3=A9ry=20Debongnie?= Date: Thu, 12 Dec 2019 13:17:51 +0100 Subject: [PATCH] [FIX] qweb: accept assignations in qweb expressions closes #560 closes #569 --- src/qweb/expression_parser.ts | 2 +- tests/component/component.test.ts | 18 +++++++++++++ tests/qweb/__snapshots__/qweb.test.ts.snap | 28 +++++++++++++++++++ tests/qweb/qweb.test.ts | 31 ++++++++++++++++++++++ tests/qweb/qweb_expressions.test.ts | 7 +++++ 5 files changed, 85 insertions(+), 1 deletion(-) diff --git a/src/qweb/expression_parser.ts b/src/qweb/expression_parser.ts index 3a02dfd7..e57b1eac 100644 --- a/src/qweb/expression_parser.ts +++ b/src/qweb/expression_parser.ts @@ -81,7 +81,7 @@ const STATIC_TOKEN_MAP: { [key: string]: TKind } = { // note that the space after typeof is relevant. It makes sure that the formatted // expression has a space after typeof -const OPERATORS = ".,===,==,+,!==,!=,!,||,&&,>=,>,<=,<,?,-,*,/,%,typeof ,=>".split(","); +const OPERATORS = ".,===,==,+,!==,!=,!,||,&&,>=,>,<=,<,?,-,*,/,%,typeof ,=>,=".split(","); type Tokenizer = (expr: string) => Token | false; diff --git a/tests/component/component.test.ts b/tests/component/component.test.ts index 25e40613..f87f828b 100644 --- a/tests/component/component.test.ts +++ b/tests/component/component.test.ts @@ -2026,6 +2026,24 @@ describe("other directives with t-component", () => { expect(flag).toBe(true); }); + test("t-on with inline statement", async () => { + class Child extends Component { + static template = xml`child`; + } + + class Parent extends Component { + static template = xml`
`; + static components = { Child }; + state = {n: 3}; + } + const parent = new Parent(); + await parent.mount(fixture); + expect(parent.state.n).toBe(3); + fixture.querySelector("span")!.click(); + expect(parent.state.n).toBe(4); + }); + + test("t-on with handler bound to argument", async () => { expect.assertions(3); env.qweb.addTemplates(` diff --git a/tests/qweb/__snapshots__/qweb.test.ts.snap b/tests/qweb/__snapshots__/qweb.test.ts.snap index 10f2f431..7a4aeb04 100644 --- a/tests/qweb/__snapshots__/qweb.test.ts.snap +++ b/tests/qweb/__snapshots__/qweb.test.ts.snap @@ -2308,6 +2308,34 @@ exports[`t-on t-on with inline statement 1`] = ` }" `; +exports[`t-on t-on with inline statement, part 2 1`] = ` +"function anonymous(context, extra +) { + // Template name: \\"test\\" + let scope = Object.create(context); + var h = this.h; + let c1 = [], p1 = {key:1,on:{}}; + var vn1 = h('button', p1, c1); + p1.on['click'] = function (e) {if (!context.__owl__.isMounted){return}scope['state'].flag=!scope['state'].flag}; + c1.push({text: \`Toggle\`}); + return vn1; +}" +`; + +exports[`t-on t-on with inline statement, part 3 1`] = ` +"function anonymous(context, extra +) { + // Template name: \\"test\\" + let scope = Object.create(context); + var h = this.h; + let c1 = [], p1 = {key:1,on:{}}; + var vn1 = h('button', p1, c1); + p1.on['click'] = function (e) {if (!context.__owl__.isMounted){return}scope['state'].n=scope['someFunction'](3)}; + c1.push({text: \`Toggle\`}); + 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 ed6254fd..c3a5255a 100644 --- a/tests/qweb/qweb.test.ts +++ b/tests/qweb/qweb.test.ts @@ -1293,6 +1293,37 @@ describe.only("t-on", () => { expect(owner.state.counter).toBe(2); }); + test("t-on with inline statement, part 2", () => { + qweb.addTemplate("test", ``); + let owner = { + state: { + flag: true + } + }; + const node = renderToDOM(qweb, "test", owner, { handlers: [] }); + expect(owner.state.flag).toBe(true); + (node).click(); + expect(owner.state.flag).toBe(false); + (node).click(); + expect(owner.state.flag).toBe(true); + }); + + test("t-on with inline statement, part 3", () => { + qweb.addTemplate("test", ``); + let owner = { + someFunction(n) { + return n + 1; + }, + state: { + n: 11 + } + }; + const node = renderToDOM(qweb, "test", owner, { handlers: [] }); + expect(owner.state.n).toBe(11); + (node).click(); + expect(owner.state.n).toBe(4); + }); + test("t-on with prevent and/or stop modifiers", async () => { expect.assertions(7); qweb.addTemplate( diff --git a/tests/qweb/qweb_expressions.test.ts b/tests/qweb/qweb_expressions.test.ts index 52ba87ae..abb1ea9b 100644 --- a/tests/qweb/qweb_expressions.test.ts +++ b/tests/qweb/qweb_expressions.test.ts @@ -170,4 +170,11 @@ describe("expression evaluation", () => { "scope['list'].map((elem,index)=>elem+index)" ); }); + + test("assignation", () => { + expect(compileExpr("a = b", {})).toBe("scope['a']=scope['b']"); + expect(compileExpr("a += b", {})).toBe("scope['a']+=scope['b']"); + expect(compileExpr("a -= b", {})).toBe("scope['a']-=scope['b']"); + expect(compileExpr("a.b = !a.b", {})).toBe("scope['a'].b=!scope['a'].b"); + }); });