Support cloneNode for DocumentType and Attribute

This commit is contained in:
Karl Seguin
2026-01-09 11:10:50 +08:00
parent 78ebd5faf8
commit 6c7c507d32
5 changed files with 41 additions and 18 deletions

View File

@@ -28,19 +28,7 @@ const DOMImplementation = @This();
_pad: bool = false,
pub fn createDocumentType(_: *const DOMImplementation, qualified_name: []const u8, public_id: ?[]const u8, system_id: ?[]const u8, page: *Page) !*DocumentType {
const name = try page.dupeString(qualified_name);
// Firefox converts null to the string "null", not empty string
const pub_id = if (public_id) |p| try page.dupeString(p) else "null";
const sys_id = if (system_id) |s| try page.dupeString(s) else "null";
const doctype = try page._factory.node(DocumentType{
._proto = undefined,
._name = name,
._public_id = pub_id,
._system_id = sys_id,
});
return doctype;
return DocumentType.init(qualified_name, public_id, system_id, page);
}
pub fn createHTMLDocument(_: *const DOMImplementation, title: ?[]const u8, page: *Page) !*Document {

View File

@@ -19,6 +19,8 @@
const std = @import("std");
const js = @import("../js/js.zig");
const Page = @import("../Page.zig");
const Node = @import("Node.zig");
const DocumentType = @This();
@@ -28,6 +30,20 @@ _name: []const u8,
_public_id: []const u8,
_system_id: []const u8,
pub fn init(qualified_name: []const u8, public_id: ?[]const u8, system_id: ?[]const u8, page: *Page) !*DocumentType {
const name = try page.dupeString(qualified_name);
// Firefox converts null to the string "null", not empty string
const pub_id = if (public_id) |p| try page.dupeString(p) else "null";
const sys_id = if (system_id) |s| try page.dupeString(s) else "null";
return page._factory.node(DocumentType{
._proto = undefined,
._name = name,
._public_id = pub_id,
._system_id = sys_id,
});
}
pub fn asNode(self: *DocumentType) *Node {
return self._proto;
}
@@ -54,6 +70,10 @@ pub fn isEqualNode(self: *const DocumentType, other: *const DocumentType) bool {
std.mem.eql(u8, self._system_id, other._system_id);
}
pub fn clone(self: *const DocumentType, page: *Page) !*DocumentType {
return .init(self._name, self._public_id, self._system_id, page);
}
pub const JsApi = struct {
pub const bridge = js.Bridge(DocumentType);

View File

@@ -1014,7 +1014,7 @@ pub fn getElementsByClassName(self: *Element, class_name: []const u8, page: *Pag
return collections.NodeLive(.class_name).init(self.asNode(), class_names.items, page);
}
pub fn cloneElement(self: *Element, deep: bool, page: *Page) !*Node {
pub fn clone(self: *Element, deep: bool, page: *Page) !*Node {
const tag_name = self.getTagNameDump();
const node = try page.createElementNS(self._namespace, tag_name, self._attributes);

View File

@@ -664,7 +664,7 @@ pub fn normalize(self: *Node, page: *Page) !void {
return self._normalize(page.call_arena, &buffer, page);
}
pub fn cloneNode(self: *Node, deep_: ?bool, page: *Page) error{ OutOfMemory, StringTooLarge, NotSupported, NotImplemented, InvalidCharacterError }!*Node {
pub fn cloneNode(self: *Node, deep_: ?bool, page: *Page) error{ OutOfMemory, StringTooLarge, NotSupported, NotImplemented, InvalidCharacterError, CloneError }!*Node {
const deep = deep_ orelse false;
switch (self._type) {
.cdata => |cd| {
@@ -676,11 +676,17 @@ pub fn cloneNode(self: *Node, deep_: ?bool, page: *Page) error{ OutOfMemory, Str
.processing_instruction => |pi| page.createProcessingInstruction(pi._target, data),
};
},
.element => |el| return el.cloneElement(deep, page),
.element => |el| return el.clone(deep, page),
.document => return error.NotSupported,
.document_type => return error.NotSupported,
.document_type => |dt| {
const cloned = dt.clone(page) catch return error.CloneError;
return cloned.asNode();
},
.document_fragment => |frag| return frag.cloneFragment(deep, page),
.attribute => return error.NotSupported,
.attribute => |attr| {
const cloned = attr.clone(page) catch return error.CloneError;
return cloned._proto;
},
}
}

View File

@@ -78,6 +78,15 @@ pub fn isEqualNode(self: *const Attribute, other: *const Attribute) bool {
return std.mem.eql(u8, self.getName(), other.getName()) and std.mem.eql(u8, self.getValue(), other.getValue());
}
pub fn clone(self: *const Attribute, page: *Page) !*Attribute {
return page._factory.node(Attribute{
._proto = undefined,
._element = self._element,
._name = self._name,
._value = self._value,
});
}
pub const JsApi = struct {
pub const bridge = js.Bridge(Attribute);