diff --git a/src/dom/cdata_section.zig b/src/dom/cdata_section.zig new file mode 100644 index 00000000..8f02ceb1 --- /dev/null +++ b/src/dom/cdata_section.zig @@ -0,0 +1,12 @@ +const std = @import("std"); + +const parser = @import("../netsurf.zig"); + +const Text = @import("text.zig").Text; + +// https://dom.spec.whatwg.org/#cdatasection +pub const CDATASection = struct { + pub const Self = parser.CDATASection; + pub const prototype = *Text; + pub const mem_guarantied = true; +}; diff --git a/src/dom/character_data.zig b/src/dom/character_data.zig index 8f139691..54c4b603 100644 --- a/src/dom/character_data.zig +++ b/src/dom/character_data.zig @@ -9,13 +9,16 @@ const parser = @import("../netsurf.zig"); const Node = @import("node.zig").Node; const Comment = @import("comment.zig").Comment; -const Text = @import("text.zig").Text; +const Text = @import("text.zig"); +const ProcessingInstruction = @import("processing_instruction.zig").ProcessingInstruction; const HTMLElem = @import("../html/elements.zig"); // CharacterData interfaces pub const Interfaces = generate.Tuple(.{ Comment, - Text, + Text.Text, + Text.Interfaces, + ProcessingInstruction, }); // CharacterData implementation diff --git a/src/dom/document.zig b/src/dom/document.zig index adf34d35..8bb4577d 100644 --- a/src/dom/document.zig +++ b/src/dom/document.zig @@ -7,6 +7,7 @@ const Case = jsruntime.test_utils.Case; const checkCases = jsruntime.test_utils.checkCases; const Node = @import("node.zig").Node; +const NodeUnion = @import("node.zig").Union; const collection = @import("html_collection.zig"); @@ -129,6 +130,40 @@ pub const Document = struct { return try parser.documentCreateDocumentFragment(self); } + pub fn _createTextNode(self: *parser.Document, data: []const u8) !*parser.Text { + return try parser.documentCreateTextNode(self, data); + } + + pub fn _createCDATASection(self: *parser.Document, data: []const u8) !*parser.CDATASection { + return try parser.documentCreateCDATASection(self, data); + } + + pub fn _createComment(self: *parser.Document, data: []const u8) !*parser.Comment { + return try parser.documentCreateComment(self, data); + } + + pub fn _createProcessingInstruction(self: *parser.Document, target: []const u8, data: []const u8) !*parser.ProcessingInstruction { + return try parser.documentCreateProcessingInstruction(self, target, data); + } + + pub fn _importNode(self: *parser.Document, node: *parser.Node, deep: ?bool) !NodeUnion { + const n = try parser.documentImportNode(self, node, deep orelse false); + return try Node.toInterface(n); + } + + pub fn _adoptNode(self: *parser.Document, node: *parser.Node) !NodeUnion { + const n = try parser.documentAdoptNode(self, node); + return try Node.toInterface(n); + } + + pub fn _createAttribute(self: *parser.Document, name: []const u8) !*parser.Attribute { + return try parser.documentCreateAttribute(self, name); + } + + pub fn _createAttributeNS(self: *parser.Document, ns: []const u8, qname: []const u8) !*parser.Attribute { + return try parser.documentCreateAttributeNS(self, ns, qname); + } + pub fn deinit(_: *parser.Document, _: std.mem.Allocator) void {} }; @@ -222,10 +257,55 @@ pub fn testExecFn( try checkCases(js_env, &new); var createDocumentFragment = [_]Case{ - .{ .src = "document.createDocumentFragment()", .ex = "[object DocumentFragment]" }, + .{ .src = "var v = document.createDocumentFragment()", .ex = "undefined" }, + .{ .src = "v.nodeName", .ex = "#document-fragment" }, }; try checkCases(js_env, &createDocumentFragment); + var createTextNode = [_]Case{ + .{ .src = "var v = document.createTextNode('foo')", .ex = "undefined" }, + .{ .src = "v.nodeName", .ex = "#text" }, + }; + try checkCases(js_env, &createTextNode); + + var createCDATASection = [_]Case{ + .{ .src = "var v = document.createCDATASection('foo')", .ex = "undefined" }, + .{ .src = "v.nodeName", .ex = "#cdata-section" }, + }; + try checkCases(js_env, &createCDATASection); + + var createComment = [_]Case{ + .{ .src = "var v = document.createComment('foo')", .ex = "undefined" }, + .{ .src = "v.nodeName", .ex = "#comment" }, + }; + try checkCases(js_env, &createComment); + + var createProcessingInstruction = [_]Case{ + .{ .src = "let pi = document.createProcessingInstruction('foo', 'bar')", .ex = "undefined" }, + .{ .src = "pi.target", .ex = "foo" }, + }; + try checkCases(js_env, &createProcessingInstruction); + + var importNode = [_]Case{ + .{ .src = "let nimp = document.getElementById('content')", .ex = "undefined" }, + .{ .src = "var v = document.importNode(nimp)", .ex = "undefined" }, + .{ .src = "v.nodeName", .ex = "DIV" }, + }; + try checkCases(js_env, &importNode); + + var adoptNode = [_]Case{ + .{ .src = "let nadop = document.getElementById('content')", .ex = "undefined" }, + .{ .src = "var v = document.adoptNode(nadop)", .ex = "undefined" }, + .{ .src = "v.nodeName", .ex = "DIV" }, + }; + try checkCases(js_env, &adoptNode); + + var createAttr = [_]Case{ + .{ .src = "var v = document.createAttribute('foo')", .ex = "undefined" }, + .{ .src = "v.nodeName", .ex = "foo" }, + }; + try checkCases(js_env, &createAttr); + const tags = comptime parser.Tag.all(); comptime var createElements: [(tags.len) * 2]Case = undefined; inline for (tags, 0..) |tag, i| { diff --git a/src/dom/node.zig b/src/dom/node.zig index 022aa9c7..86b3dae5 100644 --- a/src/dom/node.zig +++ b/src/dom/node.zig @@ -54,6 +54,8 @@ pub const Node = struct { ), .comment => .{ .Comment = @as(*parser.Comment, @ptrCast(node)) }, .text => .{ .Text = @as(*parser.Text, @ptrCast(node)) }, + .cdata_section => .{ .CDATASection = @as(*parser.CDATASection, @ptrCast(node)) }, + .processing_instruction => .{ .ProcessingInstruction = @as(*parser.ProcessingInstruction, @ptrCast(node)) }, .document => .{ .HTMLDocument = @as(*parser.DocumentHTML, @ptrCast(node)) }, .document_type => .{ .DocumentType = @as(*parser.DocumentType, @ptrCast(node)) }, .attribute => .{ .Attr = @as(*parser.Attribute, @ptrCast(node)) }, diff --git a/src/dom/processing_instruction.zig b/src/dom/processing_instruction.zig new file mode 100644 index 00000000..cb5cf29d --- /dev/null +++ b/src/dom/processing_instruction.zig @@ -0,0 +1,17 @@ +const std = @import("std"); + +const parser = @import("../netsurf.zig"); + +const CharacterData = @import("character_data.zig").CharacterData; + +// https://dom.spec.whatwg.org/#processinginstruction +pub const ProcessingInstruction = struct { + pub const Self = parser.ProcessingInstruction; + pub const prototype = *CharacterData; + pub const mem_guarantied = true; + + pub fn get_target(self: *parser.ProcessingInstruction) ![]const u8 { + // libdom stores the ProcessingInstruction target in the node's name. + return try parser.nodeName(@as(*parser.Node, @ptrCast(self))); + } +}; diff --git a/src/dom/text.zig b/src/dom/text.zig index ec098d00..30abec22 100644 --- a/src/dom/text.zig +++ b/src/dom/text.zig @@ -3,10 +3,17 @@ const std = @import("std"); const jsruntime = @import("jsruntime"); const Case = jsruntime.test_utils.Case; const checkCases = jsruntime.test_utils.checkCases; +const generate = @import("../generate.zig"); const parser = @import("../netsurf.zig"); const CharacterData = @import("character_data.zig").CharacterData; +const CDATASection = @import("cdata_section.zig").CDATASection; + +// Text interfaces +pub const Interfaces = generate.Tuple(.{ + CDATASection, +}); pub const Text = struct { pub const Self = parser.Text; diff --git a/src/netsurf.zig b/src/netsurf.zig index 0919e56a..d32b2cee 100644 --- a/src/netsurf.zig +++ b/src/netsurf.zig @@ -791,6 +791,9 @@ pub fn characterDataSubstringData(cdata: *CharacterData, offset: u32, count: u32 return strToData(s.?); } +// CDATASection +pub const CDATASection = c.dom_cdata_section; + // Text pub const Text = c.dom_text; @@ -815,6 +818,9 @@ pub fn textSplitText(text: *Text, offset: u32) !*Text { // Comment pub const Comment = c.dom_comment; +// ProcessingInstruction +pub const ProcessingInstruction = c.dom_processing_instruction; + // Attribute pub const Attribute = c.dom_attr; @@ -1137,6 +1143,74 @@ pub inline fn documentCreateDocumentFragment(doc: *Document) !*DocumentFragment return df.?; } +pub inline fn documentCreateTextNode(doc: *Document, s: []const u8) !*Text { + var txt: ?*Text = undefined; + const err = documentVtable(doc).dom_document_create_text_node.?(doc, try strFromData(s), &txt); + try DOMErr(err); + return txt.?; +} + +pub inline fn documentCreateCDATASection(doc: *Document, s: []const u8) !*CDATASection { + var cdata: ?*CDATASection = undefined; + const err = documentVtable(doc).dom_document_create_cdata_section.?(doc, try strFromData(s), &cdata); + try DOMErr(err); + return cdata.?; +} + +pub inline fn documentCreateComment(doc: *Document, s: []const u8) !*Comment { + var com: ?*Comment = undefined; + const err = documentVtable(doc).dom_document_create_comment.?(doc, try strFromData(s), &com); + try DOMErr(err); + return com.?; +} + +pub inline fn documentCreateProcessingInstruction(doc: *Document, target: []const u8, data: []const u8) !*ProcessingInstruction { + var pi: ?*ProcessingInstruction = undefined; + const err = documentVtable(doc).dom_document_create_processing_instruction.?( + doc, + try strFromData(target), + try strFromData(data), + &pi, + ); + try DOMErr(err); + return pi.?; +} + +pub inline fn documentImportNode(doc: *Document, node: *Node, deep: bool) !*Node { + var res: NodeExternal = undefined; + const nodeext = toNodeExternal(Node, node); + const err = documentVtable(doc).dom_document_import_node.?(doc, nodeext, deep, &res); + try DOMErr(err); + return @as(*Node, @ptrCast(res)); +} + +pub inline fn documentAdoptNode(doc: *Document, node: *Node) !*Node { + var res: NodeExternal = undefined; + const nodeext = toNodeExternal(Node, node); + const err = documentVtable(doc).dom_document_adopt_node.?(doc, nodeext, &res); + try DOMErr(err); + return @as(*Node, @ptrCast(res)); +} + +pub inline fn documentCreateAttribute(doc: *Document, name: []const u8) !*Attribute { + var attr: ?*Attribute = undefined; + const err = documentVtable(doc).dom_document_create_attribute.?(doc, try strFromData(name), &attr); + try DOMErr(err); + return attr.?; +} + +pub inline fn documentCreateAttributeNS(doc: *Document, ns: []const u8, qname: []const u8) !*Attribute { + var attr: ?*Attribute = undefined; + const err = documentVtable(doc).dom_document_create_attribute_ns.?( + doc, + try strFromData(ns), + try strFromData(qname), + &attr, + ); + try DOMErr(err); + return attr.?; +} + // DocumentHTML pub const DocumentHTML = c.dom_html_document; diff --git a/tests/wpt/dom/nodes/Document-adoptNode.html b/tests/wpt/dom/nodes/Document-adoptNode.html new file mode 100644 index 00000000..60a4e677 --- /dev/null +++ b/tests/wpt/dom/nodes/Document-adoptNode.html @@ -0,0 +1,50 @@ + + +