[IMP] svg namespace support

This commit is contained in:
Bruno Boi
2021-11-19 11:31:04 +01:00
committed by Géry Debongnie
parent 93b53d8017
commit ea74739d46
8 changed files with 272 additions and 38 deletions
+20 -9
View File
@@ -116,6 +116,7 @@ interface IntermediateTree {
forceRef?: boolean; forceRef?: boolean;
refIdx?: number; refIdx?: number;
refN: number; refN: number;
currentNS: string | null;
} }
function buildTree( function buildTree(
@@ -124,9 +125,10 @@ function buildTree(
domParentTree: IntermediateTree | null = null domParentTree: IntermediateTree | null = null
): IntermediateTree { ): IntermediateTree {
switch (node.nodeType) { switch (node.nodeType) {
case 1: { case Node.ELEMENT_NODE: {
// HTMLElement // HTMLElement
let isActive = false; let isActive = false;
let currentNS = parent && parent.currentNS;
const tagName = (node as Element).tagName; const tagName = (node as Element).tagName;
let el: Node | undefined = undefined; let el: Node | undefined = undefined;
const info: DynamicInfo[] = []; const info: DynamicInfo[] = [];
@@ -143,11 +145,18 @@ function buildTree(
el = document.createTextNode(""); el = document.createTextNode("");
isActive = true; isActive = true;
} }
if (!el) {
el = document.createElement(tagName);
}
if (el instanceof HTMLElement) {
const attrs = (node as Element).attributes; const attrs = (node as Element).attributes;
const ns = attrs.getNamedItem("block-ns");
if (ns) {
attrs.removeNamedItem("block-ns");
currentNS = ns.value;
}
if (!el) {
el = currentNS
? document.createElementNS(currentNS, tagName)
: document.createElement(tagName);
}
if (el instanceof Element) {
for (let i = 0; i < attrs.length; i++) { for (let i = 0; i < attrs.length; i++) {
const attrName = attrs[i].name; const attrName = attrs[i].name;
const attrValue = attrs[i].value; const attrValue = attrs[i].value;
@@ -193,13 +202,14 @@ function buildTree(
el, el,
info, info,
refN: isActive ? 1 : 0, refN: isActive ? 1 : 0,
currentNS,
}; };
if (node.firstChild) { if (node.firstChild) {
const childNode = node.childNodes[0]; const childNode = node.childNodes[0];
if ( if (
node.childNodes.length === 1 && node.childNodes.length === 1 &&
childNode.nodeType === 1 && childNode.nodeType === Node.ELEMENT_NODE &&
(childNode as Element).tagName.startsWith("block-child-") (childNode as Element).tagName.startsWith("block-child-")
) { ) {
const tagName = (childNode as Element).tagName; const tagName = (childNode as Element).tagName;
@@ -227,11 +237,11 @@ function buildTree(
} }
return tree; return tree;
} }
case 3: case Node.TEXT_NODE:
case 8: { case Node.COMMENT_NODE: {
// text node or comment node // text node or comment node
const el = const el =
node.nodeType === 3 node.nodeType === Node.TEXT_NODE
? document.createTextNode(node.textContent!) ? document.createTextNode(node.textContent!)
: document.createComment(node.textContent!); : document.createComment(node.textContent!);
return { return {
@@ -241,6 +251,7 @@ function buildTree(
el, el,
info: [], info: [],
refN: 0, refN: 0,
currentNS: null,
}; };
} }
} }
+4
View File
@@ -497,6 +497,10 @@ export class CodeGenerator {
} }
// attributes // attributes
const attrs: { [key: string]: string } = {}; const attrs: { [key: string]: string } = {};
if (ast.ns) {
// specific namespace uri
attrs["block-ns"] = ast.ns;
}
for (let key in ast.attrs) { for (let key in ast.attrs) {
if (key.startsWith("t-attf")) { if (key.startsWith("t-attf")) {
let expr = interpolate(ast.attrs[key]); let expr = interpolate(ast.attrs[key]);
+11 -8
View File
@@ -49,6 +49,7 @@ export interface ASTDomNode {
shouldTrim: boolean; shouldTrim: boolean;
shouldNumberize: boolean; shouldNumberize: boolean;
} | null; } | null;
ns: string | null;
} }
export interface ASTMulti { export interface ASTMulti {
@@ -171,11 +172,12 @@ export type AST =
// ----------------------------------------------------------------------------- // -----------------------------------------------------------------------------
interface ParsingContext { interface ParsingContext {
inPreTag: boolean; inPreTag: boolean;
inSVG: boolean;
} }
export function parse(xml: string | Node): AST { export function parse(xml: string | Node): AST {
const node = xml instanceof Element ? xml : parseXML(`<t>${xml}</t>`).firstChild!; const node = xml instanceof Element ? xml : parseXML(`<t>${xml}</t>`).firstChild!;
const ctx = { inPreTag: false }; const ctx = { inPreTag: false, inSVG: false };
const ast = parseNode(node, ctx); const ast = parseNode(node, ctx);
if (!ast) { if (!ast) {
return { type: ASTType.Text, value: "" }; return { type: ASTType.Text, value: "" };
@@ -240,7 +242,7 @@ const lineBreakRE = /[\r\n]/;
const whitespaceRE = /\s+/g; const whitespaceRE = /\s+/g;
function parseTextCommentNode(node: ChildNode, ctx: ParsingContext): AST | null { function parseTextCommentNode(node: ChildNode, ctx: ParsingContext): AST | null {
if (node.nodeType === 3) { if (node.nodeType === Node.TEXT_NODE) {
let value = node.textContent || ""; let value = node.textContent || "";
if (!ctx.inPreTag) { if (!ctx.inPreTag) {
if (lineBreakRE.test(value) && !value.trim()) { if (lineBreakRE.test(value) && !value.trim()) {
@@ -250,7 +252,7 @@ function parseTextCommentNode(node: ChildNode, ctx: ParsingContext): AST | null
} }
return { type: ASTType.Text, value }; return { type: ASTType.Text, value };
} else if (node.nodeType === 8) { } else if (node.nodeType === Node.COMMENT_NODE) {
return { type: ASTType.Comment, value: node.textContent || "" }; return { type: ASTType.Comment, value: node.textContent || "" };
} }
return null; return null;
@@ -289,18 +291,18 @@ const hasBracketsAtTheEnd = /\[[^\[]+\]\s*$/;
function parseDOMNode(node: Element, ctx: ParsingContext): AST | null { function parseDOMNode(node: Element, ctx: ParsingContext): AST | null {
const { tagName } = node; const { tagName } = node;
let dynamicTag = null; const dynamicTag = node.getAttribute("t-tag");
if (node.hasAttribute("t-tag")) {
dynamicTag = node.getAttribute("t-tag");
node.removeAttribute("t-tag"); node.removeAttribute("t-tag");
}
if (tagName === "t" && !dynamicTag) { if (tagName === "t" && !dynamicTag) {
return null; return null;
} }
const children: AST[] = []; const children: AST[] = [];
if (tagName === "pre") { if (tagName === "pre") {
ctx = { inPreTag: true }; ctx.inPreTag = true;
} }
const shouldAddSVGNS = tagName === "svg" || (tagName === "g" && !ctx.inSVG);
ctx.inSVG = ctx.inSVG || shouldAddSVGNS;
const ns = shouldAddSVGNS ? "http://www.w3.org/2000/svg" : null;
const ref = node.getAttribute("t-ref"); const ref = node.getAttribute("t-ref");
node.removeAttribute("t-ref"); node.removeAttribute("t-ref");
@@ -381,6 +383,7 @@ function parseDOMNode(node: Element, ctx: ParsingContext): AST | null {
ref, ref,
content: children, content: children,
model, model,
ns,
}; };
} }
+72
View File
@@ -0,0 +1,72 @@
import { createBlock, mount } from "../../src/blockdom";
import { makeTestFixture } from "./helpers";
//------------------------------------------------------------------------------
// Setup and helpers
//------------------------------------------------------------------------------
const XHTML_URI = "http://www.w3.org/1999/xhtml";
const SVG_URI = "http://www.w3.org/2000/svg";
let fixture: HTMLElement;
beforeEach(() => {
fixture = makeTestFixture();
});
afterEach(() => {
fixture.remove();
});
//------------------------------------------------------------------------------
// Tests
//------------------------------------------------------------------------------
describe("namespace", () => {
test("default namespace is xhtml", () => {
const block = createBlock(`<tag/>`);
const tree = block();
mount(tree, fixture);
expect(fixture.innerHTML).toBe("<tag></tag>");
expect(fixture.firstElementChild!.namespaceURI).toBe(XHTML_URI);
});
test("namespace can be changed with block-ns", () => {
const block = createBlock(`<tag block-ns="${SVG_URI}"/>`);
const tree = block();
mount(tree, fixture);
expect(fixture.innerHTML).toBe("<tag></tag>");
expect(fixture.firstElementChild!.namespaceURI).toBe(SVG_URI);
});
test("namespace is kept for children", () => {
const block = createBlock(
`<parent block-ns="${SVG_URI}"><child><subchild/></child><child/></parent>`
);
const tree = block();
mount(tree, fixture);
expect(fixture.innerHTML).toBe(
"<parent><child><subchild></subchild></child><child></child></parent>"
);
const parent = fixture.firstElementChild!;
const child1 = parent.firstElementChild!;
const subchild = child1.firstElementChild!;
const child2 = child1.nextElementSibling!;
expect(parent.namespaceURI).toBe(SVG_URI);
expect(child1.namespaceURI).toBe(SVG_URI);
expect(child2.namespaceURI).toBe(SVG_URI);
expect(subchild.namespaceURI).toBe(SVG_URI);
});
test("various namespaces in same block", () => {
const block = createBlock(`<none><one block-ns="one"/><two block-ns="two"/></none>`);
const tree = block();
mount(tree, fixture);
expect(fixture.innerHTML).toBe("<none><one></one><two></two></none>");
const none = fixture.firstElementChild!;
const one = none.firstElementChild!;
const two = one.nextElementSibling!;
expect(none.namespaceURI).toBe(XHTML_URI);
expect(one.namespaceURI).toBe("one");
expect(two.namespaceURI).toBe("two");
});
});
@@ -0,0 +1,29 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`properly support svg add proper namespace to g tags 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, safeOutput } = helpers;
let block1 = createBlock(\`<g block-ns=\\"http://www.w3.org/2000/svg\\"><circle cx=\\"50\\" cy=\\"50\\" r=\\"4\\" stroke=\\"green\\" stroke-width=\\"1\\" fill=\\"yellow\\"/> </g>\`);
return function template(ctx, node, key = \\"\\") {
return block1();
}
}"
`;
exports[`properly support svg add proper namespace to svg 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, safeOutput } = helpers;
let block1 = createBlock(\`<svg block-ns=\\"http://www.w3.org/2000/svg\\" width=\\"100px\\" height=\\"90px\\"><circle cx=\\"50\\" cy=\\"50\\" r=\\"4\\" stroke=\\"green\\" stroke-width=\\"1\\" fill=\\"yellow\\"/> </svg>\`);
return function template(ctx, node, key = \\"\\") {
return block1();
}
}"
`;
+118 -1
View File
@@ -46,6 +46,7 @@ describe("qweb parser", () => {
on: {}, on: {},
ref: null, ref: null,
model: null, model: null,
ns: null,
}); });
}); });
@@ -73,6 +74,7 @@ describe("qweb parser", () => {
ref: null, ref: null,
model: null, model: null,
content: [], content: [],
ns: null,
}); });
}); });
@@ -86,6 +88,7 @@ describe("qweb parser", () => {
ref: null, ref: null,
model: null, model: null,
content: [{ type: ASTType.Text, value: "some text" }], content: [{ type: ASTType.Text, value: "some text" }],
ns: null,
}); });
}); });
@@ -98,6 +101,7 @@ describe("qweb parser", () => {
on: {}, on: {},
ref: null, ref: null,
model: null, model: null,
ns: null,
content: [ content: [
{ type: ASTType.Text, value: "some text" }, { type: ASTType.Text, value: "some text" },
{ {
@@ -108,6 +112,7 @@ describe("qweb parser", () => {
on: {}, on: {},
ref: null, ref: null,
model: null, model: null,
ns: null,
content: [{ type: ASTType.Text, value: "inside" }], content: [{ type: ASTType.Text, value: "inside" }],
}, },
], ],
@@ -126,6 +131,7 @@ describe("qweb parser", () => {
on: {}, on: {},
ref: null, ref: null,
model: null, model: null,
ns: null,
content: [], content: [],
}, },
{ {
@@ -136,6 +142,7 @@ describe("qweb parser", () => {
on: {}, on: {},
ref: null, ref: null,
model: null, model: null,
ns: null,
content: [], content: [],
}, },
], ],
@@ -155,6 +162,7 @@ describe("qweb parser", () => {
on: {}, on: {},
ref: null, ref: null,
model: null, model: null,
ns: null,
content: [], content: [],
}, },
], ],
@@ -170,10 +178,83 @@ describe("qweb parser", () => {
on: {}, on: {},
ref: null, ref: null,
model: null, model: null,
ns: null,
content: [{ type: ASTType.Text, value: "foo" }], content: [{ type: ASTType.Text, value: "foo" }],
}); });
}); });
test("svg dom node", async () => {
expect(
parse(
`<svg width="100px" height="90px"><circle cx="50" cy="50" r="4" stroke="green" stroke-width="1" fill="yellow"/></svg>`
)
).toEqual({
attrs: {
height: "90px",
width: "100px",
},
content: [
{
attrs: {
cx: "50",
cy: "50",
fill: "yellow",
r: "4",
stroke: "green",
"stroke-width": "1",
},
content: [],
dynamicTag: null,
model: null,
ns: null,
on: {},
ref: null,
tag: "circle",
type: 2,
},
],
dynamicTag: null,
model: null,
ns: "http://www.w3.org/2000/svg",
on: {},
ref: null,
tag: "svg",
type: 2,
});
expect(
parse(`<g><circle cx="50" cy="50" r="4" stroke="green" stroke-width="1" fill="yellow"/></g>`)
).toEqual({
attrs: {},
content: [
{
attrs: {
cx: "50",
cy: "50",
fill: "yellow",
r: "4",
stroke: "green",
"stroke-width": "1",
},
content: [],
dynamicTag: null,
model: null,
ns: null,
on: {},
ref: null,
tag: "circle",
type: 2,
},
],
dynamicTag: null,
model: null,
ns: "http://www.w3.org/2000/svg",
on: {},
ref: null,
tag: "g",
type: 2,
});
});
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------
// t-esc // t-esc
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------
@@ -200,6 +281,7 @@ describe("qweb parser", () => {
on: {}, on: {},
ref: null, ref: null,
model: null, model: null,
ns: null,
content: [{ type: ASTType.TEsc, expr: "text", defaultValue: "" }], content: [{ type: ASTType.TEsc, expr: "text", defaultValue: "" }],
}); });
}); });
@@ -221,6 +303,7 @@ describe("qweb parser", () => {
on: {}, on: {},
ref: null, ref: null,
model: null, model: null,
ns: null,
content: [{ type: ASTType.TEsc, expr: "text", defaultValue: "hey" }], content: [{ type: ASTType.TEsc, expr: "text", defaultValue: "hey" }],
}); });
}); });
@@ -262,6 +345,7 @@ describe("qweb parser", () => {
on: {}, on: {},
ref: null, ref: null,
model: null, model: null,
ns: null,
content: [{ type: ASTType.TOut, expr: "text", body: null }], content: [{ type: ASTType.TOut, expr: "text", body: null }],
}); });
}); });
@@ -275,6 +359,7 @@ describe("qweb parser", () => {
on: {}, on: {},
ref: null, ref: null,
model: null, model: null,
ns: null,
content: [ content: [
{ type: ASTType.TOut, expr: "text", body: [{ type: ASTType.Text, value: "body" }] }, { type: ASTType.TOut, expr: "text", body: [{ type: ASTType.Text, value: "body" }] },
], ],
@@ -294,6 +379,7 @@ describe("qweb parser", () => {
on: {}, on: {},
ref: null, ref: null,
model: null, model: null,
ns: null,
content: [ content: [
{ {
type: ASTType.TIf, type: ASTType.TIf,
@@ -321,6 +407,7 @@ describe("qweb parser", () => {
on: {}, on: {},
ref: null, ref: null,
model: null, model: null,
ns: null,
content: [{ type: ASTType.Text, value: "hey" }], content: [{ type: ASTType.Text, value: "hey" }],
}, },
tElif: null, tElif: null,
@@ -397,6 +484,7 @@ describe("qweb parser", () => {
on: {}, on: {},
ref: null, ref: null,
model: null, model: null,
ns: null,
content: [ content: [
{ {
type: ASTType.Text, type: ASTType.Text,
@@ -415,6 +503,7 @@ describe("qweb parser", () => {
on: {}, on: {},
ref: null, ref: null,
model: null, model: null,
ns: null,
content: [{ type: ASTType.Text, value: "elif" }], content: [{ type: ASTType.Text, value: "elif" }],
}, },
}, },
@@ -427,6 +516,7 @@ describe("qweb parser", () => {
on: {}, on: {},
ref: null, ref: null,
model: null, model: null,
ns: null,
content: [ content: [
{ {
type: ASTType.Text, type: ASTType.Text,
@@ -474,6 +564,7 @@ describe("qweb parser", () => {
dynamicTag: null, dynamicTag: null,
ref: null, ref: null,
model: null, model: null,
ns: null,
content: [{ type: ASTType.Text, value: "ok" }], content: [{ type: ASTType.Text, value: "ok" }],
}, },
], ],
@@ -493,6 +584,7 @@ describe("qweb parser", () => {
dynamicTag: null, dynamicTag: null,
ref: null, ref: null,
model: null, model: null,
ns: null,
content: [{ type: ASTType.Text, value: "ok" }], content: [{ type: ASTType.Text, value: "ok" }],
}, },
{ type: ASTType.Text, value: "abc" }, { type: ASTType.Text, value: "abc" },
@@ -527,6 +619,7 @@ describe("qweb parser", () => {
on: {}, on: {},
ref: null, ref: null,
model: null, model: null,
ns: null,
content: [ content: [
{ {
type: ASTType.TIf, type: ASTType.TIf,
@@ -601,6 +694,7 @@ describe("qweb parser", () => {
on: {}, on: {},
ref: null, ref: null,
model: null, model: null,
ns: null,
content: [{ type: ASTType.TEsc, expr: "item", defaultValue: "" }], content: [{ type: ASTType.TEsc, expr: "item", defaultValue: "" }],
}, },
memo: "", memo: "",
@@ -646,6 +740,7 @@ describe("qweb parser", () => {
on: {}, on: {},
ref: null, ref: null,
model: null, model: null,
ns: null,
content: [{ type: ASTType.TEsc, expr: "item", defaultValue: "" }], content: [{ type: ASTType.TEsc, expr: "item", defaultValue: "" }],
}, },
memo: "", memo: "",
@@ -681,6 +776,7 @@ describe("qweb parser", () => {
on: {}, on: {},
ref: null, ref: null,
model: null, model: null,
ns: null,
content: [{ type: ASTType.TEsc, expr: "item", defaultValue: "" }], content: [{ type: ASTType.TEsc, expr: "item", defaultValue: "" }],
}, },
}, },
@@ -715,6 +811,7 @@ describe("qweb parser", () => {
on: {}, on: {},
ref: null, ref: null,
model: null, model: null,
ns: null,
content: [{ type: ASTType.TEsc, expr: "category.name", defaultValue: "" }], content: [{ type: ASTType.TEsc, expr: "category.name", defaultValue: "" }],
}, },
memo: "", memo: "",
@@ -736,6 +833,7 @@ describe("qweb parser", () => {
model: null, model: null,
tag: "div", tag: "div",
dynamicTag: null, dynamicTag: null,
ns: null,
content: [ content: [
{ {
type: ASTType.TForEach, type: ASTType.TForEach,
@@ -781,6 +879,7 @@ describe("qweb parser", () => {
ref: null, ref: null,
model: null, model: null,
attrs: {}, attrs: {},
ns: null,
content: [{ type: ASTType.TEsc, expr: "item", defaultValue: "" }], content: [{ type: ASTType.TEsc, expr: "item", defaultValue: "" }],
}, },
memo: "", memo: "",
@@ -888,6 +987,7 @@ describe("qweb parser", () => {
on: {}, on: {},
ref: null, ref: null,
model: null, model: null,
ns: null,
content: [ content: [
{ {
type: ASTType.TCall, type: ASTType.TCall,
@@ -925,6 +1025,7 @@ describe("qweb parser", () => {
on: { click: "add" }, on: { click: "add" },
ref: null, ref: null,
model: null, model: null,
ns: null,
content: [{ type: ASTType.Text, value: "Click" }], content: [{ type: ASTType.Text, value: "Click" }],
}); });
}); });
@@ -1003,6 +1104,7 @@ describe("qweb parser", () => {
ref: null, ref: null,
model: null, model: null,
on: {}, on: {},
ns: null,
}, },
{ {
type: ASTType.DomNode, type: ASTType.DomNode,
@@ -1013,6 +1115,7 @@ describe("qweb parser", () => {
ref: null, ref: null,
model: null, model: null,
on: {}, on: {},
ns: null,
}, },
], ],
}, },
@@ -1203,6 +1306,7 @@ describe("qweb parser", () => {
on: {}, on: {},
ref: null, ref: null,
model: null, model: null,
ns: null,
content: [{ type: ASTType.Text, value: "hey" }], content: [{ type: ASTType.Text, value: "hey" }],
}, },
}); });
@@ -1220,6 +1324,7 @@ describe("qweb parser", () => {
on: {}, on: {},
ref: null, ref: null,
model: null, model: null,
ns: null,
content: [{ type: ASTType.Text, value: "hey" }], content: [{ type: ASTType.Text, value: "hey" }],
}, },
}); });
@@ -1238,6 +1343,7 @@ describe("qweb parser", () => {
on: {}, on: {},
ref: "name", ref: "name",
model: null, model: null,
ns: null,
content: [{ type: ASTType.Text, value: "hey" }], content: [{ type: ASTType.Text, value: "hey" }],
}); });
}); });
@@ -1251,6 +1357,7 @@ describe("qweb parser", () => {
on: {}, on: {},
ref: "name", ref: "name",
model: null, model: null,
ns: null,
content: [ content: [
{ type: ASTType.TOut, expr: "text", body: [{ type: ASTType.Text, value: "body" }] }, { type: ASTType.TOut, expr: "text", body: [{ type: ASTType.Text, value: "body" }] },
], ],
@@ -1266,6 +1373,7 @@ describe("qweb parser", () => {
on: {}, on: {},
ref: "name", ref: "name",
model: null, model: null,
ns: null,
content: [{ type: ASTType.TEsc, expr: "text", defaultValue: "body" }], content: [{ type: ASTType.TEsc, expr: "text", defaultValue: "body" }],
}); });
}); });
@@ -1309,7 +1417,8 @@ describe("qweb parser", () => {
model: null, model: null,
tag: "div", tag: "div",
dynamicTag: null, dynamicTag: null,
type: 2, type: ASTType.DomNode,
ns: null,
}, },
type: 16, type: 16,
}, },
@@ -1339,6 +1448,7 @@ describe("qweb parser", () => {
ref: null, ref: null,
tag: "input", tag: "input",
dynamicTag: null, dynamicTag: null,
ns: null,
model: { model: {
baseExpr: "state", baseExpr: "state",
expr: "'stuff'", expr: "'stuff'",
@@ -1357,6 +1467,7 @@ describe("qweb parser", () => {
ref: null, ref: null,
tag: "input", tag: "input",
dynamicTag: null, dynamicTag: null,
ns: null,
model: { model: {
baseExpr: "state", baseExpr: "state",
expr: "'stuff'", expr: "'stuff'",
@@ -1375,6 +1486,7 @@ describe("qweb parser", () => {
ref: null, ref: null,
tag: "input", tag: "input",
dynamicTag: null, dynamicTag: null,
ns: null,
model: { model: {
baseExpr: "state", baseExpr: "state",
expr: "'stuff'", expr: "'stuff'",
@@ -1394,6 +1506,7 @@ describe("qweb parser", () => {
ref: null, ref: null,
tag: "textarea", tag: "textarea",
dynamicTag: null, dynamicTag: null,
ns: null,
model: { model: {
baseExpr: "state", baseExpr: "state",
expr: "'stuff'", expr: "'stuff'",
@@ -1412,6 +1525,7 @@ describe("qweb parser", () => {
ref: null, ref: null,
tag: "input", tag: "input",
dynamicTag: null, dynamicTag: null,
ns: null,
model: { model: {
baseExpr: "state", baseExpr: "state",
expr: "'stuff'", expr: "'stuff'",
@@ -1430,6 +1544,7 @@ describe("qweb parser", () => {
ref: null, ref: null,
tag: "input", tag: "input",
dynamicTag: null, dynamicTag: null,
ns: null,
model: { model: {
baseExpr: "state", baseExpr: "state",
expr: "'stuff'", expr: "'stuff'",
@@ -1448,6 +1563,7 @@ describe("qweb parser", () => {
ref: null, ref: null,
tag: "input", tag: "input",
dynamicTag: null, dynamicTag: null,
ns: null,
model: { model: {
baseExpr: "state", baseExpr: "state",
expr: "'stuff'", expr: "'stuff'",
@@ -1472,6 +1588,7 @@ describe("qweb parser", () => {
tag: "div", tag: "div",
dynamicTag: "theTag", dynamicTag: "theTag",
model: null, model: null,
ns: null,
}); });
}); });
}); });
+15 -17
View File
@@ -1,22 +1,20 @@
describe("properly support svg", () => { import { renderToString, snapshotEverything } from "../helpers";
test.skip("add proper namespace to svg", () => {
// qweb.addTemplate( snapshotEverything();
// "test",
// `<svg width="100px" height="90px"><circle cx="50" cy="50" r="4" stroke="green" stroke-width="1" fill="yellow"/> </svg>` describe.only("properly support svg", () => {
// ); test("add proper namespace to svg", () => {
// expect(renderToString(qweb, "test")).toBe( const template = `<svg width="100px" height="90px"><circle cx="50" cy="50" r="4" stroke="green" stroke-width="1" fill="yellow"/> </svg>`;
// `<svg width=\"100px\" height=\"90px\"><circle cx=\"50\" cy=\"50\" r=\"4\" stroke=\"green\" stroke-width=\"1\" fill=\"yellow\"></circle> </svg>` expect(renderToString(template)).toBe(
// ); `<svg width=\"100px\" height=\"90px\"><circle cx=\"50\" cy=\"50\" r=\"4\" stroke=\"green\" stroke-width=\"1\" fill=\"yellow\"></circle> </svg>`
);
}); });
test.skip("add proper namespace to g tags", () => { test("add proper namespace to g tags", () => {
// this is necessary if one wants to use components in a svg // this is necessary if one wants to use components in a svg
// qweb.addTemplate( const template = `<g><circle cx="50" cy="50" r="4" stroke="green" stroke-width="1" fill="yellow"/> </g>`;
// "test", expect(renderToString(template)).toBe(
// `<g><circle cx="50" cy="50" r="4" stroke="green" stroke-width="1" fill="yellow"/> </g>` `<g><circle cx=\"50\" cy=\"50\" r=\"4\" stroke=\"green\" stroke-width=\"1\" fill=\"yellow\"></circle> </g>`
// ); );
// expect(renderToString(qweb, "test")).toBe(
// `<g><circle cx=\"50\" cy=\"50\" r=\"4\" stroke=\"green\" stroke-width=\"1\" fill=\"yellow\"></circle> </g>`
// );
}); });
}); });
@@ -1192,7 +1192,7 @@ exports[`support svg components add proper namespace to svg 1`] = `
let { text, createBlock, list, multi, html, toggler, component } = bdom; let { text, createBlock, list, multi, html, toggler, component } = bdom;
let { withDefault, getTemplate, prepareList, withKey, zero, call, callSlot, capture, isBoundary, shallowEqual, setContextValue, toNumber, safeOutput } = helpers; let { withDefault, getTemplate, prepareList, withKey, zero, call, callSlot, capture, isBoundary, shallowEqual, setContextValue, toNumber, safeOutput } = helpers;
let block1 = createBlock(\`<g><circle cx=\\"50\\" cy=\\"50\\" r=\\"4\\" stroke=\\"green\\" stroke-width=\\"1\\" fill=\\"yellow\\"/></g>\`); let block1 = createBlock(\`<g block-ns=\\"http://www.w3.org/2000/svg\\"><circle cx=\\"50\\" cy=\\"50\\" r=\\"4\\" stroke=\\"green\\" stroke-width=\\"1\\" fill=\\"yellow\\"/></g>\`);
return function template(ctx, node, key = \\"\\") { return function template(ctx, node, key = \\"\\") {
return block1(); return block1();
@@ -1206,7 +1206,7 @@ exports[`support svg components add proper namespace to svg 2`] = `
let { text, createBlock, list, multi, html, toggler, component } = bdom; let { text, createBlock, list, multi, html, toggler, component } = bdom;
let { withDefault, getTemplate, prepareList, withKey, zero, call, callSlot, capture, isBoundary, shallowEqual, setContextValue, toNumber, safeOutput } = helpers; let { withDefault, getTemplate, prepareList, withKey, zero, call, callSlot, capture, isBoundary, shallowEqual, setContextValue, toNumber, safeOutput } = helpers;
let block1 = createBlock(\`<svg><block-child-0/></svg>\`); let block1 = createBlock(\`<svg block-ns=\\"http://www.w3.org/2000/svg\\"><block-child-0/></svg>\`);
return function template(ctx, node, key = \\"\\") { return function template(ctx, node, key = \\"\\") {
let b2 = component(\`GComp\`, {}, key + \`__1\`, node, ctx); let b2 = component(\`GComp\`, {}, key + \`__1\`, node, ctx);