mirror of
https://github.com/lightpanda-io/browser.git
synced 2025-12-16 08:18:59 +00:00
Element.setInnerText
This commit is contained in:
@@ -64,7 +64,7 @@ pub fn root(opts: RootOpts, writer: *std.Io.Writer, page: *Page) !void {
|
||||
|
||||
pub fn deep(node: *Node, opts: Opts, writer: *std.Io.Writer, page: *Page) error{WriteFailed}!void {
|
||||
switch (node._type) {
|
||||
.cdata => |cd| try writer.writeAll(cd.getData()),
|
||||
.cdata => |cd| try writeEscapedText(cd.getData(), writer),
|
||||
.element => |el| {
|
||||
if (shouldStripElement(el, opts)) {
|
||||
return;
|
||||
@@ -211,3 +211,35 @@ fn shouldStripElement(el: *const Node.Element, opts: Opts) bool {
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
fn writeEscapedText(text: []const u8, writer: *std.Io.Writer) !void {
|
||||
// Fast path: if no special characters, write directly
|
||||
const first_special = std.mem.indexOfAny(u8, text, "&<>") orelse {
|
||||
return writer.writeAll(text);
|
||||
};
|
||||
|
||||
try writer.writeAll(text[0..first_special]);
|
||||
try writer.writeAll(switch (text[first_special]) {
|
||||
'&' => "&",
|
||||
'<' => "<",
|
||||
'>' => ">",
|
||||
else => unreachable,
|
||||
});
|
||||
|
||||
// Process remaining text
|
||||
var remaining = text[first_special + 1 ..];
|
||||
while (std.mem.indexOfAny(u8, remaining, "&<>")) |offset| {
|
||||
try writer.writeAll(remaining[0..offset]);
|
||||
try writer.writeAll(switch (remaining[offset]) {
|
||||
'&' => "&",
|
||||
'<' => "<",
|
||||
'>' => ">",
|
||||
else => unreachable,
|
||||
});
|
||||
remaining = remaining[offset + 1 ..];
|
||||
}
|
||||
|
||||
if (remaining.len > 0) {
|
||||
try writer.writeAll(remaining);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -129,3 +129,36 @@
|
||||
d1.innerHTML = '<div><br><hr><img src="x.png"></div>';
|
||||
testing.expectEqual('<div><br><hr><img src="x.png"></div>', d1.innerHTML);
|
||||
</script>
|
||||
|
||||
<script id=innerText>
|
||||
// Get innerText from element
|
||||
d1.innerHTML = 'hello <em>world</em>';
|
||||
testing.expectEqual('hello world', d1.innerText);
|
||||
|
||||
// Set innerText - should replace children with text node
|
||||
d1.innerText = 'only text';
|
||||
testing.expectEqual('only text', d1.innerText);
|
||||
testing.expectEqual('only text', d1.innerHTML);
|
||||
|
||||
// innerText does NOT parse HTML (unlike innerHTML)
|
||||
d1.innerText = 'hello <div>world</div><b>!!</b>';
|
||||
testing.expectEqual('hello <div>world</div><b>!!</b>', d1.innerText);
|
||||
console.warn(d1.innerHTML);
|
||||
testing.expectEqual('hello <div>world</div><b>!!</b>', d1.innerHTML);
|
||||
|
||||
// Setting empty string clears children
|
||||
d1.innerText = '';
|
||||
testing.expectEqual('', d1.innerText);
|
||||
testing.expectEqual('', d1.innerHTML);
|
||||
|
||||
// innerText with nested elements
|
||||
d1.innerHTML = '<div>hello <span>beautiful</span> world</div>';
|
||||
testing.expectEqual('hello beautiful world', d1.innerText);
|
||||
|
||||
// Setting innerText removes all previous children including elements
|
||||
d1.innerHTML = '<div><p><a id=link2>hi</a></p></div>';
|
||||
testing.expectEqual('hi', d1.innerText);
|
||||
d1.innerText = 'new content';
|
||||
testing.expectEqual('new content', d1.innerText);
|
||||
testing.expectEqual(null, $('#link2'));
|
||||
</script>
|
||||
|
||||
@@ -229,6 +229,26 @@ pub fn getInnerText(self: *Element, writer: *std.Io.Writer) !void {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn setInnerText(self: *Element, text: []const u8, page: *Page) !void {
|
||||
const parent = self.asNode();
|
||||
|
||||
// Remove all existing children
|
||||
page.domChanged();
|
||||
var it = parent.childrenIterator();
|
||||
while (it.next()) |child| {
|
||||
page.removeNode(parent, child, .{ .will_be_reconnected = false });
|
||||
}
|
||||
|
||||
// Fast path: skip if text is empty
|
||||
if (text.len == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Create and append text node
|
||||
const text_node = try page.createTextNode(text);
|
||||
try page.appendNode(parent, text_node, .{ .child_already_connected = false });
|
||||
}
|
||||
|
||||
pub fn getOuterHTML(self: *Element, writer: *std.Io.Writer, page: *Page) !void {
|
||||
const dump = @import("../dump.zig");
|
||||
return dump.deep(self.asNode(), .{ .shadow = .skip }, writer, page);
|
||||
@@ -913,7 +933,7 @@ pub const JsApi = struct {
|
||||
}
|
||||
pub const namespaceURI = bridge.accessor(Element.getNamespaceURI, null, .{});
|
||||
|
||||
pub const innerText = bridge.accessor(_innerText, null, .{});
|
||||
pub const innerText = bridge.accessor(_innerText, Element.setInnerText, .{});
|
||||
fn _innerText(self: *Element, page: *const Page) ![]const u8 {
|
||||
var buf = std.Io.Writer.Allocating.init(page.call_arena);
|
||||
try self.getInnerText(&buf.writer);
|
||||
|
||||
Reference in New Issue
Block a user