diff --git a/src/dom/document.zig b/src/dom/document.zig index 72537992..791b1440 100644 --- a/src/dom/document.zig +++ b/src/dom/document.zig @@ -34,9 +34,10 @@ pub const Document = struct { return DOMImplementation{}; } - pub fn get_documentElement(self: *parser.Document) !ElementUnion { + pub fn get_documentElement(self: *parser.Document) !?ElementUnion { const e = try parser.documentGetDocumentElement(self); - return try Element.toInterface(e); + if (e == null) return null; + return try Element.toInterface(e.?); } pub fn get_documentURI(self: *parser.Document) ![]const u8 { @@ -105,13 +106,12 @@ pub const Document = struct { alloc: std.mem.Allocator, tag_name: []const u8, ) !collection.HTMLCollection { - const root = try parser.documentGetDocumentElement(self); - return try collection.HTMLCollectionByTagName( - alloc, - parser.elementToNode(root), - tag_name, - true, - ); + var elt: ?*parser.Node = null; + if (try parser.documentGetDocumentElement(self)) |root| { + elt = parser.elementToNode(root); + } + + return try collection.HTMLCollectionByTagName(alloc, elt, tag_name, true); } pub fn _getElementsByClassName( @@ -119,13 +119,12 @@ pub const Document = struct { alloc: std.mem.Allocator, classNames: []const u8, ) !collection.HTMLCollection { - const root = try parser.documentGetDocumentElement(self); - return try collection.HTMLCollectionByClassName( - alloc, - parser.elementToNode(root), - classNames, - true, - ); + var elt: ?*parser.Node = null; + if (try parser.documentGetDocumentElement(self)) |root| { + elt = parser.elementToNode(root); + } + + return try collection.HTMLCollectionByClassName(alloc, elt, classNames, true); } pub fn _createDocumentFragment(self: *parser.Document) !*parser.DocumentFragment { @@ -169,8 +168,11 @@ pub const Document = struct { // ParentNode // https://dom.spec.whatwg.org/#parentnode pub fn get_children(self: *parser.Document) !collection.HTMLCollection { - const root = try parser.documentGetDocumentElement(self); - return try collection.HTMLCollectionChildren(parser.elementToNode(root), true); + var elt: ?*parser.Node = null; + if (try parser.documentGetDocumentElement(self)) |root| { + elt = parser.elementToNode(root); + } + return try collection.HTMLCollectionChildren(elt, true); } pub fn deinit(_: *parser.Document, _: std.mem.Allocator) void {} @@ -188,6 +190,12 @@ pub fn testExecFn( .{ .src = "document.__proto__.__proto__.constructor.name", .ex = "Document" }, .{ .src = "document.__proto__.__proto__.__proto__.constructor.name", .ex = "Node" }, .{ .src = "document.__proto__.__proto__.__proto__.__proto__.constructor.name", .ex = "EventTarget" }, + + .{ .src = "let newdoc = new Document()", .ex = "undefined" }, + .{ .src = "newdoc.documentElement", .ex = "null" }, + .{ .src = "newdoc.children.length", .ex = "0" }, + .{ .src = "newdoc.getElementsByTagName('*').length", .ex = "0" }, + .{ .src = "newdoc.getElementsByTagName('*').item(0)", .ex = "null" }, }; try checkCases(js_env, &constructor); diff --git a/src/dom/html_collection.zig b/src/dom/html_collection.zig index 5928a35e..f3191ceb 100644 --- a/src/dom/html_collection.zig +++ b/src/dom/html_collection.zig @@ -57,7 +57,7 @@ pub const MatchByTagName = struct { pub fn HTMLCollectionByTagName( alloc: std.mem.Allocator, - root: *parser.Node, + root: ?*parser.Node, tag_name: []const u8, include_root: bool, ) !HTMLCollection { @@ -101,7 +101,7 @@ pub const MatchByClassName = struct { pub fn HTMLCollectionByClassName( alloc: std.mem.Allocator, - root: *parser.Node, + root: ?*parser.Node, classNames: []const u8, include_root: bool, ) !HTMLCollection { @@ -116,7 +116,7 @@ pub fn HTMLCollectionByClassName( } pub fn HTMLCollectionChildren( - root: *parser.Node, + root: ?*parser.Node, include_root: bool, ) !HTMLCollection { return HTMLCollection{ @@ -219,7 +219,7 @@ pub const HTMLCollection = struct { matcher: Matcher, walker: Walker, - root: *parser.Node, + root: ?*parser.Node, // By default the HTMLCollection walk on the root's descendant only. // But on somes cases, like for dom document, we want to walk over the root @@ -232,17 +232,21 @@ pub const HTMLCollection = struct { // start returns the first node to walk on. fn start(self: HTMLCollection) !?*parser.Node { + if (self.root == null) return null; + if (self.include_root) { - return self.root; + return self.root.?; } - return try self.walker.get_next(self.root, null); + return try self.walker.get_next(self.root.?, null); } /// get_length computes the collection's length dynamically according to /// the current root structure. // TODO: nodes retrieved must be de-referenced. pub fn get_length(self: *HTMLCollection) !u32 { + if (self.root == null) return 0; + var len: u32 = 0; var node = try self.start() orelse return 0; @@ -253,13 +257,15 @@ pub const HTMLCollection = struct { } } - node = try self.walker.get_next(self.root, node) orelse break; + node = try self.walker.get_next(self.root.?, node) orelse break; } return len; } pub fn _item(self: *HTMLCollection, index: u32) !?Union { + if (self.root == null) return null; + var i: u32 = 0; var node: *parser.Node = undefined; @@ -288,16 +294,15 @@ pub const HTMLCollection = struct { } } - node = try self.walker.get_next(self.root, node) orelse break; + node = try self.walker.get_next(self.root.?, node) orelse break; } return null; } pub fn _namedItem(self: *HTMLCollection, name: []const u8) !?Union { - if (name.len == 0) { - return null; - } + if (self.root == null) return null; + if (name.len == 0) return null; var node = try self.start() orelse return null; @@ -320,7 +325,7 @@ pub const HTMLCollection = struct { } } - node = try self.walker.get_next(self.root, node) orelse break; + node = try self.walker.get_next(self.root.?, node) orelse break; } return null; diff --git a/src/netsurf.zig b/src/netsurf.zig index 3f8336ff..2455b35a 100644 --- a/src/netsurf.zig +++ b/src/netsurf.zig @@ -1150,10 +1150,11 @@ pub inline fn documentGetElementsByTagName(doc: *Document, tagname: []const u8) } // documentGetDocumentElement returns the root document element. -pub inline fn documentGetDocumentElement(doc: *Document) !*Element { +pub inline fn documentGetDocumentElement(doc: *Document) !?*Element { var elem: ?*Element = undefined; const err = documentVtable(doc).dom_document_get_document_element.?(doc, &elem); try DOMErr(err); + if (elem == null) return null; return elem.?; }