mirror of
https://github.com/odoo/owl.git
synced 2025-10-06 19:59:41 +07:00
[IMP] qweb: reintroduce t-tag directive
will not be compatible with t-model directive !
This commit is contained in:
+27
-8
@@ -54,6 +54,7 @@ class BlockDescription {
|
||||
|
||||
varName: string;
|
||||
blockName: string;
|
||||
dynamicTagName: string | null = null;
|
||||
isRoot: boolean = false;
|
||||
hasDynamicChildren: boolean = false;
|
||||
children: BlockDescription[] = [];
|
||||
@@ -95,6 +96,9 @@ class BlockDescription {
|
||||
if (hasChildren) {
|
||||
params += ", [" + this.children.map((c) => c.varName).join(", ") + "]";
|
||||
}
|
||||
if (this.dynamicTagName) {
|
||||
return `toggler(${this.dynamicTagName}, ${this.blockName}(${this.dynamicTagName})(${params}))`;
|
||||
}
|
||||
return `${this.blockName}(${params})`;
|
||||
} else if (this.type === "list") {
|
||||
return `list(c_block${this.id})`;
|
||||
@@ -304,7 +308,14 @@ export class QWebCompiler {
|
||||
this.addLine(``);
|
||||
for (let block of this.blocks) {
|
||||
if (block.dom) {
|
||||
this.addLine(`let ${block.blockName} = createBlock(\`${block.asXmlString()}\`);`);
|
||||
let xmlString = block.asXmlString();
|
||||
if (block.dynamicTagName) {
|
||||
xmlString = xmlString.replace(/^<\w+/, `<\${tag || '${block.dom.nodeName}'}`);
|
||||
xmlString = xmlString.replace(/\w+>$/, `\${tag || '${block.dom.nodeName}'}>`);
|
||||
this.addLine(`let ${block.blockName} = tag => createBlock(\`${xmlString}\`);`);
|
||||
} else {
|
||||
this.addLine(`let ${block.blockName} = createBlock(\`${xmlString}\`);`);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -514,11 +525,19 @@ export class QWebCompiler {
|
||||
|
||||
compileTDomNode(ast: ASTDomNode, ctx: Context) {
|
||||
let { block, forceNewBlock } = ctx;
|
||||
const isNewBlock = !block || forceNewBlock;
|
||||
const isNewBlock = !block || forceNewBlock || ast.dynamicTag !== null;
|
||||
let codeIdx = this.target.code.length;
|
||||
if (isNewBlock) {
|
||||
if (ast.dynamicTag && ctx.block) {
|
||||
this.insertAnchor(ctx.block!);
|
||||
}
|
||||
block = this.createBlock(block, "block", ctx);
|
||||
this.blocks.push(block);
|
||||
if (ast.dynamicTag) {
|
||||
const tagExpr = this.generateId("tag");
|
||||
this.addLine(`let ${tagExpr} = ${compileExpr(ast.dynamicTag)};`);
|
||||
block.dynamicTagName = tagExpr;
|
||||
}
|
||||
}
|
||||
// attributes
|
||||
const attrs: { [key: string]: string } = {};
|
||||
@@ -989,12 +1008,6 @@ export class QWebCompiler {
|
||||
propString = propVar;
|
||||
}
|
||||
|
||||
let keyArg = `key + \`${key}\``;
|
||||
if (ctx.tKeyExpr) {
|
||||
keyArg = `${ctx.tKeyExpr} + ${keyArg}`;
|
||||
}
|
||||
let blockArgs = `${expr}, ${propString}, ${keyArg}, node, ctx`;
|
||||
|
||||
// slots
|
||||
const hasSlot = !!Object.keys(ast.slots).length;
|
||||
let slotDef: string;
|
||||
@@ -1034,6 +1047,12 @@ export class QWebCompiler {
|
||||
// todo: check the forcenewblock condition
|
||||
this.insertAnchor(block);
|
||||
}
|
||||
|
||||
let keyArg = `key + \`${key}\``;
|
||||
if (ctx.tKeyExpr) {
|
||||
keyArg = `${ctx.tKeyExpr} + ${keyArg}`;
|
||||
}
|
||||
const blockArgs = `${expr}, ${propString}, ${keyArg}, node, ctx`;
|
||||
let blockExpr = `component(${blockArgs})`;
|
||||
if (Object.keys(extraArgs).length) {
|
||||
this.shouldDefineAssign = true;
|
||||
|
||||
@@ -25,9 +25,10 @@
|
||||
// Misc types, constants and helpers
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
const RESERVED_WORDS = "true,false,NaN,null,undefined,debugger,console,window,in,instanceof,new,function,return,this,eval,void,Math,RegExp,Array,Object,Date".split(
|
||||
","
|
||||
);
|
||||
const RESERVED_WORDS =
|
||||
"true,false,NaN,null,undefined,debugger,console,window,in,instanceof,new,function,return,this,eval,void,Math,RegExp,Array,Object,Date".split(
|
||||
","
|
||||
);
|
||||
|
||||
const WORD_REPLACEMENT: { [key: string]: string } = Object.assign(Object.create(null), {
|
||||
and: "&&",
|
||||
|
||||
+10
-11
@@ -35,6 +35,7 @@ export interface ASTComment {
|
||||
export interface ASTDomNode {
|
||||
type: ASTType.DomNode;
|
||||
tag: string;
|
||||
dynamicTag: string | null;
|
||||
attrs: { [key: string]: string };
|
||||
content: AST[];
|
||||
ref: string | null;
|
||||
@@ -289,7 +290,12 @@ const hasBracketsAtTheEnd = /\[[^\[]+\]\s*$/;
|
||||
|
||||
function parseDOMNode(node: Element, ctx: ParsingContext): AST | null {
|
||||
const { tagName } = node;
|
||||
if (tagName === "t") {
|
||||
let dynamicTag = null;
|
||||
if (node.hasAttribute("t-tag")) {
|
||||
dynamicTag = node.getAttribute("t-tag");
|
||||
node.removeAttribute("t-tag");
|
||||
}
|
||||
if (tagName === "t" && !dynamicTag) {
|
||||
return null;
|
||||
}
|
||||
const children: AST[] = [];
|
||||
@@ -373,6 +379,7 @@ function parseDOMNode(node: Element, ctx: ParsingContext): AST | null {
|
||||
return {
|
||||
type: ASTType.DomNode,
|
||||
tag: tagName,
|
||||
dynamicTag,
|
||||
attrs,
|
||||
on,
|
||||
ref,
|
||||
@@ -404,13 +411,9 @@ function parseTEscNode(node: Element, ctx: ParsingContext): AST | null {
|
||||
}
|
||||
if (ast && ast.type === ASTType.DomNode) {
|
||||
return {
|
||||
type: ASTType.DomNode,
|
||||
tag: ast.tag,
|
||||
attrs: ast.attrs,
|
||||
on: ast.on,
|
||||
...ast,
|
||||
ref,
|
||||
content: [tesc],
|
||||
model: ast.model,
|
||||
};
|
||||
}
|
||||
if (ast && ast.type === ASTType.TComponent) {
|
||||
@@ -443,13 +446,9 @@ function parseTRawNode(node: Element, ctx: ParsingContext): AST | null {
|
||||
if (ast && ast.type === ASTType.DomNode) {
|
||||
tRaw.body = ast.content.length ? ast.content : null;
|
||||
return {
|
||||
type: ASTType.DomNode,
|
||||
tag: ast.tag,
|
||||
attrs: ast.attrs,
|
||||
on: ast.on,
|
||||
...ast,
|
||||
ref,
|
||||
content: [tRaw],
|
||||
model: ast.model,
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -43,7 +43,8 @@ describe("basics", () => {
|
||||
expect(fixture.innerHTML).toBe("");
|
||||
expect(status(parent)).toBe("destroyed");
|
||||
expect(error).toBeDefined();
|
||||
const regexp = /Cannot read properties of undefined \(reading 'this'\)|Cannot read property 'this' of undefined/g;
|
||||
const regexp =
|
||||
/Cannot read properties of undefined \(reading 'this'\)|Cannot read property 'this' of undefined/g;
|
||||
expect(error.message).toMatch(regexp);
|
||||
});
|
||||
|
||||
@@ -112,7 +113,8 @@ describe.skip("errors and promises", () => {
|
||||
error = e;
|
||||
}
|
||||
expect(error).toBeDefined();
|
||||
const regexp = /Cannot read properties of undefined \(reading 'crash'\)|Cannot read property 'crash' of undefined/g;
|
||||
const regexp =
|
||||
/Cannot read properties of undefined \(reading 'crash'\)|Cannot read property 'crash' of undefined/g;
|
||||
expect(error.message).toMatch(regexp);
|
||||
|
||||
expect(console.error).toBeCalledTimes(0);
|
||||
@@ -225,7 +227,8 @@ describe.skip("errors and promises", () => {
|
||||
error = e;
|
||||
}
|
||||
expect(error).toBeDefined();
|
||||
const regexp = /Cannot read properties of undefined \(reading 'crash'\)|Cannot read property 'crash' of undefined/g;
|
||||
const regexp =
|
||||
/Cannot read properties of undefined \(reading 'crash'\)|Cannot read property 'crash' of undefined/g;
|
||||
expect(error.message).toMatch(regexp);
|
||||
|
||||
expect(console.error).toBeCalledTimes(0);
|
||||
@@ -251,7 +254,8 @@ describe.skip("errors and promises", () => {
|
||||
error = e;
|
||||
}
|
||||
expect(error).toBeDefined();
|
||||
const regexp = /Cannot read properties of undefined \(reading 'crash'\)|Cannot read property 'crash' of undefined/g;
|
||||
const regexp =
|
||||
/Cannot read properties of undefined \(reading 'crash'\)|Cannot read property 'crash' of undefined/g;
|
||||
expect(error.message).toMatch(regexp);
|
||||
|
||||
expect(console.error).toBeCalledTimes(0);
|
||||
@@ -274,7 +278,8 @@ describe.skip("errors and promises", () => {
|
||||
error = e;
|
||||
}
|
||||
expect(error).toBeDefined();
|
||||
const regexp = /Cannot read properties of undefined \(reading 'y'\)|Cannot read property 'y' of undefined/g;
|
||||
const regexp =
|
||||
/Cannot read properties of undefined \(reading 'y'\)|Cannot read property 'y' of undefined/g;
|
||||
expect(error.message).toMatch(regexp);
|
||||
});
|
||||
|
||||
|
||||
@@ -341,7 +341,8 @@ describe("style and class handling", () => {
|
||||
error = e;
|
||||
}
|
||||
expect(error).toBeDefined();
|
||||
const regexp = /Cannot read properties of undefined \(reading 'crash'\)|Cannot read property 'crash' of undefined/g;
|
||||
const regexp =
|
||||
/Cannot read properties of undefined \(reading 'crash'\)|Cannot read property 'crash' of undefined/g;
|
||||
expect(error.message).toMatch(regexp);
|
||||
expect(fixture.innerHTML).toBe("");
|
||||
});
|
||||
|
||||
@@ -405,7 +405,8 @@ describe("Portal", () => {
|
||||
error = e;
|
||||
}
|
||||
expect(error).toBeDefined();
|
||||
const regexp = /Cannot read properties of undefined \(reading 'crash'\)|Cannot read property 'crash' of undefined/g;
|
||||
const regexp =
|
||||
/Cannot read properties of undefined \(reading 'crash'\)|Cannot read property 'crash' of undefined/g;
|
||||
expect(error.message).toMatch(regexp);
|
||||
});
|
||||
|
||||
|
||||
@@ -0,0 +1,128 @@
|
||||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`qweb t-tag can fallback if falsy tag 1`] = `
|
||||
"function anonymous(bdom, helpers
|
||||
) {
|
||||
let { text, createBlock, list, multi, html, toggler, component } = bdom;
|
||||
let { withDefault, getTemplate, prepareList, withKey, zero, call, callSlot, capture, isBoundary, shallowEqual, setContextValue, toNumber } = helpers;
|
||||
|
||||
let block1 = tag => createBlock(\`<\${tag || 'fallback'}/>\`);
|
||||
|
||||
return function template(ctx, node, key = \\"\\") {
|
||||
let tag1 = ctx['tag'];
|
||||
return toggler(tag1, block1(tag1)());
|
||||
}
|
||||
}"
|
||||
`;
|
||||
|
||||
exports[`qweb t-tag can update 1`] = `
|
||||
"function anonymous(bdom, helpers
|
||||
) {
|
||||
let { text, createBlock, list, multi, html, toggler, component } = bdom;
|
||||
let { withDefault, getTemplate, prepareList, withKey, zero, call, callSlot, capture, isBoundary, shallowEqual, setContextValue, toNumber } = helpers;
|
||||
|
||||
let block1 = tag => createBlock(\`<\${tag || 't'}/>\`);
|
||||
|
||||
return function template(ctx, node, key = \\"\\") {
|
||||
let tag1 = ctx['tag'];
|
||||
return toggler(tag1, block1(tag1)());
|
||||
}
|
||||
}"
|
||||
`;
|
||||
|
||||
exports[`qweb t-tag simple usecases 1`] = `
|
||||
"function anonymous(bdom, helpers
|
||||
) {
|
||||
let { text, createBlock, list, multi, html, toggler, component } = bdom;
|
||||
let { withDefault, getTemplate, prepareList, withKey, zero, call, callSlot, capture, isBoundary, shallowEqual, setContextValue, toNumber } = helpers;
|
||||
|
||||
let block1 = tag => createBlock(\`<\${tag || 't'}/>\`);
|
||||
|
||||
return function template(ctx, node, key = \\"\\") {
|
||||
let tag1 = 'div';
|
||||
return toggler(tag1, block1(tag1)());
|
||||
}
|
||||
}"
|
||||
`;
|
||||
|
||||
exports[`qweb t-tag simple usecases 2`] = `
|
||||
"function anonymous(bdom, helpers
|
||||
) {
|
||||
let { text, createBlock, list, multi, html, toggler, component } = bdom;
|
||||
let { withDefault, getTemplate, prepareList, withKey, zero, call, callSlot, capture, isBoundary, shallowEqual, setContextValue, toNumber } = helpers;
|
||||
|
||||
let block1 = tag => createBlock(\`<\${tag || 't'}>text</\${tag || 't'}>\`);
|
||||
|
||||
return function template(ctx, node, key = \\"\\") {
|
||||
let tag1 = ctx['tag'];
|
||||
return toggler(tag1, block1(tag1)());
|
||||
}
|
||||
}"
|
||||
`;
|
||||
|
||||
exports[`qweb t-tag with multiple attributes 1`] = `
|
||||
"function anonymous(bdom, helpers
|
||||
) {
|
||||
let { text, createBlock, list, multi, html, toggler, component } = bdom;
|
||||
let { withDefault, getTemplate, prepareList, withKey, zero, call, callSlot, capture, isBoundary, shallowEqual, setContextValue, toNumber } = helpers;
|
||||
|
||||
let block1 = tag => createBlock(\`<\${tag || 't'} class=\\"blueberry\\" taste=\\"raspberry\\">gooseberry</\${tag || 't'}>\`);
|
||||
|
||||
return function template(ctx, node, key = \\"\\") {
|
||||
let tag1 = ctx['tag'];
|
||||
return toggler(tag1, block1(tag1)());
|
||||
}
|
||||
}"
|
||||
`;
|
||||
|
||||
exports[`qweb t-tag with multiple child nodes 1`] = `
|
||||
"function anonymous(bdom, helpers
|
||||
) {
|
||||
let { text, createBlock, list, multi, html, toggler, component } = bdom;
|
||||
let { withDefault, getTemplate, prepareList, withKey, zero, call, callSlot, capture, isBoundary, shallowEqual, setContextValue, toNumber } = helpers;
|
||||
|
||||
let block1 = tag => createBlock(\`<\${tag || 't'}> pear <span>apple</span> strawberry </\${tag || 't'}>\`);
|
||||
|
||||
return function template(ctx, node, key = \\"\\") {
|
||||
let tag1 = ctx['tag'];
|
||||
return toggler(tag1, block1(tag1)());
|
||||
}
|
||||
}"
|
||||
`;
|
||||
|
||||
exports[`qweb t-tag with multiple t-tag in same template 1`] = `
|
||||
"function anonymous(bdom, helpers
|
||||
) {
|
||||
let { text, createBlock, list, multi, html, toggler, component } = bdom;
|
||||
let { withDefault, getTemplate, prepareList, withKey, zero, call, callSlot, capture, isBoundary, shallowEqual, setContextValue, toNumber } = helpers;
|
||||
|
||||
let block1 = tag => createBlock(\`<\${tag || 't'}><block-child-0/></\${tag || 't'}>\`);
|
||||
let block2 = tag => createBlock(\`<\${tag || 't'}>baz</\${tag || 't'}>\`);
|
||||
|
||||
return function template(ctx, node, key = \\"\\") {
|
||||
let tag1 = ctx['outer'];
|
||||
let tag2 = ctx['inner'];
|
||||
let b2 = toggler(tag2, block2(tag2)());
|
||||
return toggler(tag1, block1(tag1)([], [b2]));
|
||||
}
|
||||
}"
|
||||
`;
|
||||
|
||||
exports[`qweb t-tag with multiple t-tag in same template, part 2 1`] = `
|
||||
"function anonymous(bdom, helpers
|
||||
) {
|
||||
let { text, createBlock, list, multi, html, toggler, component } = bdom;
|
||||
let { withDefault, getTemplate, prepareList, withKey, zero, call, callSlot, capture, isBoundary, shallowEqual, setContextValue, toNumber } = helpers;
|
||||
|
||||
let block2 = tag => createBlock(\`<\${tag || 't'}>bar</\${tag || 't'}>\`);
|
||||
let block3 = tag => createBlock(\`<\${tag || 't'}>baz</\${tag || 't'}>\`);
|
||||
|
||||
return function template(ctx, node, key = \\"\\") {
|
||||
let tag1 = ctx['brother'];
|
||||
let b2 = toggler(tag1, block2(tag1)());
|
||||
let tag2 = ctx['brother'];
|
||||
let b3 = toggler(tag2, block3(tag2)());
|
||||
return multi([b2, b3]);
|
||||
}
|
||||
}"
|
||||
`;
|
||||
@@ -40,6 +40,7 @@ describe("qweb parser", () => {
|
||||
expect(parse(template)).toEqual({
|
||||
type: ASTType.DomNode,
|
||||
tag: "div",
|
||||
dynamicTag: null,
|
||||
content: [],
|
||||
attrs: {},
|
||||
on: {},
|
||||
@@ -66,6 +67,7 @@ describe("qweb parser", () => {
|
||||
expect(parse("<div></div>")).toEqual({
|
||||
type: ASTType.DomNode,
|
||||
tag: "div",
|
||||
dynamicTag: null,
|
||||
attrs: {},
|
||||
on: {},
|
||||
ref: null,
|
||||
@@ -78,6 +80,7 @@ describe("qweb parser", () => {
|
||||
expect(parse("<div>some text</div>")).toEqual({
|
||||
type: ASTType.DomNode,
|
||||
tag: "div",
|
||||
dynamicTag: null,
|
||||
attrs: {},
|
||||
on: {},
|
||||
ref: null,
|
||||
@@ -90,6 +93,7 @@ describe("qweb parser", () => {
|
||||
expect(parse("<div>some text<span>inside</span></div>")).toEqual({
|
||||
type: ASTType.DomNode,
|
||||
tag: "div",
|
||||
dynamicTag: null,
|
||||
attrs: {},
|
||||
on: {},
|
||||
ref: null,
|
||||
@@ -99,6 +103,7 @@ describe("qweb parser", () => {
|
||||
{
|
||||
type: ASTType.DomNode,
|
||||
tag: "span",
|
||||
dynamicTag: null,
|
||||
attrs: {},
|
||||
on: {},
|
||||
ref: null,
|
||||
@@ -116,6 +121,7 @@ describe("qweb parser", () => {
|
||||
{
|
||||
type: ASTType.DomNode,
|
||||
tag: "div",
|
||||
dynamicTag: null,
|
||||
attrs: {},
|
||||
on: {},
|
||||
ref: null,
|
||||
@@ -125,6 +131,7 @@ describe("qweb parser", () => {
|
||||
{
|
||||
type: ASTType.DomNode,
|
||||
tag: "span",
|
||||
dynamicTag: null,
|
||||
attrs: {},
|
||||
on: {},
|
||||
ref: null,
|
||||
@@ -143,6 +150,7 @@ describe("qweb parser", () => {
|
||||
{
|
||||
type: ASTType.DomNode,
|
||||
tag: "span",
|
||||
dynamicTag: null,
|
||||
attrs: {},
|
||||
on: {},
|
||||
ref: null,
|
||||
@@ -157,6 +165,7 @@ describe("qweb parser", () => {
|
||||
expect(parse(`<div class="abc">foo</div>`)).toEqual({
|
||||
type: ASTType.DomNode,
|
||||
tag: "div",
|
||||
dynamicTag: null,
|
||||
attrs: { class: "abc" },
|
||||
on: {},
|
||||
ref: null,
|
||||
@@ -186,6 +195,7 @@ describe("qweb parser", () => {
|
||||
expect(parse(`<span t-esc="text"/>`)).toEqual({
|
||||
type: ASTType.DomNode,
|
||||
tag: "span",
|
||||
dynamicTag: null,
|
||||
attrs: {},
|
||||
on: {},
|
||||
ref: null,
|
||||
@@ -206,6 +216,7 @@ describe("qweb parser", () => {
|
||||
expect(parse(`<div t-esc="text">hey</div>`)).toEqual({
|
||||
type: ASTType.DomNode,
|
||||
tag: "div",
|
||||
dynamicTag: null,
|
||||
attrs: {},
|
||||
on: {},
|
||||
ref: null,
|
||||
@@ -230,6 +241,7 @@ describe("qweb parser", () => {
|
||||
expect(parse(`<div t-raw="text"/>`)).toEqual({
|
||||
type: ASTType.DomNode,
|
||||
tag: "div",
|
||||
dynamicTag: null,
|
||||
attrs: {},
|
||||
on: {},
|
||||
ref: null,
|
||||
@@ -242,6 +254,7 @@ describe("qweb parser", () => {
|
||||
expect(parse(`<div t-raw="text">body</div>`)).toEqual({
|
||||
type: ASTType.DomNode,
|
||||
tag: "div",
|
||||
dynamicTag: null,
|
||||
attrs: {},
|
||||
on: {},
|
||||
ref: null,
|
||||
@@ -260,6 +273,7 @@ describe("qweb parser", () => {
|
||||
expect(parse(`<div><t t-if="condition">hey</t></div>`)).toEqual({
|
||||
type: ASTType.DomNode,
|
||||
tag: "div",
|
||||
dynamicTag: null,
|
||||
attrs: {},
|
||||
on: {},
|
||||
ref: null,
|
||||
@@ -286,6 +300,7 @@ describe("qweb parser", () => {
|
||||
content: {
|
||||
type: ASTType.DomNode,
|
||||
tag: "div",
|
||||
dynamicTag: null,
|
||||
attrs: {},
|
||||
on: {},
|
||||
ref: null,
|
||||
@@ -361,6 +376,7 @@ describe("qweb parser", () => {
|
||||
content: {
|
||||
type: ASTType.DomNode,
|
||||
tag: "div",
|
||||
dynamicTag: null,
|
||||
attrs: {},
|
||||
on: {},
|
||||
ref: null,
|
||||
@@ -378,6 +394,7 @@ describe("qweb parser", () => {
|
||||
content: {
|
||||
type: ASTType.DomNode,
|
||||
tag: "h1",
|
||||
dynamicTag: null,
|
||||
attrs: {},
|
||||
on: {},
|
||||
ref: null,
|
||||
@@ -389,6 +406,7 @@ describe("qweb parser", () => {
|
||||
tElse: {
|
||||
type: ASTType.DomNode,
|
||||
tag: "h2",
|
||||
dynamicTag: null,
|
||||
attrs: {},
|
||||
on: {},
|
||||
ref: null,
|
||||
@@ -437,6 +455,7 @@ describe("qweb parser", () => {
|
||||
attrs: {},
|
||||
on: {},
|
||||
tag: "div",
|
||||
dynamicTag: null,
|
||||
ref: null,
|
||||
model: null,
|
||||
content: [{ type: ASTType.Text, value: "ok" }],
|
||||
@@ -455,6 +474,7 @@ describe("qweb parser", () => {
|
||||
attrs: {},
|
||||
on: {},
|
||||
tag: "div",
|
||||
dynamicTag: null,
|
||||
ref: null,
|
||||
model: null,
|
||||
content: [{ type: ASTType.Text, value: "ok" }],
|
||||
@@ -486,6 +506,7 @@ describe("qweb parser", () => {
|
||||
).toEqual({
|
||||
type: ASTType.DomNode,
|
||||
tag: "div",
|
||||
dynamicTag: null,
|
||||
attrs: {},
|
||||
on: {},
|
||||
ref: null,
|
||||
@@ -559,6 +580,7 @@ describe("qweb parser", () => {
|
||||
body: {
|
||||
type: ASTType.DomNode,
|
||||
tag: "div",
|
||||
dynamicTag: null,
|
||||
attrs: {},
|
||||
on: {},
|
||||
ref: null,
|
||||
@@ -603,6 +625,7 @@ describe("qweb parser", () => {
|
||||
body: {
|
||||
type: ASTType.DomNode,
|
||||
tag: "span",
|
||||
dynamicTag: null,
|
||||
attrs: {},
|
||||
on: {},
|
||||
ref: null,
|
||||
@@ -637,6 +660,7 @@ describe("qweb parser", () => {
|
||||
content: {
|
||||
type: ASTType.DomNode,
|
||||
tag: "span",
|
||||
dynamicTag: null,
|
||||
attrs: {},
|
||||
on: {},
|
||||
ref: null,
|
||||
@@ -667,6 +691,7 @@ describe("qweb parser", () => {
|
||||
body: {
|
||||
type: ASTType.DomNode,
|
||||
tag: "option",
|
||||
dynamicTag: null,
|
||||
attrs: {
|
||||
"t-att-selected": "category.id==options.active_category_id",
|
||||
"t-att-value": "category.id",
|
||||
@@ -694,6 +719,7 @@ describe("qweb parser", () => {
|
||||
ref: null,
|
||||
model: null,
|
||||
tag: "div",
|
||||
dynamicTag: null,
|
||||
content: [
|
||||
{
|
||||
type: ASTType.TForEach,
|
||||
@@ -734,6 +760,7 @@ describe("qweb parser", () => {
|
||||
body: {
|
||||
type: ASTType.DomNode,
|
||||
tag: "span",
|
||||
dynamicTag: null,
|
||||
on: {},
|
||||
ref: null,
|
||||
model: null,
|
||||
@@ -840,6 +867,7 @@ describe("qweb parser", () => {
|
||||
expect(parse(`<div t-call="blabla" />`)).toEqual({
|
||||
type: ASTType.DomNode,
|
||||
tag: "div",
|
||||
dynamicTag: null,
|
||||
attrs: {},
|
||||
on: {},
|
||||
ref: null,
|
||||
@@ -876,6 +904,7 @@ describe("qweb parser", () => {
|
||||
expect(parse(`<button t-on-click="add">Click</button>`)).toEqual({
|
||||
type: ASTType.DomNode,
|
||||
tag: "button",
|
||||
dynamicTag: null,
|
||||
attrs: {},
|
||||
on: { click: "add" },
|
||||
ref: null,
|
||||
@@ -952,6 +981,7 @@ describe("qweb parser", () => {
|
||||
{
|
||||
type: ASTType.DomNode,
|
||||
tag: "span",
|
||||
dynamicTag: null,
|
||||
attrs: {},
|
||||
content: [],
|
||||
ref: null,
|
||||
@@ -961,6 +991,7 @@ describe("qweb parser", () => {
|
||||
{
|
||||
type: ASTType.DomNode,
|
||||
tag: "div",
|
||||
dynamicTag: null,
|
||||
attrs: {},
|
||||
content: [],
|
||||
ref: null,
|
||||
@@ -1156,6 +1187,7 @@ describe("qweb parser", () => {
|
||||
content: {
|
||||
type: ASTType.DomNode,
|
||||
tag: "div",
|
||||
dynamicTag: null,
|
||||
attrs: {},
|
||||
on: {},
|
||||
ref: null,
|
||||
@@ -1172,6 +1204,7 @@ describe("qweb parser", () => {
|
||||
content: {
|
||||
type: ASTType.DomNode,
|
||||
tag: "div",
|
||||
dynamicTag: null,
|
||||
attrs: {},
|
||||
on: {},
|
||||
ref: null,
|
||||
@@ -1189,6 +1222,7 @@ describe("qweb parser", () => {
|
||||
expect(parse(`<div t-ref="name">hey</div>`)).toEqual({
|
||||
type: ASTType.DomNode,
|
||||
tag: "div",
|
||||
dynamicTag: null,
|
||||
attrs: {},
|
||||
on: {},
|
||||
ref: "name",
|
||||
@@ -1201,6 +1235,7 @@ describe("qweb parser", () => {
|
||||
expect(parse(`<div t-raw="text" t-ref="name">body</div>`)).toEqual({
|
||||
type: ASTType.DomNode,
|
||||
tag: "div",
|
||||
dynamicTag: null,
|
||||
attrs: {},
|
||||
on: {},
|
||||
ref: "name",
|
||||
@@ -1215,6 +1250,7 @@ describe("qweb parser", () => {
|
||||
expect(parse(`<div t-esc="text" t-ref="name">body</div>`)).toEqual({
|
||||
type: ASTType.DomNode,
|
||||
tag: "div",
|
||||
dynamicTag: null,
|
||||
attrs: {},
|
||||
on: {},
|
||||
ref: "name",
|
||||
@@ -1261,6 +1297,7 @@ describe("qweb parser", () => {
|
||||
ref: null,
|
||||
model: null,
|
||||
tag: "div",
|
||||
dynamicTag: null,
|
||||
type: 2,
|
||||
},
|
||||
type: 16,
|
||||
@@ -1290,6 +1327,7 @@ describe("qweb parser", () => {
|
||||
on: {},
|
||||
ref: null,
|
||||
tag: "input",
|
||||
dynamicTag: null,
|
||||
model: {
|
||||
baseExpr: "state",
|
||||
expr: "'stuff'",
|
||||
@@ -1307,6 +1345,7 @@ describe("qweb parser", () => {
|
||||
on: {},
|
||||
ref: null,
|
||||
tag: "input",
|
||||
dynamicTag: null,
|
||||
model: {
|
||||
baseExpr: "state",
|
||||
expr: "'stuff'",
|
||||
@@ -1324,6 +1363,7 @@ describe("qweb parser", () => {
|
||||
on: {},
|
||||
ref: null,
|
||||
tag: "input",
|
||||
dynamicTag: null,
|
||||
model: {
|
||||
baseExpr: "state",
|
||||
expr: "'stuff'",
|
||||
@@ -1342,6 +1382,7 @@ describe("qweb parser", () => {
|
||||
on: {},
|
||||
ref: null,
|
||||
tag: "textarea",
|
||||
dynamicTag: null,
|
||||
model: {
|
||||
baseExpr: "state",
|
||||
expr: "'stuff'",
|
||||
@@ -1359,6 +1400,7 @@ describe("qweb parser", () => {
|
||||
on: {},
|
||||
ref: null,
|
||||
tag: "input",
|
||||
dynamicTag: null,
|
||||
model: {
|
||||
baseExpr: "state",
|
||||
expr: "'stuff'",
|
||||
@@ -1376,6 +1418,7 @@ describe("qweb parser", () => {
|
||||
on: {},
|
||||
ref: null,
|
||||
tag: "input",
|
||||
dynamicTag: null,
|
||||
model: {
|
||||
baseExpr: "state",
|
||||
expr: "'stuff'",
|
||||
@@ -1393,6 +1436,7 @@ describe("qweb parser", () => {
|
||||
on: {},
|
||||
ref: null,
|
||||
tag: "input",
|
||||
dynamicTag: null,
|
||||
model: {
|
||||
baseExpr: "state",
|
||||
expr: "'stuff'",
|
||||
@@ -1403,4 +1447,20 @@ describe("qweb parser", () => {
|
||||
specialInitTargetAttr: "checked",
|
||||
},
|
||||
});
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// t-tag
|
||||
// ---------------------------------------------------------------------------
|
||||
test("t-tag", async () => {
|
||||
expect(parse(`<div t-tag="theTag" />`)).toEqual({
|
||||
type: ASTType.DomNode,
|
||||
attrs: {},
|
||||
content: [],
|
||||
on: {},
|
||||
ref: null,
|
||||
tag: "div",
|
||||
dynamicTag: "theTag",
|
||||
model: null,
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -1,14 +1,25 @@
|
||||
import { renderToString, snapshotEverything } from "../helpers";
|
||||
import { mount, patch } from "../../src/blockdom";
|
||||
import { makeTestFixture, renderToBdom, renderToString, snapshotEverything } from "../helpers";
|
||||
|
||||
snapshotEverything();
|
||||
|
||||
let fixture: HTMLElement;
|
||||
|
||||
beforeEach(() => {
|
||||
fixture = makeTestFixture();
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
fixture.remove();
|
||||
});
|
||||
|
||||
describe("qweb t-tag", () => {
|
||||
test.skip("simple usecases", () => {
|
||||
test("simple usecases", () => {
|
||||
expect(renderToString(`<t t-tag="'div'"></t>`)).toBe("<div></div>");
|
||||
expect(renderToString(`<t t-tag="tag">text</t>`, { tag: "span" })).toBe("<span>text</span>");
|
||||
});
|
||||
|
||||
test.skip("with multiple child nodes", () => {
|
||||
test("with multiple child nodes", () => {
|
||||
const template = `
|
||||
<t t-tag="tag">
|
||||
pear
|
||||
@@ -20,9 +31,39 @@ describe("qweb t-tag", () => {
|
||||
);
|
||||
});
|
||||
|
||||
test.skip("with multiple attributes", () => {
|
||||
test("with multiple attributes", () => {
|
||||
const template = `<t t-tag="tag" class="blueberry" taste="raspberry">gooseberry</t>`;
|
||||
const expected = `<div taste=\"raspberry\" class=\"blueberry\">gooseberry</div>`;
|
||||
const expected = `<div class=\"blueberry\" taste=\"raspberry\">gooseberry</div>`;
|
||||
expect(renderToString(template, { tag: "div" })).toBe(expected);
|
||||
});
|
||||
|
||||
test("can fallback if falsy tag", () => {
|
||||
const template = `<fallback t-tag="tag"/>`;
|
||||
expect(renderToString(template, { tag: "div" })).toBe(`<div></div>`);
|
||||
expect(renderToString(template, { tag: "" })).toBe(`<fallback></fallback>`);
|
||||
expect(renderToString(template, { tag: undefined })).toBe(`<fallback></fallback>`);
|
||||
expect(renderToString(template, { tag: null })).toBe(`<fallback></fallback>`);
|
||||
expect(renderToString(template, { tag: false })).toBe(`<fallback></fallback>`);
|
||||
});
|
||||
|
||||
test("with multiple t-tag in same template", () => {
|
||||
const template = `<t t-tag="outer"><t t-tag="inner">baz</t></t>`;
|
||||
expect(renderToString(template, { outer: "foo", inner: "bar" })).toBe(
|
||||
`<foo><bar>baz</bar></foo>`
|
||||
);
|
||||
});
|
||||
|
||||
test("with multiple t-tag in same template, part 2", () => {
|
||||
const template = `<t t-tag="brother">bar</t><t t-tag="brother">baz</t>`;
|
||||
expect(renderToString(template, { brother: "foo" })).toBe(`<foo>bar</foo><foo>baz</foo>`);
|
||||
});
|
||||
|
||||
test("can update", () => {
|
||||
const template = `<t t-tag="tag"></t>`;
|
||||
const bdom = renderToBdom(template, { tag: "yop" });
|
||||
mount(bdom, fixture);
|
||||
expect(fixture.innerHTML).toBe("<yop></yop>");
|
||||
patch(bdom, renderToBdom(template, { tag: "gnap" }));
|
||||
expect(fixture.innerHTML).toBe("<gnap></gnap>");
|
||||
});
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user