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 @@
-
-
-
-
-
-
-
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 });
};