fix(js,dom): keep parsed SVG in the SVG namespace so href reflects an SVGAnimatedString
get namespaceURI() derived the namespace from the tag name and only ever recognised the <svg> root, so every element parsed inside an <svg> subtree reported the XHTML namespace. get href() gates the SVGAnimatedString reflection on the SVG namespace, so for parsed content the gate never opened: href returned a plain string and .animVal/.baseVal were undefined, making new URL(el.href.animVal) throw. Only createElementNS-built elements worked, because createElementNS records _ns explicitly. The tree builder already applies the HTML5 foreign-content rules, so QualName.ns is correct for parsed SVG; it just was not exposed to JS. Add a namespace_uri DOM op and read it in get namespaceURI(), keeping _ns as the override and the old tag-name heuristic as the fallback when no element name is recorded. Namespaces are immutable, so the result is cached like _lname. Fixes #484
This commit is contained in:
1 parent
e314b9b0f3
commit
3a4e3f7d7d
2 files changed
+22
-4
No files matched your search
Vendored
+14
-4
@@ -1210,11 +1210,21 @@ class Element extends Node {
|
||||
set className(v) { this.setAttribute("class", v); }
|
||||
get namespaceURI() {
|
||||
// createElementNS records the requested namespace on _ns; an empty string
|
||||
// maps to the null namespace per spec. Elements made via createElement (or
|
||||
// parsed) have no _ns: default to XHTML, except <svg> which is SVG.
|
||||
// maps to the null namespace per spec.
|
||||
if (this._ns !== undefined) return this._ns === "" ? null : this._ns;
|
||||
if (this.localName === "svg") return "http://www.w3.org/2000/svg";
|
||||
return "http://www.w3.org/1999/xhtml";
|
||||
// Otherwise use the namespace the HTML tree builder assigned. Foreign
|
||||
// content puts the WHOLE <svg>/<math> subtree in that namespace, not just
|
||||
// the root, so deriving it from the tag name (the old `localName === "svg"`
|
||||
// check) left every descendant looking like HTML and skipped the SVG-only
|
||||
// reflections -- notably `get href()`, which then returned a plain string
|
||||
// instead of an SVGAnimatedString. An element's namespace never changes,
|
||||
// so cache it like _lname.
|
||||
if (this._nsCache !== undefined) return this._nsCache;
|
||||
let ns = _domParse("namespace_uri", this._nid) || "";
|
||||
// Nodes with no element name recorded fall back to the previous heuristic.
|
||||
if (!ns) ns = this.localName === "svg" ? "http://www.w3.org/2000/svg" : "http://www.w3.org/1999/xhtml";
|
||||
this._nsCache = ns;
|
||||
return ns;
|
||||
}
|
||||
// `inner_html` resolves a <template> to its contents document on the Rust
|
||||
// side (issue #463), so this needs no template special case.
|
||||
|
||||
@@ -303,6 +303,14 @@ fn op_dom_inner(state: &OpState, cmd: String, arg1: String, arg2: String) -> Str
|
||||
let name = dom.with_node(NodeId::new(nid), |n| n.as_element().map(|name| name.local.as_ref().to_ascii_uppercase())).flatten().unwrap_or_default();
|
||||
serde_json::to_string(&name).unwrap_or("\"\"".into())
|
||||
}
|
||||
// The tree builder already assigns foreign content (an <svg>/<math>
|
||||
// subtree) its own namespace; expose it so JS does not have to guess
|
||||
// the namespace from the tag name.
|
||||
"namespace_uri" => {
|
||||
let nid = arg1.parse::<u32>().unwrap_or(0);
|
||||
let ns = dom.with_node(NodeId::new(nid), |n| n.as_element().map(|name| name.ns.as_ref().to_string())).flatten().unwrap_or_default();
|
||||
serde_json::to_string(&ns).unwrap_or("\"\"".into())
|
||||
}
|
||||
"get_attribute" => {
|
||||
let nid = arg1.parse::<u32>().unwrap_or(0);
|
||||
let val = dom.with_node(NodeId::new(nid), |n| n.get_attribute(&arg2).map(|s| s.to_string())).flatten();
|
||||
|
||||
Reference in new issue
Block a user