From a4d9aae9a759c126879edbdce4a0a93b21f1268f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?G=C3=A9ry=20Debongnie?= Date: Mon, 24 Jan 2022 09:01:51 +0100 Subject: [PATCH] [FIX] svg: allow path as root tag --- doc/reference/templates.md | 10 ++++--- src/compiler/parser.ts | 4 ++- tests/compiler/__snapshots__/svg.test.ts.snap | 29 +++++++++++++++++++ tests/compiler/svg.test.ts | 22 ++++++++++++++ 4 files changed, 60 insertions(+), 5 deletions(-) diff --git a/doc/reference/templates.md b/doc/reference/templates.md index cbb3980a..91c62dfe 100644 --- a/doc/reference/templates.md +++ b/doc/reference/templates.md @@ -674,7 +674,9 @@ This `RootNode` component will then display a live SVG representation of the graph described by the `graph` property. Note that there is a recursive structure here: the `Node` component uses itself as a subcomponent. -Note that since SVG needs to be handled in a specific way (its namespace needs -to be properly set), there is a small constraint for Owl components: if an owl -component is supposed to be a part of an svg graph, then its root node needs to -be a `g` tag, so Owl can properly set the namespace. +**Important note:** Owl needs to properly set the namespace for each svg elements. +Since Owl compile each template separately, it is not able to determine easily +if a template is supposed to be included in a svg namespace or not. Therefore, +Owl depends on a heuristic: if a tag is either `svg`, `g` or `path`, then it will +be considered as svg. In practice, this means that each component or each sub +templates (included with `t-call`) should have one of these tag as root tag. diff --git a/src/compiler/parser.ts b/src/compiler/parser.ts index 5ab4089f..61f2531e 100644 --- a/src/compiler/parser.ts +++ b/src/compiler/parser.ts @@ -285,6 +285,8 @@ function parseTDebugLog(node: Element, ctx: ParsingContext): AST | null { const hasDotAtTheEnd = /\.[\w_]+\s*$/; const hasBracketsAtTheEnd = /\[[^\[]+\]\s*$/; +const ROOT_SVG_TAGS = new Set(["svg", "g", "path"]); + function parseDOMNode(node: Element, ctx: ParsingContext): AST | null { const { tagName } = node; const dynamicTag = node.getAttribute("t-tag"); @@ -296,7 +298,7 @@ function parseDOMNode(node: Element, ctx: ParsingContext): AST | null { if (tagName === "pre") { ctx.inPreTag = true; } - const shouldAddSVGNS = tagName === "svg" || (tagName === "g" && !ctx.inSVG); + const shouldAddSVGNS = ROOT_SVG_TAGS.has(tagName) && !ctx.inSVG; ctx.inSVG = ctx.inSVG || shouldAddSVGNS; const ns = shouldAddSVGNS ? "http://www.w3.org/2000/svg" : null; const ref = node.getAttribute("t-ref"); diff --git a/tests/compiler/__snapshots__/svg.test.ts.snap b/tests/compiler/__snapshots__/svg.test.ts.snap index 2161f05a..14c96c65 100644 --- a/tests/compiler/__snapshots__/svg.test.ts.snap +++ b/tests/compiler/__snapshots__/svg.test.ts.snap @@ -52,6 +52,35 @@ exports[`properly support svg namespace to svg tags added even if already in svg }" `; +exports[`properly support svg svg namespace added to sub templates if root tag is path 1`] = ` +"function anonymous(bdom, helpers +) { + let { text, createBlock, list, multi, html, toggler, component, comment } = bdom; + let { getTemplate } = helpers; + const callTemplate_1 = getTemplate(\`path\`); + + let block1 = createBlock(\`\`); + + return function template(ctx, node, key = \\"\\") { + let b2 = callTemplate_1.call(this, ctx, node, key + \`__1\`); + return block1([], [b2]); + } +}" +`; + +exports[`properly support svg svg namespace added to sub templates if root tag is path 2`] = ` +"function anonymous(bdom, helpers +) { + let { text, createBlock, list, multi, html, toggler, component, comment } = bdom; + + let block1 = createBlock(\`\`); + + return function template(ctx, node, key = \\"\\") { + return block1(); + } +}" +`; + exports[`properly support svg svg namespace added to sub-blocks 1`] = ` "function anonymous(bdom, helpers ) { diff --git a/tests/compiler/svg.test.ts b/tests/compiler/svg.test.ts index a56aa348..42b55d2d 100644 --- a/tests/compiler/svg.test.ts +++ b/tests/compiler/svg.test.ts @@ -1,5 +1,7 @@ import { renderToString, renderToBdom, snapshotEverything, makeTestFixture } from "../helpers"; import { mount } from "../../src/blockdom"; +import { mount as mountComponent, Component } from "../../src/index"; + // NB: check the snapshots to see where the SVG namespaces are added snapshotEverything(); @@ -52,4 +54,24 @@ describe("properly support svg", () => { expect(el.namespaceURI).toBe("http://www.w3.org/2000/svg"); } }); + + test("svg namespace added to sub templates if root tag is path", async () => { + const templates = ` + + + + `; + const fixture = makeTestFixture(); + + class Svg extends Component { + static template = "svg"; + } + + await mountComponent(Svg, fixture, { templates }); + const elems = fixture.querySelectorAll("svg, path"); + expect(elems.length).toEqual(2); + for (const el of elems) { + expect(el.namespaceURI).toBe("http://www.w3.org/2000/svg"); + } + }); });