mirror of
https://github.com/sveltejs/svelte.git
synced 2024-11-30 00:46:29 +01:00
[fix] Specify svg namespace if {@html} is used in svg (#7464)
* add test * create svg element if {@html} tag is inside of svg * always use claim_html_tag
This commit is contained in:
parent
eb37f4a285
commit
1803290864
@ -1,8 +1,10 @@
|
||||
import { namespaces } from './../../../utils/namespaces';
|
||||
import { b, x } from 'code-red';
|
||||
import Renderer from '../Renderer';
|
||||
import Block from '../Block';
|
||||
import Tag from './shared/Tag';
|
||||
import Wrapper from './shared/Wrapper';
|
||||
import Element from '../../nodes/Element';
|
||||
import MustacheTag from '../../nodes/MustacheTag';
|
||||
import RawMustacheTag from '../../nodes/RawMustacheTag';
|
||||
import { is_head } from './shared/is_head';
|
||||
@ -51,9 +53,12 @@ export default class RawMustacheTagWrapper extends Tag {
|
||||
|
||||
const update_anchor = needs_anchor ? html_anchor : this.next ? this.next.var : 'null';
|
||||
|
||||
block.chunks.create.push(b`${html_tag} = new @HtmlTag();`);
|
||||
const parent_element = this.node.find_nearest(/^Element/) as Element;
|
||||
const is_svg = parent_element && parent_element.namespace === namespaces.svg;
|
||||
block.chunks.create.push(b`${html_tag} = new @HtmlTag(${is_svg ? 'true' : 'false'});`);
|
||||
|
||||
if (this.renderer.options.hydratable) {
|
||||
block.chunks.claim.push(b`${html_tag} = @claim_html_tag(${_parent_nodes});`);
|
||||
block.chunks.claim.push(b`${html_tag} = @claim_html_tag(${_parent_nodes}, ${is_svg ? 'true' : 'false'});`);
|
||||
}
|
||||
block.chunks.hydrate.push(b`${html_tag}.a = ${update_anchor};`);
|
||||
block.chunks.mount.push(b`${html_tag}.m(${init}, ${parent_node || '#target'}, ${parent_node ? null : '#anchor'});`);
|
||||
|
@ -492,12 +492,13 @@ function find_comment(nodes, text, start) {
|
||||
return nodes.length;
|
||||
}
|
||||
|
||||
export function claim_html_tag(nodes) {
|
||||
|
||||
export function claim_html_tag(nodes, is_svg: boolean) {
|
||||
// find html opening tag
|
||||
const start_index = find_comment(nodes, 'HTML_TAG_START', 0);
|
||||
const end_index = find_comment(nodes, 'HTML_TAG_END', start_index);
|
||||
if (start_index === end_index) {
|
||||
return new HtmlTagHydration();
|
||||
return new HtmlTagHydration(undefined, is_svg);
|
||||
}
|
||||
|
||||
init_claim_info(nodes);
|
||||
@ -509,7 +510,7 @@ export function claim_html_tag(nodes) {
|
||||
n.claim_order = nodes.claim_info.total_claimed;
|
||||
nodes.claim_info.total_claimed += 1;
|
||||
}
|
||||
return new HtmlTagHydration(claimed_nodes);
|
||||
return new HtmlTagHydration(claimed_nodes, is_svg);
|
||||
}
|
||||
|
||||
export function set_data(text, data) {
|
||||
@ -645,16 +646,18 @@ export function query_selector_all(selector: string, parent: HTMLElement = docum
|
||||
}
|
||||
|
||||
export class HtmlTag {
|
||||
private is_svg = false;
|
||||
// parent for creating node
|
||||
e: HTMLElement;
|
||||
e: HTMLElement | SVGElement;
|
||||
// html tag nodes
|
||||
n: ChildNode[];
|
||||
// target
|
||||
t: HTMLElement;
|
||||
t: HTMLElement | SVGElement;
|
||||
// anchor
|
||||
a: HTMLElement;
|
||||
a: HTMLElement | SVGElement;
|
||||
|
||||
constructor() {
|
||||
constructor(is_svg: boolean = false) {
|
||||
this.is_svg = is_svg;
|
||||
this.e = this.n = null;
|
||||
}
|
||||
|
||||
@ -662,9 +665,14 @@ export class HtmlTag {
|
||||
this.h(html);
|
||||
}
|
||||
|
||||
m(html: string, target: HTMLElement, anchor: HTMLElement = null) {
|
||||
m(
|
||||
html: string,
|
||||
target: HTMLElement | SVGElement,
|
||||
anchor: HTMLElement | SVGElement = null
|
||||
) {
|
||||
if (!this.e) {
|
||||
this.e = element(target.nodeName as keyof HTMLElementTagNameMap);
|
||||
if (this.is_svg) this.e = svg_element(target.nodeName as keyof SVGElementTagNameMap);
|
||||
else this.e = element(target.nodeName as keyof HTMLElementTagNameMap);
|
||||
this.t = target;
|
||||
this.c(html);
|
||||
}
|
||||
@ -698,8 +706,8 @@ export class HtmlTagHydration extends HtmlTag {
|
||||
// hydration claimed nodes
|
||||
l: ChildNode[] | void;
|
||||
|
||||
constructor(claimed_nodes?: ChildNode[]) {
|
||||
super();
|
||||
constructor(claimed_nodes?: ChildNode[], is_svg: boolean = false) {
|
||||
super(is_svg);
|
||||
this.e = this.n = null;
|
||||
this.l = claimed_nodes;
|
||||
}
|
||||
|
@ -52,7 +52,7 @@ function create_each_block(ctx) {
|
||||
t4 = text(t4_value);
|
||||
t5 = text(" ago:");
|
||||
t6 = space();
|
||||
html_tag = new HtmlTag();
|
||||
html_tag = new HtmlTag(false);
|
||||
attr(span, "class", "meta");
|
||||
html_tag.a = null;
|
||||
attr(div, "class", "comment");
|
||||
@ -170,4 +170,4 @@ class Component extends SvelteComponent {
|
||||
}
|
||||
}
|
||||
|
||||
export default Component;
|
||||
export default Component;
|
||||
|
35
test/runtime/samples/svg-html-tag/_config.js
Normal file
35
test/runtime/samples/svg-html-tag/_config.js
Normal file
@ -0,0 +1,35 @@
|
||||
export default {
|
||||
html: `
|
||||
<svg width="100" height="60">
|
||||
<circle cx="25" cy="30" r="24" fill="#FFD166"></circle>
|
||||
<circle cx="75" cy="30" r="24" fill="#118AB2"></circle>
|
||||
</svg>
|
||||
`,
|
||||
test({ assert, target, component }) {
|
||||
|
||||
let svg = target.querySelector('svg');
|
||||
let circles = target.querySelectorAll('circle');
|
||||
assert.equal(svg.namespaceURI, 'http://www.w3.org/2000/svg');
|
||||
assert.equal(2, circles.length);
|
||||
assert.equal(circles[0].namespaceURI, 'http://www.w3.org/2000/svg');
|
||||
assert.equal(circles[1].namespaceURI, 'http://www.w3.org/2000/svg');
|
||||
|
||||
component.width = 200;
|
||||
component.height = 120;
|
||||
assert.htmlEqual(
|
||||
target.innerHTML,
|
||||
`
|
||||
<svg width="200" height="120">
|
||||
<circle cx="50" cy="60" r="24" fill="#FFD166"></circle>
|
||||
<circle cx="150" cy="60" r="24" fill="#118AB2"></circle>
|
||||
</svg>
|
||||
`
|
||||
);
|
||||
svg = target.querySelector('svg');
|
||||
circles = target.querySelectorAll('circle');
|
||||
assert.equal(svg.namespaceURI, 'http://www.w3.org/2000/svg');
|
||||
assert.equal(2, circles.length);
|
||||
assert.equal(circles[0].namespaceURI, 'http://www.w3.org/2000/svg');
|
||||
assert.equal(circles[1].namespaceURI, 'http://www.w3.org/2000/svg');
|
||||
}
|
||||
};
|
10
test/runtime/samples/svg-html-tag/main.svelte
Normal file
10
test/runtime/samples/svg-html-tag/main.svelte
Normal file
@ -0,0 +1,10 @@
|
||||
<script>
|
||||
export let width = 100
|
||||
export let height = 60
|
||||
$: circle = `<circle cx="${width/4}" cy="${height/2}" r="24" fill="#FFD166"/>`
|
||||
</script>
|
||||
|
||||
<svg width="{width}" height="{height}">
|
||||
{@html circle}
|
||||
<circle cx="{width/4*3}" cy="{height/2}" r="24" fill="#118AB2"/>
|
||||
</svg>
|
39
test/runtime/samples/svg-html-tag2/_config.js
Normal file
39
test/runtime/samples/svg-html-tag2/_config.js
Normal file
@ -0,0 +1,39 @@
|
||||
export default {
|
||||
html: `
|
||||
<svg width="100" height="60">
|
||||
<rect>
|
||||
<circle cx="25" cy="30" r="24" fill="#FFD166"></circle>
|
||||
<circle cx="75" cy="30" r="24" fill="#118AB2"></circle>
|
||||
</rect>
|
||||
</svg>
|
||||
`,
|
||||
test({ assert, target, component }) {
|
||||
|
||||
let svg = target.querySelector('svg');
|
||||
let circles = target.querySelectorAll('circle');
|
||||
assert.equal(svg.namespaceURI, 'http://www.w3.org/2000/svg');
|
||||
assert.equal(2, circles.length);
|
||||
assert.equal(circles[0].namespaceURI, 'http://www.w3.org/2000/svg');
|
||||
assert.equal(circles[1].namespaceURI, 'http://www.w3.org/2000/svg');
|
||||
|
||||
component.width = 200;
|
||||
component.height = 120;
|
||||
assert.htmlEqual(
|
||||
target.innerHTML,
|
||||
`
|
||||
<svg width="200" height="120">
|
||||
<rect>
|
||||
<circle cx="50" cy="60" r="24" fill="#FFD166"></circle>
|
||||
<circle cx="150" cy="60" r="24" fill="#118AB2"></circle>
|
||||
</rect>
|
||||
</svg>
|
||||
`
|
||||
);
|
||||
svg = target.querySelector('svg');
|
||||
circles = target.querySelectorAll('circle');
|
||||
assert.equal(svg.namespaceURI, 'http://www.w3.org/2000/svg');
|
||||
assert.equal(2, circles.length);
|
||||
assert.equal(circles[0].namespaceURI, 'http://www.w3.org/2000/svg');
|
||||
assert.equal(circles[1].namespaceURI, 'http://www.w3.org/2000/svg');
|
||||
}
|
||||
};
|
12
test/runtime/samples/svg-html-tag2/main.svelte
Normal file
12
test/runtime/samples/svg-html-tag2/main.svelte
Normal file
@ -0,0 +1,12 @@
|
||||
<script>
|
||||
export let width = 100
|
||||
export let height = 60
|
||||
$: circle = `<circle cx="${width/4}" cy="${height/2}" r="24" fill="#FFD166"/>`
|
||||
</script>
|
||||
|
||||
<svg width="{width}" height="{height}">
|
||||
<rect>
|
||||
{@html circle}
|
||||
<circle cx="{width/4*3}" cy="{height/2}" r="24" fill="#118AB2"/>
|
||||
</rect>
|
||||
</svg>
|
33
test/runtime/samples/svg-html-tag3/_config.js
Normal file
33
test/runtime/samples/svg-html-tag3/_config.js
Normal file
@ -0,0 +1,33 @@
|
||||
export default {
|
||||
html: `
|
||||
<svg>
|
||||
<foreignObject>
|
||||
<circle cx="25" cy="30" r="24" fill="#FFD166"></circle>
|
||||
</foreignObject>
|
||||
</svg>
|
||||
`,
|
||||
test({ assert, target, component }) {
|
||||
|
||||
let svg = target.querySelector('svg');
|
||||
let circle = target.querySelector('circle');
|
||||
assert.equal(svg.namespaceURI, 'http://www.w3.org/2000/svg');
|
||||
assert.equal(circle.namespaceURI, 'http://www.w3.org/1999/xhtml');
|
||||
|
||||
component.width = 200;
|
||||
component.height = 120;
|
||||
assert.htmlEqual(
|
||||
target.innerHTML,
|
||||
`
|
||||
<svg>
|
||||
<foreignObject>
|
||||
<circle cx="50" cy="60" r="24" fill="#FFD166"></circle>
|
||||
</foreignObject>
|
||||
</svg>
|
||||
`
|
||||
);
|
||||
svg = target.querySelector('svg');
|
||||
circle = target.querySelector('circle');
|
||||
assert.equal(svg.namespaceURI, 'http://www.w3.org/2000/svg');
|
||||
assert.equal(circle.namespaceURI, 'http://www.w3.org/1999/xhtml');
|
||||
}
|
||||
};
|
11
test/runtime/samples/svg-html-tag3/main.svelte
Normal file
11
test/runtime/samples/svg-html-tag3/main.svelte
Normal file
@ -0,0 +1,11 @@
|
||||
<script>
|
||||
export let width = 100
|
||||
export let height = 60
|
||||
$: circle = `<circle cx="${width/4}" cy="${height/2}" r="24" fill="#FFD166"/>`
|
||||
</script>
|
||||
|
||||
<svg>
|
||||
<foreignObject>
|
||||
{@html circle}
|
||||
</foreignObject>
|
||||
</svg>
|
Loading…
Reference in New Issue
Block a user