mirror of
				https://github.com/lightpanda-io/browser.git
				synced 2025-10-30 15:41:48 +00:00 
			
		
		
		
	dom: add NamedNodeMap implementation
and create Attr type
This commit is contained in:
		
							
								
								
									
										15
									
								
								src/dom/attribute.zig
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										15
									
								
								src/dom/attribute.zig
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,15 @@ | |||||||
|  | const std = @import("std"); | ||||||
|  |  | ||||||
|  | const parser = @import("../netsurf.zig"); | ||||||
|  |  | ||||||
|  | const Node = @import("node.zig").Node; | ||||||
|  | const DOMException = @import("exceptions.zig").DOMException; | ||||||
|  |  | ||||||
|  | // WEB IDL https://dom.spec.whatwg.org/#attr | ||||||
|  | pub const Attr = struct { | ||||||
|  |     pub const Self = parser.Attribute; | ||||||
|  |     pub const prototype = *Node; | ||||||
|  |     pub const mem_guarantied = true; | ||||||
|  |  | ||||||
|  |     pub const Exception = DOMException; | ||||||
|  | }; | ||||||
| @@ -3,12 +3,14 @@ const generate = @import("../generate.zig"); | |||||||
| const DOMException = @import("exceptions.zig").DOMException; | const DOMException = @import("exceptions.zig").DOMException; | ||||||
| const EventTarget = @import("event_target.zig").EventTarget; | const EventTarget = @import("event_target.zig").EventTarget; | ||||||
| const DOMImplementation = @import("implementation.zig").DOMImplementation; | const DOMImplementation = @import("implementation.zig").DOMImplementation; | ||||||
|  | const NamedNodeMap = @import("namednodemap.zig").NamedNodeMap; | ||||||
| const Nod = @import("node.zig"); | const Nod = @import("node.zig"); | ||||||
|  |  | ||||||
| pub const Interfaces = generate.Tuple(.{ | pub const Interfaces = generate.Tuple(.{ | ||||||
|     DOMException, |     DOMException, | ||||||
|     EventTarget, |     EventTarget, | ||||||
|     DOMImplementation, |     DOMImplementation, | ||||||
|  |     NamedNodeMap, | ||||||
|     Nod.Node, |     Nod.Node, | ||||||
|     Nod.Interfaces, |     Nod.Interfaces, | ||||||
| }); | }); | ||||||
|   | |||||||
| @@ -10,12 +10,16 @@ const Node = @import("node.zig").Node; | |||||||
| const HTMLElem = @import("../html/elements.zig"); | const HTMLElem = @import("../html/elements.zig"); | ||||||
| pub const Union = @import("../html/elements.zig").Union; | pub const Union = @import("../html/elements.zig").Union; | ||||||
|  |  | ||||||
|  | const DOMException = @import("exceptions.zig").DOMException; | ||||||
|  |  | ||||||
| // WEB IDL https://dom.spec.whatwg.org/#element | // WEB IDL https://dom.spec.whatwg.org/#element | ||||||
| pub const Element = struct { | pub const Element = struct { | ||||||
|     pub const Self = parser.Element; |     pub const Self = parser.Element; | ||||||
|     pub const prototype = *Node; |     pub const prototype = *Node; | ||||||
|     pub const mem_guarantied = true; |     pub const mem_guarantied = true; | ||||||
|  |  | ||||||
|  |     pub const Exception = DOMException; | ||||||
|  |  | ||||||
|     pub fn toInterface(e: *parser.Element) !Union { |     pub fn toInterface(e: *parser.Element) !Union { | ||||||
|         return try HTMLElem.toInterface(Union, e); |         return try HTMLElem.toInterface(Union, e); | ||||||
|     } |     } | ||||||
| @@ -27,6 +31,10 @@ pub const Element = struct { | |||||||
|         return try parser.elementLocalName(self); |         return try parser.elementLocalName(self); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  |     pub fn get_attributes(self: *parser.Element) !*parser.NamedNodeMap { | ||||||
|  |         return try parser.nodeGetAttributes(parser.elementToNode(self)); | ||||||
|  |     } | ||||||
|  |  | ||||||
|     pub fn _hasAttributes(self: *parser.Element) !bool { |     pub fn _hasAttributes(self: *parser.Element) !bool { | ||||||
|         return try parser.nodeHasAttributes(parser.elementToNode(self)); |         return try parser.nodeHasAttributes(parser.elementToNode(self)); | ||||||
|     } |     } | ||||||
| @@ -89,6 +97,8 @@ pub fn testExecFn( | |||||||
|     var attribute = [_]Case{ |     var attribute = [_]Case{ | ||||||
|         .{ .src = "let a = document.getElementById('content')", .ex = "undefined" }, |         .{ .src = "let a = document.getElementById('content')", .ex = "undefined" }, | ||||||
|         .{ .src = "a.hasAttributes()", .ex = "true" }, |         .{ .src = "a.hasAttributes()", .ex = "true" }, | ||||||
|  |         .{ .src = "a.attributes.length", .ex = "1" }, | ||||||
|  |  | ||||||
|         .{ .src = "a.getAttribute('id')", .ex = "content" }, |         .{ .src = "a.getAttribute('id')", .ex = "content" }, | ||||||
|  |  | ||||||
|         .{ .src = "a.hasAttribute('foo')", .ex = "false" }, |         .{ .src = "a.hasAttribute('foo')", .ex = "false" }, | ||||||
|   | |||||||
							
								
								
									
										80
									
								
								src/dom/namednodemap.zig
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										80
									
								
								src/dom/namednodemap.zig
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,80 @@ | |||||||
|  | const std = @import("std"); | ||||||
|  |  | ||||||
|  | const parser = @import("../netsurf.zig"); | ||||||
|  |  | ||||||
|  | const jsruntime = @import("jsruntime"); | ||||||
|  | const Case = jsruntime.test_utils.Case; | ||||||
|  | const checkCases = jsruntime.test_utils.checkCases; | ||||||
|  |  | ||||||
|  | const DOMException = @import("exceptions.zig").DOMException; | ||||||
|  |  | ||||||
|  | // WEB IDL https://dom.spec.whatwg.org/#namednodemap | ||||||
|  | pub const NamedNodeMap = struct { | ||||||
|  |     pub const Self = parser.NamedNodeMap; | ||||||
|  |     pub const mem_guarantied = true; | ||||||
|  |  | ||||||
|  |     pub const Exception = DOMException; | ||||||
|  |  | ||||||
|  |     // TODO implement LegacyUnenumerableNamedProperties. | ||||||
|  |     // https://webidl.spec.whatwg.org/#LegacyUnenumerableNamedProperties | ||||||
|  |  | ||||||
|  |     pub fn get_length(self: *parser.NamedNodeMap) !u32 { | ||||||
|  |         return try parser.namedNodeMapGetLength(self); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     pub fn _item(self: *parser.NamedNodeMap, index: u32) !?*parser.Attribute { | ||||||
|  |         return try parser.namedNodeMapItem(self, index); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     pub fn _getNamedItem(self: *parser.NamedNodeMap, qname: []const u8) !?*parser.Attribute { | ||||||
|  |         return try parser.namedNodeMapGetNamedItem(self, qname); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     pub fn _getNamedItemNS( | ||||||
|  |         self: *parser.NamedNodeMap, | ||||||
|  |         namespace: []const u8, | ||||||
|  |         localname: []const u8, | ||||||
|  |     ) !?*parser.Attribute { | ||||||
|  |         return try parser.namedNodeMapGetNamedItemNS(self, namespace, localname); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     pub fn _setNamedItem(self: *parser.NamedNodeMap, attr: *parser.Attribute) !?*parser.Attribute { | ||||||
|  |         return try parser.namedNodeMapSetNamedItem(self, attr); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     pub fn _setNamedItemNS(self: *parser.NamedNodeMap, attr: *parser.Attribute) !?*parser.Attribute { | ||||||
|  |         return try parser.namedNodeMapSetNamedItemNS(self, attr); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     pub fn _removeNamedItem(self: *parser.NamedNodeMap, qname: []const u8) !*parser.Attribute { | ||||||
|  |         return try parser.namedNodeMapRemoveNamedItem(self, qname); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     pub fn _removeNamedItemNS( | ||||||
|  |         self: *parser.NamedNodeMap, | ||||||
|  |         namespace: []const u8, | ||||||
|  |         localname: []const u8, | ||||||
|  |     ) !*parser.Attribute { | ||||||
|  |         return try parser.namedNodeMapRemoveNamedItemNS(self, namespace, localname); | ||||||
|  |     } | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | // Tests | ||||||
|  | // ----- | ||||||
|  |  | ||||||
|  | pub fn testExecFn( | ||||||
|  |     _: std.mem.Allocator, | ||||||
|  |     js_env: *jsruntime.Env, | ||||||
|  |     comptime _: []jsruntime.API, | ||||||
|  | ) !void { | ||||||
|  |     var setItem = [_]Case{ | ||||||
|  |         .{ .src = "let a = document.getElementById('content').attributes", .ex = "undefined" }, | ||||||
|  |         .{ .src = "a.length", .ex = "1" }, | ||||||
|  |         .{ .src = "a.item(0)", .ex = "[object Attr]" }, | ||||||
|  |         .{ .src = "a.item(1)", .ex = "null" }, | ||||||
|  |         .{ .src = "a.getNamedItem('id')", .ex = "[object Attr]" }, | ||||||
|  |         .{ .src = "a.getNamedItem('foo')", .ex = "null" }, | ||||||
|  |         .{ .src = "a.setNamedItem(a.getNamedItem('id'))", .ex = "[object Attr]" }, | ||||||
|  |     }; | ||||||
|  |     try checkCases(js_env, &setItem); | ||||||
|  | } | ||||||
| @@ -11,6 +11,7 @@ const parser = @import("../netsurf.zig"); | |||||||
| const EventTarget = @import("event_target.zig").EventTarget; | const EventTarget = @import("event_target.zig").EventTarget; | ||||||
|  |  | ||||||
| // DOM | // DOM | ||||||
|  | const Attr = @import("attribute.zig").Attr; | ||||||
| const CData = @import("character_data.zig"); | const CData = @import("character_data.zig"); | ||||||
| const Element = @import("element.zig").Element; | const Element = @import("element.zig").Element; | ||||||
| const Document = @import("document.zig").Document; | const Document = @import("document.zig").Document; | ||||||
| @@ -23,6 +24,7 @@ const HTMLElem = @import("../html/elements.zig"); | |||||||
|  |  | ||||||
| // Node interfaces | // Node interfaces | ||||||
| pub const Interfaces = generate.Tuple(.{ | pub const Interfaces = generate.Tuple(.{ | ||||||
|  |     Attr, | ||||||
|     CData.CharacterData, |     CData.CharacterData, | ||||||
|     CData.Interfaces, |     CData.Interfaces, | ||||||
|     Element, |     Element, | ||||||
| @@ -52,6 +54,7 @@ pub const Node = struct { | |||||||
|             .text => .{ .Text = @as(*parser.Text, @ptrCast(node)) }, |             .text => .{ .Text = @as(*parser.Text, @ptrCast(node)) }, | ||||||
|             .document => .{ .HTMLDocument = @as(*parser.DocumentHTML, @ptrCast(node)) }, |             .document => .{ .HTMLDocument = @as(*parser.DocumentHTML, @ptrCast(node)) }, | ||||||
|             .document_type => .{ .DocumentType = @as(*parser.DocumentType, @ptrCast(node)) }, |             .document_type => .{ .DocumentType = @as(*parser.DocumentType, @ptrCast(node)) }, | ||||||
|  |             .attribute => .{ .Attr = @as(*parser.Attribute, @ptrCast(node)) }, | ||||||
|             else => @panic("node type not handled"), // TODO |             else => @panic("node type not handled"), // TODO | ||||||
|         }; |         }; | ||||||
|     } |     } | ||||||
|   | |||||||
							
								
								
									
										132
									
								
								src/netsurf.zig
									
									
									
									
									
								
							
							
						
						
									
										132
									
								
								src/netsurf.zig
									
									
									
									
									
								
							| @@ -336,6 +336,131 @@ fn DOMErr(except: DOMException) DOMError!void { | |||||||
| // EventTarget | // EventTarget | ||||||
| pub const EventTarget = c.dom_event_target; | pub const EventTarget = c.dom_event_target; | ||||||
|  |  | ||||||
|  | // NamedNodeMap | ||||||
|  | pub const NamedNodeMap = c.dom_namednodemap; | ||||||
|  |  | ||||||
|  | pub fn namedNodeMapGetLength(nnm: *NamedNodeMap) !u32 { | ||||||
|  |     var ln: u32 = undefined; | ||||||
|  |     const err = c.dom_namednodemap_get_length(nnm, &ln); | ||||||
|  |     try DOMErr(err); | ||||||
|  |     return ln; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | pub fn namedNodeMapItem(nnm: *NamedNodeMap, index: u32) !?*Attribute { | ||||||
|  |     var n: [*c]c.dom_node = undefined; | ||||||
|  |     const err = c._dom_namednodemap_item(nnm, index, &n); | ||||||
|  |     try DOMErr(err); | ||||||
|  |  | ||||||
|  |     if (n == null) { | ||||||
|  |         return null; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     // cast [*c]c.dom_node into *Attribute | ||||||
|  |     return @as(*Attribute, @ptrCast(n)); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | pub fn namedNodeMapGetNamedItem(nnm: *NamedNodeMap, qname: []const u8) !?*Attribute { | ||||||
|  |     var n: [*c]c.dom_node = undefined; | ||||||
|  |     const err = c._dom_namednodemap_get_named_item(nnm, try stringFromData(qname), &n); | ||||||
|  |     try DOMErr(err); | ||||||
|  |  | ||||||
|  |     if (n == null) { | ||||||
|  |         return null; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     // cast [*c]c.dom_node into *Attribute | ||||||
|  |     return @as(*Attribute, @ptrCast(n)); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | pub fn namedNodeMapGetNamedItemNS( | ||||||
|  |     nnm: *NamedNodeMap, | ||||||
|  |     namespace: []const u8, | ||||||
|  |     localname: []const u8, | ||||||
|  | ) !?*Attribute { | ||||||
|  |     var n: [*c]c.dom_node = undefined; | ||||||
|  |     const err = c._dom_namednodemap_get_named_item_ns( | ||||||
|  |         nnm, | ||||||
|  |         try stringFromData(namespace), | ||||||
|  |         try stringFromData(localname), | ||||||
|  |         &n, | ||||||
|  |     ); | ||||||
|  |     try DOMErr(err); | ||||||
|  |  | ||||||
|  |     if (n == null) { | ||||||
|  |         return null; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     // cast [*c]c.dom_node into *Attribute | ||||||
|  |     return @as(*Attribute, @ptrCast(n)); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // Convert a parser pointer to a public dom_node pointer. | ||||||
|  | fn toDOMNode(comptime T: type, v: *T) [*c]c.dom_node { | ||||||
|  |     const v_aligned: *align(@alignOf([*c]c.dom_node)) T = @alignCast(v); | ||||||
|  |     return @ptrCast(v_aligned); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | pub fn namedNodeMapSetNamedItem(nnm: *NamedNodeMap, attr: *Attribute) !?*Attribute { | ||||||
|  |     var n: [*c]c.dom_node = undefined; | ||||||
|  |     const err = c._dom_namednodemap_set_named_item( | ||||||
|  |         nnm, | ||||||
|  |         toDOMNode(Attribute, attr), | ||||||
|  |         &n, | ||||||
|  |     ); | ||||||
|  |     try DOMErr(err); | ||||||
|  |  | ||||||
|  |     if (n == null) { | ||||||
|  |         return null; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     // cast [*c]c.dom_node into *Attribute | ||||||
|  |     return @as(*Attribute, @ptrCast(n)); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | pub fn namedNodeMapSetNamedItemNS(nnm: *NamedNodeMap, attr: *Attribute) !?*Attribute { | ||||||
|  |     var n: [*c]c.dom_node = undefined; | ||||||
|  |     const err = c._dom_namednodemap_set_named_item_ns( | ||||||
|  |         nnm, | ||||||
|  |         toDOMNode(Attribute, attr), | ||||||
|  |         &n, | ||||||
|  |     ); | ||||||
|  |     try DOMErr(err); | ||||||
|  |  | ||||||
|  |     if (n == null) { | ||||||
|  |         return null; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     // cast [*c]c.dom_node into *Attribute | ||||||
|  |     return @as(*Attribute, @ptrCast(n)); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | pub fn namedNodeMapRemoveNamedItem(nnm: *NamedNodeMap, qname: []const u8) !*Attribute { | ||||||
|  |     var n: [*c]c.dom_node = undefined; | ||||||
|  |     const err = c._dom_namednodemap_remove_named_item(nnm, try stringFromData(qname), &n); | ||||||
|  |     try DOMErr(err); | ||||||
|  |  | ||||||
|  |     // cast [*c]c.dom_node into *Attribute | ||||||
|  |     return @as(*Attribute, @ptrCast(n)); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | pub fn namedNodeMapRemoveNamedItemNS( | ||||||
|  |     nnm: *NamedNodeMap, | ||||||
|  |     namespace: []const u8, | ||||||
|  |     localname: []const u8, | ||||||
|  | ) !*Attribute { | ||||||
|  |     var n: [*c]c.dom_node = undefined; | ||||||
|  |     const err = c._dom_namednodemap_remove_named_item_ns( | ||||||
|  |         nnm, | ||||||
|  |         try stringFromData(namespace), | ||||||
|  |         try stringFromData(localname), | ||||||
|  |         &n, | ||||||
|  |     ); | ||||||
|  |     try DOMErr(err); | ||||||
|  |  | ||||||
|  |     // cast [*c]c.dom_node into *Attribute | ||||||
|  |     return @as(*Attribute, @ptrCast(n)); | ||||||
|  | } | ||||||
|  |  | ||||||
| // NodeType | // NodeType | ||||||
|  |  | ||||||
| pub const NodeType = enum(u4) { | pub const NodeType = enum(u4) { | ||||||
| @@ -637,6 +762,13 @@ pub fn nodeHasAttributes(node: *Node) !bool { | |||||||
|     return res; |     return res; | ||||||
| } | } | ||||||
|  |  | ||||||
|  | pub fn nodeGetAttributes(node: *Node) !*NamedNodeMap { | ||||||
|  |     var res: ?*NamedNodeMap = undefined; | ||||||
|  |     const err = nodeVtable(node).dom_node_get_attributes.?(node, &res); | ||||||
|  |     try DOMErr(err); | ||||||
|  |     return res.?; | ||||||
|  | } | ||||||
|  |  | ||||||
| // nodeToElement is an helper to convert a node to an element. | // nodeToElement is an helper to convert a node to an element. | ||||||
| pub inline fn nodeToElement(node: *Node) *Element { | pub inline fn nodeToElement(node: *Node) *Element { | ||||||
|     return @as(*Element, @ptrCast(node)); |     return @as(*Element, @ptrCast(node)); | ||||||
|   | |||||||
| @@ -15,6 +15,7 @@ const elementTestExecFn = @import("dom/element.zig").testExecFn; | |||||||
| const HTMLCollectionTestExecFn = @import("dom/html_collection.zig").testExecFn; | const HTMLCollectionTestExecFn = @import("dom/html_collection.zig").testExecFn; | ||||||
| const DOMExceptionTestExecFn = @import("dom/exceptions.zig").testExecFn; | const DOMExceptionTestExecFn = @import("dom/exceptions.zig").testExecFn; | ||||||
| const DOMImplementationExecFn = @import("dom/implementation.zig").testExecFn; | const DOMImplementationExecFn = @import("dom/implementation.zig").testExecFn; | ||||||
|  | const NamedNodeMapExecFn = @import("dom/namednodemap.zig").testExecFn; | ||||||
|  |  | ||||||
| var doc: *parser.DocumentHTML = undefined; | var doc: *parser.DocumentHTML = undefined; | ||||||
|  |  | ||||||
| @@ -61,6 +62,7 @@ fn testsAllExecFn( | |||||||
|         HTMLCollectionTestExecFn, |         HTMLCollectionTestExecFn, | ||||||
|         DOMExceptionTestExecFn, |         DOMExceptionTestExecFn, | ||||||
|         DOMImplementationExecFn, |         DOMImplementationExecFn, | ||||||
|  |         NamedNodeMapExecFn, | ||||||
|     }; |     }; | ||||||
|  |  | ||||||
|     inline for (testFns) |testFn| { |     inline for (testFns) |testFn| { | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user
	 Pierre Tachoire
					Pierre Tachoire