mirror of
https://github.com/odoo/owl.git
synced 2025-10-06 19:59:41 +07:00
[FIX] qweb: accept assignations in qweb expressions
closes #560 closes #569
This commit is contained in:
@@ -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
|
// note that the space after typeof is relevant. It makes sure that the formatted
|
||||||
// expression has a space after typeof
|
// expression has a space after typeof
|
||||||
const OPERATORS = ".,===,==,+,!==,!=,!,||,&&,>=,>,<=,<,?,-,*,/,%,typeof ,=>".split(",");
|
const OPERATORS = ".,===,==,+,!==,!=,!,||,&&,>=,>,<=,<,?,-,*,/,%,typeof ,=>,=".split(",");
|
||||||
|
|
||||||
type Tokenizer = (expr: string) => Token | false;
|
type Tokenizer = (expr: string) => Token | false;
|
||||||
|
|
||||||
|
|||||||
@@ -2026,6 +2026,24 @@ describe("other directives with t-component", () => {
|
|||||||
expect(flag).toBe(true);
|
expect(flag).toBe(true);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test("t-on with inline statement", async () => {
|
||||||
|
class Child extends Component<any, any> {
|
||||||
|
static template = xml`<span>child</span>`;
|
||||||
|
}
|
||||||
|
|
||||||
|
class Parent extends Component<any, any> {
|
||||||
|
static template = xml`<div><Child t-on-click="state.n = state.n + 1"/></div>`;
|
||||||
|
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 () => {
|
test("t-on with handler bound to argument", async () => {
|
||||||
expect.assertions(3);
|
expect.assertions(3);
|
||||||
env.qweb.addTemplates(`
|
env.qweb.addTemplates(`
|
||||||
|
|||||||
@@ -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`] = `
|
exports[`t-on t-on with prevent and self modifiers (order matters) 1`] = `
|
||||||
"function anonymous(context, extra
|
"function anonymous(context, extra
|
||||||
) {
|
) {
|
||||||
|
|||||||
@@ -1293,6 +1293,37 @@ describe.only("t-on", () => {
|
|||||||
expect(owner.state.counter).toBe(2);
|
expect(owner.state.counter).toBe(2);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test("t-on with inline statement, part 2", () => {
|
||||||
|
qweb.addTemplate("test", `<button t-on-click="state.flag = !state.flag">Toggle</button>`);
|
||||||
|
let owner = {
|
||||||
|
state: {
|
||||||
|
flag: true
|
||||||
|
}
|
||||||
|
};
|
||||||
|
const node = renderToDOM(qweb, "test", owner, { handlers: [] });
|
||||||
|
expect(owner.state.flag).toBe(true);
|
||||||
|
(<HTMLElement>node).click();
|
||||||
|
expect(owner.state.flag).toBe(false);
|
||||||
|
(<HTMLElement>node).click();
|
||||||
|
expect(owner.state.flag).toBe(true);
|
||||||
|
});
|
||||||
|
|
||||||
|
test("t-on with inline statement, part 3", () => {
|
||||||
|
qweb.addTemplate("test", `<button t-on-click="state.n = someFunction(3)">Toggle</button>`);
|
||||||
|
let owner = {
|
||||||
|
someFunction(n) {
|
||||||
|
return n + 1;
|
||||||
|
},
|
||||||
|
state: {
|
||||||
|
n: 11
|
||||||
|
}
|
||||||
|
};
|
||||||
|
const node = renderToDOM(qweb, "test", owner, { handlers: [] });
|
||||||
|
expect(owner.state.n).toBe(11);
|
||||||
|
(<HTMLElement>node).click();
|
||||||
|
expect(owner.state.n).toBe(4);
|
||||||
|
});
|
||||||
|
|
||||||
test("t-on with prevent and/or stop modifiers", async () => {
|
test("t-on with prevent and/or stop modifiers", async () => {
|
||||||
expect.assertions(7);
|
expect.assertions(7);
|
||||||
qweb.addTemplate(
|
qweb.addTemplate(
|
||||||
|
|||||||
@@ -170,4 +170,11 @@ describe("expression evaluation", () => {
|
|||||||
"scope['list'].map((elem,index)=>elem+index)"
|
"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");
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
Reference in New Issue
Block a user