add outerHTML setter

This commit is contained in:
Karl Seguin
2026-01-07 11:43:55 +08:00
parent 6d5a984413
commit 518e0aa07a
4 changed files with 54 additions and 7 deletions

View File

@@ -2172,9 +2172,9 @@ pub fn appendAllChildren(self: *Page, parent: *Node, target: *Node) !void {
}
}
pub fn insertAllChildrenBefore(self: *Page, fragment: *Node, target: *Node, ref_node: *Node) !void {
pub fn insertAllChildrenBefore(self: *Page, fragment: *Node, parent: *Node, ref_node: *Node) !void {
self.domChanged();
const dest_connected = target.isConnected();
const dest_connected = parent.isConnected();
var it = fragment.childrenIterator();
while (it.next()) |child| {
@@ -2182,7 +2182,7 @@ pub fn insertAllChildrenBefore(self: *Page, fragment: *Node, target: *Node, ref_
const child_was_connected = child.isConnected();
self.removeNode(fragment, child, .{ .will_be_reconnected = dest_connected });
try self.insertNodeRelative(
target,
parent,
child,
.{ .before = ref_node },
.{ .child_already_connected = child_was_connected },

View File

@@ -0,0 +1,21 @@
<!DOCTYPE html>
<script src="../testing.js"></script>
<div id=d1>hello <em>world</em></div>
<script id=outerHTML>
const d1 = $('#d1');
testing.expectEqual('<div id=\"d1\">hello <em>world</em></div>', d1.outerHTML);
d1.outerHTML = '<p id=p1>spice</p>';
// setting outerHTML doesn't update what d1 points to
testing.expectEqual('<div id="d1">hello <em>world</em></div>', d1.outerHTML);
// but it does update the document
testing.expectEqual(null, document.getElementById('d1'));
testing.expectEqual(true, document.getElementById('p1') != null);
testing.expectEqual('<p id="p1">spice</p>', document.getElementById('p1').outerHTML);
// testing.expectEqual(true, document.body.outerHTML.replaceAll(/\n/g, '').startsWith('<body><p id="p1">spice</p><script id="outerHTML">'));
// document.getElementById('p1').outerHTML = '';
// testing.expectEqual(null, document.getElementById('p1'));
// testing.expectEqual(true, document.body.outerHTML.replaceAll(/\n/g, '').startsWith('<body><script id="outerHTML">'));
</script>

View File

@@ -163,8 +163,10 @@ pub fn createAttributeNS(_: *const Document, namespace: []const u8, name: []cons
});
}
pub fn getElementById(self: *const Document, id_: ?[]const u8) ?*Element {
const id = id_ orelse return null;
pub fn getElementById(self: *const Document, id: []const u8) ?*Element {
if (id.len == 0) {
return null;
}
return self._elements_by_id.get(id);
}
@@ -685,7 +687,17 @@ pub const JsApi = struct {
pub const createEvent = bridge.function(Document.createEvent, .{ .dom_exception = true });
pub const createTreeWalker = bridge.function(Document.createTreeWalker, .{});
pub const createNodeIterator = bridge.function(Document.createNodeIterator, .{});
pub const getElementById = bridge.function(Document.getElementById, .{});
pub const getElementById = bridge.function(_getElementById, .{});
fn _getElementById(self: *const Document, value_: ?js.Value) !?*Element {
const value = value_ orelse return null;
if (value.isNull()) {
return self.getElementById("null");
}
if (value.isUndefined()) {
return self.getElementById("undefined");
}
return self.getElementById(try value.toZig([]const u8));
}
pub const querySelector = bridge.function(Document.querySelector, .{ .dom_exception = true });
pub const querySelectorAll = bridge.function(Document.querySelectorAll, .{ .dom_exception = true });
pub const getElementsByTagName = bridge.function(Document.getElementsByTagName, .{});

View File

@@ -317,6 +317,20 @@ pub fn getOuterHTML(self: *Element, writer: *std.Io.Writer, page: *Page) !void {
return dump.deep(self.asNode(), .{ .shadow = .skip }, writer, page);
}
pub fn setOuterHTML(self: *Element, html: []const u8, page: *Page) !void {
const node = self.asNode();
const parent = node._parent orelse return;
page.domChanged();
if (html.len > 0) {
const fragment = (try Node.DocumentFragment.init(page)).asNode();
try page.parseHtmlAsChildren(fragment, html);
try page.insertAllChildrenBefore(fragment, parent, node);
}
page.removeNode(parent, node, .{ .will_be_reconnected = false });
}
pub fn getInnerHTML(self: *Element, writer: *std.Io.Writer, page: *Page) !void {
const dump = @import("../dump.zig");
return dump.children(self.asNode(), .{ .shadow = .skip }, writer, page);
@@ -1220,7 +1234,7 @@ pub const JsApi = struct {
return buf.written();
}
pub const outerHTML = bridge.accessor(_outerHTML, null, .{});
pub const outerHTML = bridge.accessor(_outerHTML, Element.setOuterHTML, .{});
fn _outerHTML(self: *Element, page: *Page) ![]const u8 {
var buf = std.Io.Writer.Allocating.init(page.call_arena);
try self.getOuterHTML(&buf.writer, page);