[FIX] compiler: allow t-out on component tag

Before this commit, the template parser would allow using t-esc on a
component tag (<MyComponent t-esc="expr"/>) but would incorrectly ignore
the component when parsing a t-out: <MyComponent t-out="expr"/> would be
parsed as <t t-out="expr"/>

This commit solves the issue, and also, moves the `t-out` parsing code
next to `t-esc` so they have the same priority relatively to other
directives.

closes #1483
This commit is contained in:
Géry Debongnie
2023-07-19 14:55:25 +02:00
committed by Sam Degueldre
parent 0d9d21a5c1
commit 2e07799250
2 changed files with 24 additions and 19 deletions
+18 -19
View File
@@ -235,10 +235,10 @@ function parseNode(node: Node, ctx: ParsingContext): AST | null {
parseTCall(node, ctx) || parseTCall(node, ctx) ||
parseTCallBlock(node, ctx) || parseTCallBlock(node, ctx) ||
parseTEscNode(node, ctx) || parseTEscNode(node, ctx) ||
parseTOutNode(node, ctx) ||
parseTKey(node, ctx) || parseTKey(node, ctx) ||
parseTTranslation(node, ctx) || parseTTranslation(node, ctx) ||
parseTSlot(node, ctx) || parseTSlot(node, ctx) ||
parseTOutNode(node, ctx) ||
parseComponent(node, ctx) || parseComponent(node, ctx) ||
parseDOMNode(node, ctx) || parseDOMNode(node, ctx) ||
parseTSetNode(node, ctx) || parseTSetNode(node, ctx) ||
@@ -444,9 +444,6 @@ function parseTEscNode(node: Element, ctx: ParsingContext): AST | null {
content: [tesc], content: [tesc],
}; };
} }
if (ast.type === ASTType.TComponent) {
throw new OwlError("t-esc is not supported on Component nodes");
}
return tesc; return tesc;
} }
@@ -941,21 +938,23 @@ function normalizeTIf(el: Element) {
* *
* @param el the element containing the tree that should be normalized * @param el the element containing the tree that should be normalized
*/ */
function normalizeTEsc(el: Element) { function normalizeTEscTOut(el: Element) {
const elements = [...el.querySelectorAll("[t-esc]")].filter( for (const d of ["t-esc", "t-out"]) {
(el) => el.tagName[0] === el.tagName[0].toUpperCase() || el.hasAttribute("t-component") const elements = [...el.querySelectorAll(`[${d}]`)].filter(
); (el) => el.tagName[0] === el.tagName[0].toUpperCase() || el.hasAttribute("t-component")
for (const el of elements) { );
if (el.childNodes.length) { for (const el of elements) {
throw new OwlError("Cannot have t-esc on a component that already has content"); if (el.childNodes.length) {
throw new OwlError(`Cannot have ${d} on a component that already has content`);
}
const value = el.getAttribute(d);
el.removeAttribute(d);
const t = el.ownerDocument.createElement("t");
if (value != null) {
t.setAttribute(d, value);
}
el.appendChild(t);
} }
const value = el.getAttribute("t-esc");
el.removeAttribute("t-esc");
const t = el.ownerDocument.createElement("t");
if (value != null) {
t.setAttribute("t-esc", value);
}
el.appendChild(t);
} }
} }
@@ -967,7 +966,7 @@ function normalizeTEsc(el: Element) {
*/ */
function normalizeXML(el: Element) { function normalizeXML(el: Element) {
normalizeTIf(el); normalizeTIf(el);
normalizeTEsc(el); normalizeTEscTOut(el);
} }
/** /**
+6
View File
@@ -1569,6 +1569,12 @@ describe("qweb parser", () => {
); );
}); });
test("component with t-out", async () => {
expect(parse(`<MyComponent t-out="someValue"/>`)).toEqual(
parse(`<MyComponent><t t-out="someValue"/></MyComponent>`)
);
});
test("component with t-esc and content", async () => { test("component with t-esc and content", async () => {
expect(() => parse(`<MyComponent t-esc="someValue">Some content</MyComponent>`)).toThrow( expect(() => parse(`<MyComponent t-esc="someValue">Some content</MyComponent>`)).toThrow(
"Cannot have t-esc on a component that already has content" "Cannot have t-esc on a component that already has content"