diff --git a/src/browser/tests/document/create_element_ns.html b/src/browser/tests/document/create_element_ns.html index 73b3ee24..c99a5167 100644 --- a/src/browser/tests/document/create_element_ns.html +++ b/src/browser/tests/document/create_element_ns.html @@ -7,9 +7,11 @@ testing.expectEqual(true, htmlDiv1 instanceof HTMLDivElement); testing.expectEqual('http://www.w3.org/1999/xhtml', htmlDiv1.namespaceURI); + // Per spec, createElementNS does NOT lowercase — 'DIV' != 'div', so this + // creates an HTMLUnknownElement, not an HTMLDivElement. const htmlDiv2 = document.createElementNS('http://www.w3.org/1999/xhtml', 'DIV'); testing.expectEqual('DIV', htmlDiv2.tagName); - testing.expectEqual(true, htmlDiv2 instanceof HTMLDivElement); + testing.expectEqual(false, htmlDiv2 instanceof HTMLDivElement); testing.expectEqual('http://www.w3.org/1999/xhtml', htmlDiv2.namespaceURI); const svgRect = document.createElementNS('http://www.w3.org/2000/svg', 'RecT'); diff --git a/src/browser/webapi/Document.zig b/src/browser/webapi/Document.zig index 10725115..85f9c35f 100644 --- a/src/browser/webapi/Document.zig +++ b/src/browser/webapi/Document.zig @@ -157,8 +157,8 @@ pub fn createElement(self: *Document, name: []const u8, options_: ?CreateElement pub fn createElementNS(self: *Document, namespace: ?[]const u8, name: []const u8, page: *Page) !*Element { try validateElementName(name); const ns = Element.Namespace.parse(namespace); - const normalized_name = if (ns == .html) std.ascii.lowerString(&page.buf, name) else name; - const node = try page.createElementNS(ns, normalized_name, null); + // Per spec, createElementNS does NOT lowercase (unlike createElement). + const node = try page.createElementNS(ns, name, null); // Store original URI for unknown namespaces so lookupNamespaceURI can return it if (ns == .unknown) { diff --git a/src/browser/webapi/DocumentType.zig b/src/browser/webapi/DocumentType.zig index c70fc907..ce94192b 100644 --- a/src/browser/webapi/DocumentType.zig +++ b/src/browser/webapi/DocumentType.zig @@ -74,6 +74,12 @@ pub fn clone(self: *const DocumentType, page: *Page) !*DocumentType { return .init(self._name, self._public_id, self._system_id, page); } +pub fn remove(self: *DocumentType, page: *Page) !void { + const node = self.asNode(); + const parent = node.parentNode() orelse return; + _ = try parent.removeChild(node, page); +} + pub const JsApi = struct { pub const bridge = js.Bridge(DocumentType); @@ -87,4 +93,5 @@ pub const JsApi = struct { pub const name = bridge.accessor(DocumentType.getName, null, .{}); pub const publicId = bridge.accessor(DocumentType.getPublicId, null, .{}); pub const systemId = bridge.accessor(DocumentType.getSystemId, null, .{}); + pub const remove = bridge.function(DocumentType.remove, .{}); }; diff --git a/src/browser/webapi/MutationObserver.zig b/src/browser/webapi/MutationObserver.zig index 65c828e1..c84e4db0 100644 --- a/src/browser/webapi/MutationObserver.zig +++ b/src/browser/webapi/MutationObserver.zig @@ -387,9 +387,9 @@ pub const MutationRecord = struct { } pub fn getAttributeNamespace(self: *const MutationRecord) ?[]const u8 { - if (self._attribute_name != null) { - return "http://www.w3.org/1999/xhtml"; - } + _ = self; + // Non-namespaced attribute mutations return null. Full namespace tracking + // for setAttributeNS mutations is not yet implemented. return null; } diff --git a/src/browser/webapi/collections/node_live.zig b/src/browser/webapi/collections/node_live.zig index d341b484..5f6bd330 100644 --- a/src/browser/webapi/collections/node_live.zig +++ b/src/browser/webapi/collections/node_live.zig @@ -225,8 +225,13 @@ pub fn NodeLive(comptime mode: Mode) type { // If we're in `tag_name` mode, then the tag_name isn't // a known tag. It could be a custom element, heading, or // any generic element. Compare against the element's tag name. + // Per spec, getElementsByTagName is case-insensitive for HTML + // namespace elements, case-sensitive for others. const el = node.is(Element) orelse return false; const element_tag = el.getTagNameLower(); + if (el._namespace == .html) { + return std.ascii.eqlIgnoreCase(element_tag, self._filter.str()); + } return std.mem.eql(u8, element_tag, self._filter.str()); }, .tag_name_ns => {