Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions src/browser/webapi/CData.zig
Original file line number Diff line number Diff line change
Expand Up @@ -135,6 +135,10 @@ pub fn getLength(self: *const CData) usize {
return self._data.len;
}

pub fn isEqualNode(self: *const CData, other: *const CData) bool {
return std.mem.eql(u8, self.getData(), other.getData());
}

pub fn appendData(self: *CData, data: []const u8, page: *Page) !void {
const new_data = try std.mem.concat(page.arena, u8, &.{ self._data, data });
try self.setData(new_data, page);
Expand Down Expand Up @@ -256,6 +260,7 @@ pub const JsApi = struct {
pub const data = bridge.accessor(CData.getData, CData.setData, .{});
pub const length = bridge.accessor(CData.getLength, null, .{});

pub const isEqualNode = bridge.function(CData.isEqualNode, .{});
pub const appendData = bridge.function(CData.appendData, .{});
pub const deleteData = bridge.function(CData.deleteData, .{ .dom_exception = true });
pub const insertData = bridge.function(CData.insertData, .{ .dom_exception = true });
Expand Down
52 changes: 52 additions & 0 deletions src/browser/webapi/Element.zig
Original file line number Diff line number Diff line change
Expand Up @@ -117,6 +117,57 @@ pub fn className(self: *const Element) []const u8 {
};
}

/// TODO: localName and prefix comparison.
pub fn isEqualNode(self: *Element, other: *Element) bool {
const self_tag = self.getTagNameDump();
const other_tag = other.getTagNameDump();
// Compare namespaces and tags.
const dirty = self._namespace != other._namespace or !std.mem.eql(u8, self_tag, other_tag);
if (dirty) {
return false;
}

// Compare attributes.
{
var self_iter = self.attributeIterator();
var other_iter = other.attributeIterator();
var self_count: usize = 0;
var other_count: usize = 0;
while (self_iter.next()) |a1| : (self_count += 1) {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Probably can't assume they're in order.

const a2 = other_iter.next() orelse return false;
other_count += 1;
if (a1._name.eql(a2._name) and a1._value.eql(a2._value)) {
continue;
}

return false;
}

// Make sure both have equal number of attribs.
if (self_count != other_count) {
return false;
}
}

// Compare children.
var self_iter = self.asNode().childrenIterator();
var other_iter = other.asNode().childrenIterator();
var self_count: usize = 0;
var other_count: usize = 0;
while (self_iter.next()) |self_node| : (self_count += 1) {
const other_node = other_iter.next() orelse return false;
other_count += 1;
if (self_node.isEqualNode(other_node)) {
continue;
}

return false;
}

// Make sure both have equal number of children.
return self_count == other_count;
}

pub fn getTagNameLower(self: *const Element) []const u8 {
switch (self._type) {
.html => |he| switch (he._type) {
Expand Down Expand Up @@ -1034,6 +1085,7 @@ pub const JsApi = struct {
pub const removeAttributeNode = bridge.function(Element.removeAttributeNode, .{ .dom_exception = true });
pub const shadowRoot = bridge.accessor(Element.getShadowRoot, null, .{});
pub const attachShadow = bridge.function(_attachShadow, .{ .dom_exception = true });
pub const isEqualNode = bridge.function(Element.isEqualNode, .{});

const ShadowRootInit = struct {
mode: []const u8,
Expand Down
22 changes: 22 additions & 0 deletions src/browser/webapi/Node.zig
Original file line number Diff line number Diff line change
Expand Up @@ -236,6 +236,27 @@ pub fn nodeType(self: *const Node) u8 {
};
}

pub fn isEqualNode(self: *Node, other: *Node) bool {
// Make sure types match.
if (self.nodeType() != other.nodeType()) {
return false;
}

// TODO: Compare `localName` and prefix.
return switch (self._type) {
.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 => {
log.warn(.browser, "not implemented", .{
.type = self._type,
.feature = "Node.isEqualNode",
});
return false;
},
};
}

pub fn isInShadowTree(self: *Node) bool {
var node = self._parent;
while (node) |n| {
Expand Down Expand Up @@ -760,6 +781,7 @@ pub const JsApi = struct {
pub const cloneNode = bridge.function(Node.cloneNode, .{ .dom_exception = true });
pub const compareDocumentPosition = bridge.function(Node.compareDocumentPosition, .{});
pub const getRootNode = bridge.function(Node.getRootNode, .{});
pub const isEqualNode = bridge.function(Node.isEqualNode, .{});

pub const toString = bridge.function(_toString, .{});
fn _toString(self: *const Node) []const u8 {
Expand Down
6 changes: 6 additions & 0 deletions src/browser/webapi/element/Attribute.zig
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,10 @@ pub fn getOwnerElement(self: *const Attribute) ?*Element {
return self._element;
}

pub fn isEqualNode(self: *const Attribute, other: *const Attribute) bool {
return std.mem.eql(u8, self.getName(), other.getName()) and std.mem.eql(u8, self.getValue(), other.getValue());
}

pub const JsApi = struct {
pub const bridge = js.Bridge(Attribute);

Expand All @@ -96,6 +100,8 @@ pub const JsApi = struct {
pub const value = bridge.accessor(Attribute.getValue, null, .{});
pub const namespaceURI = bridge.accessor(Attribute.getNamespaceURI, null, .{});
pub const ownerElement = bridge.accessor(Attribute.getOwnerElement, null, .{});

pub const isEqualNode = bridge.function(Attribute.isEqualNode, .{});
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You don't need these. I guess it's probably a bit more efficient (though I don't really know how v8 resolves this)..but it isn't typically how we do it. The implementation on Node which dispatches into the type is good enough.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I was after the little performance diff but you're right, using parent's method is more conventional.

};

// This is what an Element references. It isn't exposed to JavaScript. In
Expand Down
Loading