mirror of
https://github.com/lightpanda-io/browser.git
synced 2026-02-04 22:43:48 +00:00
Merge pull request #1342 from lightpanda-io/better_namespace_support
Some checks failed
e2e-test / zig build release (push) Has been cancelled
e2e-test / demo-scripts (push) Has been cancelled
e2e-test / cdp-and-hyperfine-bench (push) Has been cancelled
e2e-test / perf-fmt (push) Has been cancelled
zig-test / zig build dev (push) Has been cancelled
zig-test / browser fetch (push) Has been cancelled
zig-test / zig test (push) Has been cancelled
zig-test / perf-fmt (push) Has been cancelled
Some checks failed
e2e-test / zig build release (push) Has been cancelled
e2e-test / demo-scripts (push) Has been cancelled
e2e-test / cdp-and-hyperfine-bench (push) Has been cancelled
e2e-test / perf-fmt (push) Has been cancelled
zig-test / zig build dev (push) Has been cancelled
zig-test / browser fetch (push) Has been cancelled
zig-test / zig test (push) Has been cancelled
zig-test / perf-fmt (push) Has been cancelled
Improve support for non-HTML namespace
This commit is contained in:
1221
src/browser/Page.zig
1221
src/browser/Page.zig
File diff suppressed because it is too large
Load Diff
@@ -104,7 +104,7 @@ pub fn parseXML(self: *Parser, xml: []const u8) void {
|
|||||||
xml.len,
|
xml.len,
|
||||||
&self.container,
|
&self.container,
|
||||||
self,
|
self,
|
||||||
createElementCallback,
|
createXMLElementCallback,
|
||||||
getDataCallback,
|
getDataCallback,
|
||||||
appendCallback,
|
appendCallback,
|
||||||
parseErrorCallback,
|
parseErrorCallback,
|
||||||
@@ -225,17 +225,26 @@ fn _popCallback(self: *Parser, node: *Node) !void {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn createElementCallback(ctx: *anyopaque, data: *anyopaque, qname: h5e.QualName, attributes: h5e.AttributeIterator) callconv(.c) ?*anyopaque {
|
fn createElementCallback(ctx: *anyopaque, data: *anyopaque, qname: h5e.QualName, attributes: h5e.AttributeIterator) callconv(.c) ?*anyopaque {
|
||||||
|
return _createElementCallbackWithDefaultnamespace(ctx, data, qname, attributes, .unknown);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn createXMLElementCallback(ctx: *anyopaque, data: *anyopaque, qname: h5e.QualName, attributes: h5e.AttributeIterator) callconv(.c) ?*anyopaque {
|
||||||
|
return _createElementCallbackWithDefaultnamespace(ctx, data, qname, attributes, .xml);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn _createElementCallbackWithDefaultnamespace(ctx: *anyopaque, data: *anyopaque, qname: h5e.QualName, attributes: h5e.AttributeIterator, default_namespace: Element.Namespace) ?*anyopaque {
|
||||||
const self: *Parser = @ptrCast(@alignCast(ctx));
|
const self: *Parser = @ptrCast(@alignCast(ctx));
|
||||||
return self._createElementCallback(data, qname, attributes) catch |err| {
|
return self._createElementCallback(data, qname, attributes, default_namespace) catch |err| {
|
||||||
self.err = .{ .err = err, .source = .create_element };
|
self.err = .{ .err = err, .source = .create_element };
|
||||||
return null;
|
return null;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
fn _createElementCallback(self: *Parser, data: *anyopaque, qname: h5e.QualName, attributes: h5e.AttributeIterator) !*anyopaque {
|
fn _createElementCallback(self: *Parser, data: *anyopaque, qname: h5e.QualName, attributes: h5e.AttributeIterator, default_namespace: Element.Namespace) !*anyopaque {
|
||||||
const page = self.page;
|
const page = self.page;
|
||||||
const name = qname.local.slice();
|
const name = qname.local.slice();
|
||||||
const namespace = qname.ns.slice();
|
const namespace_string = qname.ns.slice();
|
||||||
const node = try page.createElement(namespace, name, attributes);
|
const namespace = if (namespace_string.len == 0) default_namespace else Element.Namespace.parse(namespace_string);
|
||||||
|
const node = try page.createElementNS(namespace, name, attributes);
|
||||||
|
|
||||||
const pn = try self.arena.create(ParsedNode);
|
const pn = try self.arena.create(ParsedNode);
|
||||||
pn.* = .{
|
pn.* = .{
|
||||||
|
|||||||
@@ -19,12 +19,13 @@
|
|||||||
testing.expectEqual('http://www.w3.org/XML/1998/namespace', xmlElement.namespaceURI);
|
testing.expectEqual('http://www.w3.org/XML/1998/namespace', xmlElement.namespaceURI);
|
||||||
|
|
||||||
const nullNsElement = document.createElementNS(null, 'span');
|
const nullNsElement = document.createElementNS(null, 'span');
|
||||||
testing.expectEqual('SPAN', nullNsElement.tagName);
|
testing.expectEqual('span', nullNsElement.tagName);
|
||||||
testing.expectEqual('http://www.w3.org/1999/xhtml', nullNsElement.namespaceURI);
|
testing.expectEqual(null, nullNsElement.namespaceURI);
|
||||||
|
|
||||||
const unknownNsElement = document.createElementNS('http://example.com/unknown', 'custom');
|
const unknownNsElement = document.createElementNS('http://example.com/unknown', 'custom');
|
||||||
testing.expectEqual('CUSTOM', unknownNsElement.tagName);
|
testing.expectEqual('custom', unknownNsElement.tagName);
|
||||||
testing.expectEqual('http://www.w3.org/1999/xhtml', unknownNsElement.namespaceURI);
|
// Should be http://example.com/unknown
|
||||||
|
testing.expectEqual('http://lightpanda.io/unsupported/namespace', unknownNsElement.namespaceURI);
|
||||||
|
|
||||||
const regularDiv = document.createElement('div');
|
const regularDiv = document.createElement('div');
|
||||||
testing.expectEqual('DIV', regularDiv.tagName);
|
testing.expectEqual('DIV', regularDiv.tagName);
|
||||||
@@ -36,5 +37,5 @@
|
|||||||
testing.expectEqual('te:ST', custom.tagName);
|
testing.expectEqual('te:ST', custom.tagName);
|
||||||
testing.expectEqual('te', custom.prefix);
|
testing.expectEqual('te', custom.prefix);
|
||||||
testing.expectEqual('ST', custom.localName);
|
testing.expectEqual('ST', custom.localName);
|
||||||
testing.expectEqual('http://www.w3.org/1999/xhtml', custom.namespaceURI); // Should be test
|
testing.expectEqual('http://lightpanda.io/unsupported/namespace', custom.namespaceURI); // Should be test
|
||||||
</script>
|
</script>
|
||||||
|
|||||||
@@ -168,7 +168,7 @@
|
|||||||
const root = doc.documentElement;
|
const root = doc.documentElement;
|
||||||
testing.expectEqual(true, root !== null);
|
testing.expectEqual(true, root !== null);
|
||||||
// TODO: XML documents should preserve case, but we currently uppercase
|
// TODO: XML documents should preserve case, but we currently uppercase
|
||||||
testing.expectEqual('ROOT', root.tagName);
|
testing.expectEqual('root', root.tagName);
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
@@ -206,10 +206,9 @@
|
|||||||
const doc = impl.createDocument('http://example.com', 'prefix:localName', null);
|
const doc = impl.createDocument('http://example.com', 'prefix:localName', null);
|
||||||
|
|
||||||
const root = doc.documentElement;
|
const root = doc.documentElement;
|
||||||
// TODO: XML documents should preserve case, but we currently uppercase
|
testing.expectEqual('prefix:localName', root.tagName);
|
||||||
testing.expectEqual('prefix:LOCALNAME', root.tagName);
|
// TODO: Custom namespaces are being replaced with an empty value
|
||||||
// TODO: Custom namespaces are being overridden to XHTML namespace
|
testing.expectEqual('http://lightpanda.io/unsupported/namespace', root.namespaceURI);
|
||||||
testing.expectEqual('http://www.w3.org/1999/xhtml', root.namespaceURI);
|
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
@@ -224,8 +223,7 @@
|
|||||||
doc.documentElement.appendChild(child);
|
doc.documentElement.appendChild(child);
|
||||||
|
|
||||||
testing.expectEqual(1, doc.documentElement.childNodes.length);
|
testing.expectEqual(1, doc.documentElement.childNodes.length);
|
||||||
// TODO: XML documents should preserve case, but we currently uppercase
|
testing.expectEqual('child', doc.documentElement.firstChild.tagName);
|
||||||
testing.expectEqual('CHILD', doc.documentElement.firstChild.tagName);
|
|
||||||
testing.expectEqual('Test', doc.documentElement.firstChild.textContent);
|
testing.expectEqual('Test', doc.documentElement.firstChild.textContent);
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|||||||
@@ -364,14 +364,14 @@
|
|||||||
];
|
];
|
||||||
|
|
||||||
for (const mime of mimes) {
|
for (const mime of mimes) {
|
||||||
const doc = parser.parseFromString(sampleXML, "text/xml");
|
const doc = parser.parseFromString(sampleXML, mime);
|
||||||
const { firstChild: { childNodes, children: collection, tagName }, children } = doc;
|
const { firstChild: { childNodes, children: collection, tagName }, children } = doc;
|
||||||
// doc.
|
// doc.
|
||||||
testing.expectEqual(true, doc instanceof XMLDocument);
|
testing.expectEqual(true, doc instanceof XMLDocument);
|
||||||
testing.expectEqual(1, children.length);
|
testing.expectEqual(1, children.length);
|
||||||
// firstChild.
|
// firstChild.
|
||||||
// TODO: Modern browsers expect this in lowercase.
|
// TODO: Modern browsers expect this in lowercase.
|
||||||
testing.expectEqual("CATALOG", tagName);
|
testing.expectEqual("catalog", tagName);
|
||||||
testing.expectEqual(25, childNodes.length);
|
testing.expectEqual(25, childNodes.length);
|
||||||
testing.expectEqual(12, collection.length);
|
testing.expectEqual(12, collection.length);
|
||||||
// Check children of first child.
|
// Check children of first child.
|
||||||
@@ -379,12 +379,12 @@
|
|||||||
const {children: elements, id} = collection.item(i);
|
const {children: elements, id} = collection.item(i);
|
||||||
testing.expectEqual("bk" + (100 + i + 1), id);
|
testing.expectEqual("bk" + (100 + i + 1), id);
|
||||||
// TODO: Modern browsers expect these in lowercase.
|
// TODO: Modern browsers expect these in lowercase.
|
||||||
testing.expectEqual("AUTHOR", elements.item(0).tagName);
|
testing.expectEqual("author", elements.item(0).tagName);
|
||||||
testing.expectEqual("TITLE", elements.item(1).tagName);
|
testing.expectEqual("title", elements.item(1).tagName);
|
||||||
testing.expectEqual("GENRE", elements.item(2).tagName);
|
testing.expectEqual("genre", elements.item(2).tagName);
|
||||||
testing.expectEqual("PRICE", elements.item(3).tagName);
|
testing.expectEqual("price", elements.item(3).tagName);
|
||||||
testing.expectEqual("PUBLISH_DATE", elements.item(4).tagName);
|
testing.expectEqual("publish_date", elements.item(4).tagName);
|
||||||
testing.expectEqual("DESCRIPTION", elements.item(5).tagName);
|
testing.expectEqual("description", elements.item(5).tagName);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -57,26 +57,26 @@ pub fn createHTMLDocument(_: *const DOMImplementation, title: ?[]const u8, page:
|
|||||||
_ = try document.asNode().appendChild(doctype.asNode(), page);
|
_ = try document.asNode().appendChild(doctype.asNode(), page);
|
||||||
}
|
}
|
||||||
|
|
||||||
const html_node = try page.createElement(null, "html", null);
|
const html_node = try page.createElementNS(.html, "html", null);
|
||||||
_ = try document.asNode().appendChild(html_node, page);
|
_ = try document.asNode().appendChild(html_node, page);
|
||||||
|
|
||||||
const head_node = try page.createElement(null, "head", null);
|
const head_node = try page.createElementNS(.html, "head", null);
|
||||||
_ = try html_node.appendChild(head_node, page);
|
_ = try html_node.appendChild(head_node, page);
|
||||||
|
|
||||||
if (title) |t| {
|
if (title) |t| {
|
||||||
const title_node = try page.createElement(null, "title", null);
|
const title_node = try page.createElementNS(.html, "title", null);
|
||||||
_ = try head_node.appendChild(title_node, page);
|
_ = try head_node.appendChild(title_node, page);
|
||||||
const text_node = try page.createTextNode(t);
|
const text_node = try page.createTextNode(t);
|
||||||
_ = try title_node.appendChild(text_node, page);
|
_ = try title_node.appendChild(text_node, page);
|
||||||
}
|
}
|
||||||
|
|
||||||
const body_node = try page.createElement(null, "body", null);
|
const body_node = try page.createElementNS(.html, "body", null);
|
||||||
_ = try html_node.appendChild(body_node, page);
|
_ = try html_node.appendChild(body_node, page);
|
||||||
|
|
||||||
return document;
|
return document;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn createDocument(_: *const DOMImplementation, namespace: ?[]const u8, qualified_name: ?[]const u8, doctype: ?*DocumentType, page: *Page) !*Document {
|
pub fn createDocument(_: *const DOMImplementation, namespace_: ?[]const u8, qualified_name: ?[]const u8, doctype: ?*DocumentType, page: *Page) !*Document {
|
||||||
// Create XML Document
|
// Create XML Document
|
||||||
const document = (try page._factory.document(Node.Document.XMLDocument{ ._proto = undefined })).asDocument();
|
const document = (try page._factory.document(Node.Document.XMLDocument{ ._proto = undefined })).asDocument();
|
||||||
|
|
||||||
@@ -88,7 +88,8 @@ pub fn createDocument(_: *const DOMImplementation, namespace: ?[]const u8, quali
|
|||||||
// Create and append root element if qualified_name provided
|
// Create and append root element if qualified_name provided
|
||||||
if (qualified_name) |qname| {
|
if (qualified_name) |qname| {
|
||||||
if (qname.len > 0) {
|
if (qname.len > 0) {
|
||||||
const root = try page.createElement(namespace, qname, null);
|
const namespace = if (namespace_) |ns| Node.Element.Namespace.parse(ns) else .xml;
|
||||||
|
const root = try page.createElementNS(namespace, qname, null);
|
||||||
_ = try document.asNode().appendChild(root, page);
|
_ = try document.asNode().appendChild(root, page);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -124,7 +124,14 @@ const CreateElementOptions = struct {
|
|||||||
};
|
};
|
||||||
|
|
||||||
pub fn createElement(self: *Document, name: []const u8, options_: ?CreateElementOptions, page: *Page) !*Element {
|
pub fn createElement(self: *Document, name: []const u8, options_: ?CreateElementOptions, page: *Page) !*Element {
|
||||||
const node = try page.createElement(null, name, null);
|
const namespace: Element.Namespace = blk: {
|
||||||
|
if (self._type == .xml) {
|
||||||
|
@branchHint(.unlikely);
|
||||||
|
break :blk .xml;
|
||||||
|
}
|
||||||
|
break :blk .html;
|
||||||
|
};
|
||||||
|
const node = try page.createElementNS(namespace, name, null);
|
||||||
const element = node.as(Element);
|
const element = node.as(Element);
|
||||||
|
|
||||||
// Track owner document if it's not the main document
|
// Track owner document if it's not the main document
|
||||||
@@ -142,7 +149,7 @@ pub fn createElement(self: *Document, name: []const u8, options_: ?CreateElement
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn createElementNS(self: *Document, namespace: ?[]const u8, name: []const u8, page: *Page) !*Element {
|
pub fn createElementNS(self: *Document, namespace: ?[]const u8, name: []const u8, page: *Page) !*Element {
|
||||||
const node = try page.createElement(namespace, name, null);
|
const node = try page.createElementNS(Element.Namespace.parse(namespace), name, null);
|
||||||
|
|
||||||
// Track owner document if it's not the main document
|
// Track owner document if it's not the main document
|
||||||
if (self != page.document) {
|
if (self != page.document) {
|
||||||
|
|||||||
@@ -53,15 +53,41 @@ pub const Namespace = enum(u8) {
|
|||||||
svg,
|
svg,
|
||||||
mathml,
|
mathml,
|
||||||
xml,
|
xml,
|
||||||
|
// We should keep the original value, but don't. If this becomes important
|
||||||
|
// consider storing it in a page lookup, like `_element_class_lists`, rather
|
||||||
|
// that adding a slice directly here (directly in every element).
|
||||||
|
unknown,
|
||||||
|
null,
|
||||||
|
|
||||||
pub fn toUri(self: Namespace) []const u8 {
|
pub fn toUri(self: Namespace) ?[]const u8 {
|
||||||
return switch (self) {
|
return switch (self) {
|
||||||
.html => "http://www.w3.org/1999/xhtml",
|
.html => "http://www.w3.org/1999/xhtml",
|
||||||
.svg => "http://www.w3.org/2000/svg",
|
.svg => "http://www.w3.org/2000/svg",
|
||||||
.mathml => "http://www.w3.org/1998/Math/MathML",
|
.mathml => "http://www.w3.org/1998/Math/MathML",
|
||||||
.xml => "http://www.w3.org/XML/1998/namespace",
|
.xml => "http://www.w3.org/XML/1998/namespace",
|
||||||
|
.unknown => "http://lightpanda.io/unsupported/namespace",
|
||||||
|
.null => null,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn parse(namespace_: ?[]const u8) Namespace {
|
||||||
|
const namespace = namespace_ orelse return .null;
|
||||||
|
if (namespace.len == "http://www.w3.org/1999/xhtml".len) {
|
||||||
|
// Common case, avoid the string comparion. Recklessly
|
||||||
|
@branchHint(.likely);
|
||||||
|
return .html;
|
||||||
|
}
|
||||||
|
if (std.mem.eql(u8, namespace, "http://www.w3.org/XML/1998/namespace")) {
|
||||||
|
return .xml;
|
||||||
|
}
|
||||||
|
if (std.mem.eql(u8, namespace, "http://www.w3.org/2000/svg")) {
|
||||||
|
return .svg;
|
||||||
|
}
|
||||||
|
if (std.mem.eql(u8, namespace, "http://www.w3.org/1998/Math/MathML")) {
|
||||||
|
return .mathml;
|
||||||
|
}
|
||||||
|
return .unknown;
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
_type: Type,
|
_type: Type,
|
||||||
@@ -211,60 +237,54 @@ pub fn getTagNameLower(self: *const Element) []const u8 {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn getTagNameSpec(self: *const Element, buf: []u8) []const u8 {
|
pub fn getTagNameSpec(self: *const Element, buf: []u8) []const u8 {
|
||||||
switch (self._type) {
|
return switch (self._type) {
|
||||||
.html => |he| switch (he._type) {
|
.html => |he| switch (he._type) {
|
||||||
.custom => |e| {
|
.anchor => "A",
|
||||||
@branchHint(.unlikely);
|
.body => "BODY",
|
||||||
return upperTagName(&e._tag_name, buf);
|
.br => "BR",
|
||||||
|
.button => "BUTTON",
|
||||||
|
.canvas => "CANVAS",
|
||||||
|
.custom => |e| upperTagName(&e._tag_name, buf),
|
||||||
|
.data => "DATA",
|
||||||
|
.dialog => "DIALOG",
|
||||||
|
.div => "DIV",
|
||||||
|
.embed => "EMBED",
|
||||||
|
.form => "FORM",
|
||||||
|
.generic => |e| upperTagName(&e._tag_name, buf),
|
||||||
|
.heading => |e| upperTagName(&e._tag_name, buf),
|
||||||
|
.head => "HEAD",
|
||||||
|
.html => "HTML",
|
||||||
|
.hr => "HR",
|
||||||
|
.iframe => "IFRAME",
|
||||||
|
.img => "IMG",
|
||||||
|
.input => "INPUT",
|
||||||
|
.li => "LI",
|
||||||
|
.link => "LINK",
|
||||||
|
.meta => "META",
|
||||||
|
.media => |m| switch (m._type) {
|
||||||
|
.audio => "AUDIO",
|
||||||
|
.video => "VIDEO",
|
||||||
|
.generic => "MEDIA",
|
||||||
},
|
},
|
||||||
else => return switch (he._type) {
|
.ol => "OL",
|
||||||
.anchor => "A",
|
.option => "OPTION",
|
||||||
.body => "BODY",
|
.p => "P",
|
||||||
.br => "BR",
|
.script => "SCRIPT",
|
||||||
.button => "BUTTON",
|
.select => "SELECT",
|
||||||
.canvas => "CANVAS",
|
.slot => "SLOT",
|
||||||
.custom => |e| upperTagName(&e._tag_name, buf),
|
.span => "SPAN",
|
||||||
.data => "DATA",
|
.style => "STYLE",
|
||||||
.dialog => "DIALOG",
|
.template => "TEMPLATE",
|
||||||
.div => "DIV",
|
.textarea => "TEXTAREA",
|
||||||
.embed => "EMBED",
|
.title => "TITLE",
|
||||||
.form => "FORM",
|
.ul => "UL",
|
||||||
.generic => |e| upperTagName(&e._tag_name, buf),
|
.unknown => |e| switch (self._namespace) {
|
||||||
.heading => |e| upperTagName(&e._tag_name, buf),
|
.html => upperTagName(&e._tag_name, buf),
|
||||||
.head => "HEAD",
|
.svg, .xml, .mathml, .unknown, .null => e._tag_name.str(),
|
||||||
.html => "HTML",
|
|
||||||
.hr => "HR",
|
|
||||||
.iframe => "IFRAME",
|
|
||||||
.img => "IMG",
|
|
||||||
.input => "INPUT",
|
|
||||||
.li => "LI",
|
|
||||||
.link => "LINK",
|
|
||||||
.meta => "META",
|
|
||||||
.media => |m| switch (m._type) {
|
|
||||||
.audio => "AUDIO",
|
|
||||||
.video => "VIDEO",
|
|
||||||
.generic => "MEDIA",
|
|
||||||
},
|
|
||||||
.ol => "OL",
|
|
||||||
.option => "OPTION",
|
|
||||||
.p => "P",
|
|
||||||
.script => "SCRIPT",
|
|
||||||
.select => "SELECT",
|
|
||||||
.slot => "SLOT",
|
|
||||||
.span => "SPAN",
|
|
||||||
.style => "STYLE",
|
|
||||||
.template => "TEMPLATE",
|
|
||||||
.textarea => "TEXTAREA",
|
|
||||||
.title => "TITLE",
|
|
||||||
.ul => "UL",
|
|
||||||
.unknown => |e| switch (self._namespace) {
|
|
||||||
.html => upperTagName(&e._tag_name, buf),
|
|
||||||
.svg, .xml, .mathml => return e._tag_name.str(),
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
.svg => |svg| return svg._tag_name.str(),
|
.svg => |svg| svg._tag_name.str(),
|
||||||
}
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn getTagNameDump(self: *const Element) []const u8 {
|
pub fn getTagNameDump(self: *const Element) []const u8 {
|
||||||
@@ -274,7 +294,7 @@ pub fn getTagNameDump(self: *const Element) []const u8 {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn getNamespaceURI(self: *const Element) []const u8 {
|
pub fn getNamespaceURI(self: *const Element) ?[]const u8 {
|
||||||
return self._namespace.toUri();
|
return self._namespace.toUri();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -996,9 +1016,7 @@ pub fn getElementsByClassName(self: *Element, class_name: []const u8, page: *Pag
|
|||||||
|
|
||||||
pub fn cloneElement(self: *Element, deep: bool, page: *Page) !*Node {
|
pub fn cloneElement(self: *Element, deep: bool, page: *Page) !*Node {
|
||||||
const tag_name = self.getTagNameDump();
|
const tag_name = self.getTagNameDump();
|
||||||
const namespace_uri = self.getNamespaceURI();
|
const node = try page.createElementNS(self._namespace, tag_name, self._attributes);
|
||||||
|
|
||||||
const node = try page.createElement(namespace_uri, tag_name, self._attributes);
|
|
||||||
|
|
||||||
// Allow element-specific types to copy their runtime state
|
// Allow element-specific types to copy their runtime state
|
||||||
_ = Element.Build.call(node.as(Element), "cloned", .{ self, node.as(Element), page }) catch |err| {
|
_ = Element.Build.call(node.as(Element), "cloned", .{ self, node.as(Element), page }) catch |err| {
|
||||||
|
|||||||
@@ -132,7 +132,7 @@ pub fn setTitle(self: *HTMLDocument, title: []const u8, page: *Page) !void {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// No title element found, create one
|
// No title element found, create one
|
||||||
const title_node = try page.createElement(null, "title", null);
|
const title_node = try page.createElementNS(.html, "title", null);
|
||||||
const title_element = title_node.as(Element);
|
const title_element = title_node.as(Element);
|
||||||
|
|
||||||
// Only add text if non-empty
|
// Only add text if non-empty
|
||||||
|
|||||||
@@ -443,9 +443,9 @@ pub fn createContextualFragment(self: *const Range, html: []const u8, page: *Pag
|
|||||||
// Create a temporary element of the same type as the context for parsing
|
// Create a temporary element of the same type as the context for parsing
|
||||||
// This preserves the parsing context without modifying the original node
|
// This preserves the parsing context without modifying the original node
|
||||||
const temp_node = if (context_node.is(Node.Element)) |el|
|
const temp_node = if (context_node.is(Node.Element)) |el|
|
||||||
try page.createElement(el._namespace.toUri(), el.getTagNameLower(), null)
|
try page.createElementNS(el._namespace, el.getTagNameLower(), null)
|
||||||
else
|
else
|
||||||
try page.createElement(null, "div", null);
|
try page.createElementNS(.html, "div", null);
|
||||||
|
|
||||||
try page.parseHtmlAsChildren(temp_node, html);
|
try page.parseHtmlAsChildren(temp_node, html);
|
||||||
|
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ const Image = @This();
|
|||||||
_proto: *HtmlElement,
|
_proto: *HtmlElement,
|
||||||
|
|
||||||
pub fn constructor(w_: ?u32, h_: ?u32, page: *Page) !*Image {
|
pub fn constructor(w_: ?u32, h_: ?u32, page: *Page) !*Image {
|
||||||
const node = try page.createElement(null, "img", null);
|
const node = try page.createElementNS(.html, "img", null);
|
||||||
const el = node.as(Element);
|
const el = node.as(Element);
|
||||||
|
|
||||||
if (w_) |w| blk: {
|
if (w_) |w| blk: {
|
||||||
|
|||||||
Reference in New Issue
Block a user