diff --git a/src/browser/tests/cdata/text/text.html b/src/browser/tests/cdata/text/text.html new file mode 100644 index 00000000..9c5ac3d1 --- /dev/null +++ b/src/browser/tests/cdata/text/text.html @@ -0,0 +1,19 @@ + +OK + + + diff --git a/src/browser/tests/document/get_elements_by_tag_name.html b/src/browser/tests/document/get_elements_by_tag_name.html index 89ab1470..267d074e 100644 --- a/src/browser/tests/document/get_elements_by_tag_name.html +++ b/src/browser/tests/document/get_elements_by_tag_name.html @@ -23,6 +23,7 @@
Main
+ + diff --git a/src/browser/tests/element/get_elements_by_tag_name.html b/src/browser/tests/element/get_elements_by_tag_name.html index 208203de..3f23b2e7 100644 --- a/src/browser/tests/element/get_elements_by_tag_name.html +++ b/src/browser/tests/element/get_elements_by_tag_name.html @@ -41,6 +41,7 @@ { const container = $('#container'); + testing.expectEqual(5, container.getElementsByTagName('*').length); testing.expectEqual(0, container.getElementsByTagName('a').length); testing.expectEqual(0, container.getElementsByTagName('unknown').length); diff --git a/src/browser/tests/legacy/dom/element.html b/src/browser/tests/legacy/dom/element.html index a0f9757f..6a7155c8 100644 --- a/src/browser/tests/legacy/dom/element.html +++ b/src/browser/tests/legacy/dom/element.html @@ -71,7 +71,7 @@ testing.expectEqual('bar', content.getAttribute('foo')); testing.expectEqual(['id', 'dir', 'foo'], content.getAttributeNames()); - testing.expectError('Error: Invalid Character', () => { + testing.expectError('InvalidCharacterError: Invalid Character', () => { content.setAttribute('.foo', 'invalid') }); diff --git a/src/browser/tests/legacy/dom/html_collection.html b/src/browser/tests/legacy/dom/html_collection.html index 22590e58..a0fb0b19 100644 --- a/src/browser/tests/legacy/dom/html_collection.html +++ b/src/browser/tests/legacy/dom/html_collection.html @@ -20,7 +20,7 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -"puppeteer " -

Leto - - - Atreides

- diff --git a/src/browser/tests/legacy/dom/node_iterator.html b/src/browser/tests/legacy/dom/node_iterator.html deleted file mode 100644 index 6225dea4..00000000 --- a/src/browser/tests/legacy/dom/node_iterator.html +++ /dev/null @@ -1,62 +0,0 @@ - - - - - -
- OK -

- -

-

And

- -
- diff --git a/src/browser/webapi/Document.zig b/src/browser/webapi/Document.zig index bcd75b47..54aa7f94 100644 --- a/src/browser/webapi/Document.zig +++ b/src/browser/webapi/Document.zig @@ -163,7 +163,6 @@ pub fn getElementsByTagName(self: *Document, tag_name: []const u8, page: *Page) return error.InvalidTagName; } - // Handle wildcard '*' - return all elements if (std.mem.eql(u8, tag_name, "*")) { return .{ .all_elements = collections.NodeLive(.all_elements).init(self.asNode(), {}, page), diff --git a/src/browser/webapi/DocumentFragment.zig b/src/browser/webapi/DocumentFragment.zig index 5e94f3ab..24d8d5a5 100644 --- a/src/browser/webapi/DocumentFragment.zig +++ b/src/browser/webapi/DocumentFragment.zig @@ -199,6 +199,29 @@ pub fn cloneFragment(self: *DocumentFragment, deep: bool, page: *Page) !*Node { return fragment_node; } +pub fn isEqualNode(self: *DocumentFragment, other: *DocumentFragment) bool { + var self_iter = self.asNode().childrenIterator(); + var other_iter = other.asNode().childrenIterator(); + + while (true) { + const self_child = self_iter.next(); + const other_child = other_iter.next(); + + if ((self_child == null) != (other_child == null)) { + return false; + } + + if (self_child == null) { + // We've reached the end + return true; + } + + if (!self_child.?.isEqualNode(other_child.?)) { + return false; + } + } +} + pub const JsApi = struct { pub const bridge = js.Bridge(DocumentFragment); diff --git a/src/browser/webapi/DocumentType.zig b/src/browser/webapi/DocumentType.zig index 0bced680..ff2b4f11 100644 --- a/src/browser/webapi/DocumentType.zig +++ b/src/browser/webapi/DocumentType.zig @@ -53,6 +53,12 @@ pub fn className(_: *const DocumentType) []const u8 { return "[object DocumentType]"; } +pub fn isEqualNode(self: *const DocumentType, other: *const DocumentType) bool { + return std.mem.eql(u8, self._name, other._name) and + std.mem.eql(u8, self._public_id, other._public_id) and + std.mem.eql(u8, self._system_id, other._system_id); +} + pub const JsApi = struct { pub const bridge = js.Bridge(DocumentType); diff --git a/src/browser/webapi/Element.zig b/src/browser/webapi/Element.zig index ed926b90..d2a1b508 100644 --- a/src/browser/webapi/Element.zig +++ b/src/browser/webapi/Element.zig @@ -944,6 +944,7 @@ fn calculateSiblingPosition(node: *Node) f64 { const GetElementsByTagNameResult = union(enum) { tag: collections.NodeLive(.tag), tag_name: collections.NodeLive(.tag_name), + all_elements: collections.NodeLive(.all_elements), }; pub fn getElementsByTagName(self: *Element, tag_name: []const u8, page: *Page) !GetElementsByTagNameResult { if (tag_name.len > 256) { @@ -951,6 +952,12 @@ pub fn getElementsByTagName(self: *Element, tag_name: []const u8, page: *Page) ! return error.InvalidTagName; } + if (std.mem.eql(u8, tag_name, "*")) { + return .{ + .all_elements = collections.NodeLive(.all_elements).init(self.asNode(), {}, page), + }; + } + const lower = std.ascii.lowerString(&page.buf, tag_name); if (Tag.parseForMatch(lower)) |known| { // optimized for known tag names diff --git a/src/browser/webapi/Node.zig b/src/browser/webapi/Node.zig index 47ef3db9..64ca8f8e 100644 --- a/src/browser/webapi/Node.zig +++ b/src/browser/webapi/Node.zig @@ -331,7 +331,10 @@ pub fn isEqualNode(self: *Node, other: *Node) bool { .element => self.as(Element).isEqualNode(other.as(Element)), .attribute => self.as(Element.Attribute).isEqualNode(other.as(Element.Attribute)), .cdata => self.as(CData).isEqualNode(other.as(CData)), - else => { + .document_fragment => self.as(DocumentFragment).isEqualNode(other.as(DocumentFragment)), + .document_type => self.as(DocumentType).isEqualNode(other.as(DocumentType)), + .document => { + // Document comparison is complex and rarely used in practice log.warn(.browser, "not implemented", .{ .type = self._type, .feature = "Node.isEqualNode", diff --git a/src/browser/webapi/cdata/Text.zig b/src/browser/webapi/cdata/Text.zig index ad440348..8037db2e 100644 --- a/src/browser/webapi/cdata/Text.zig +++ b/src/browser/webapi/cdata/Text.zig @@ -16,19 +16,53 @@ // You should have received a copy of the GNU Affero General Public License // along with this program. If not, see . -const js = @import("../../js/js.zig"); - +const Page = @import("../../Page.zig"); const CData = @import("../CData.zig"); const Text = @This(); _proto: *CData, +pub fn init(str: ?[]const u8, page: *Page) !*Text { + const node = try page.createTextNode(str orelse ""); + return node.as(Text); +} + pub fn getWholeText(self: *Text) []const u8 { return self._proto._data; } +pub fn splitText(self: *Text, offset: usize, page: *Page) !*Text { + const data = self._proto._data; + + if (offset > data.len) { + return error.IndexSizeError; + } + + const new_data = data[offset..]; + const new_node = try page.createTextNode(new_data); + const new_text = new_node.as(Text); + + const old_data = data[0..offset]; + try self._proto.setData(old_data, page); + + // If this node has a parent, insert the new node right after this one + const node = self._proto.asNode(); + if (node.parentNode()) |parent| { + const next_sibling = node.nextSibling(); + _ = try parent.insertBefore(new_node, next_sibling, page); + } + + return new_text; +} + +const testing = @import("../../../testing.zig"); +test "WebApi: CData.Text" { + try testing.htmlRunner("cdata/text", .{}); +} + pub const JsApi = struct { + const js = @import("../../js/js.zig"); pub const bridge = js.Bridge(Text); pub const Meta = struct { @@ -37,5 +71,7 @@ pub const JsApi = struct { pub var class_id: bridge.ClassId = undefined; }; + pub const constructor = bridge.constructor(Text.init, .{}); pub const wholeText = bridge.accessor(Text.getWholeText, null, .{}); + pub const splitText = bridge.function(Text.splitText, .{ .dom_exception = true }); };