mirror of
https://github.com/lightpanda-io/browser.git
synced 2025-12-15 15:58:57 +00:00
add insertAdjacentElement and insertAdjacentText
This commit is contained in:
@@ -375,7 +375,7 @@ pub fn insertAdjacentHTML(
|
||||
|
||||
const Parser = @import("../parser/Parser.zig");
|
||||
var parser = Parser.init(page.call_arena, doc_node, page);
|
||||
parser.parseFragment(html_or_xml);
|
||||
parser.parse(html_or_xml);
|
||||
// Check if there's parsing error.
|
||||
if (parser.err) |_| return error.Invalid;
|
||||
|
||||
@@ -390,52 +390,7 @@ pub fn insertAdjacentHTML(
|
||||
std.debug.assert(maybe_body_node != null);
|
||||
const body = maybe_body_node orelse return;
|
||||
|
||||
const self_node = self.asNode();
|
||||
// * `target_node` is `*Node` (where we actually insert),
|
||||
// * `prev_node` is `?*Node`.
|
||||
const target_node, const prev_node = blk: {
|
||||
// Prefer case-sensitive match.
|
||||
// "beforeend" was the most common case in my tests; we might adjust the order
|
||||
// depending on which ones websites prefer most.
|
||||
if (std.mem.eql(u8, position, "beforeend")) {
|
||||
break :blk .{ self_node, null };
|
||||
}
|
||||
|
||||
if (std.mem.eql(u8, position, "afterbegin")) {
|
||||
// Get the first child; null indicates there are no children.
|
||||
break :blk .{ self_node, self_node.firstChild() };
|
||||
}
|
||||
|
||||
if (std.mem.eql(u8, position, "beforebegin")) {
|
||||
// The node must have a parent node in order to use this variant.
|
||||
const parent_node = self_node.parentNode() orelse return error.NoModificationAllowed;
|
||||
// Parent cannot be Document.
|
||||
switch (parent_node._type) {
|
||||
.document, .document_fragment => return error.NoModificationAllowed,
|
||||
else => {},
|
||||
}
|
||||
|
||||
break :blk .{ parent_node, self_node };
|
||||
}
|
||||
|
||||
if (std.mem.eql(u8, position, "afterend")) {
|
||||
// The node must have a parent node in order to use this variant.
|
||||
const parent_node = self_node.parentNode() orelse return error.NoModificationAllowed;
|
||||
// Parent cannot be Document.
|
||||
switch (parent_node._type) {
|
||||
.document, .document_fragment => return error.NoModificationAllowed,
|
||||
else => {},
|
||||
}
|
||||
|
||||
// Get the next sibling or null; null indicates our node is the only one.
|
||||
break :blk .{ parent_node, self_node.nextSibling() };
|
||||
}
|
||||
|
||||
// Returned if:
|
||||
// * position is not one of the four listed values.
|
||||
// * The input is XML that is not well-formed.
|
||||
return error.Syntax;
|
||||
};
|
||||
const target_node, const prev_node = try self.asNode().findAdjacentNodes(position);
|
||||
|
||||
var iter = body.childrenIterator();
|
||||
while (iter.next()) |child_node| {
|
||||
@@ -443,6 +398,27 @@ pub fn insertAdjacentHTML(
|
||||
}
|
||||
}
|
||||
|
||||
pub fn insertAdjacentElement(
|
||||
self: *Element,
|
||||
position: []const u8,
|
||||
element: *Element,
|
||||
page: *Page,
|
||||
) !void {
|
||||
const target_node, const prev_node = try self.asNode().findAdjacentNodes(position);
|
||||
_ = try target_node.insertBefore(element.asNode(), prev_node, page);
|
||||
}
|
||||
|
||||
pub fn insertAdjacentText(
|
||||
self: *Element,
|
||||
where: []const u8,
|
||||
data: []const u8,
|
||||
page: *Page,
|
||||
) !void {
|
||||
const text_node = try page.createTextNode(data);
|
||||
const target_node, const prev_node = try self.asNode().findAdjacentNodes(where);
|
||||
_ = try target_node.insertBefore(text_node, prev_node, page);
|
||||
}
|
||||
|
||||
pub fn setAttributeNode(self: *Element, attr: *Attribute, page: *Page) !?*Attribute {
|
||||
if (attr._element) |el| {
|
||||
if (el == self) {
|
||||
@@ -1076,6 +1052,8 @@ pub const JsApi = struct {
|
||||
pub const shadowRoot = bridge.accessor(Element.getShadowRoot, null, .{});
|
||||
pub const attachShadow = bridge.function(_attachShadow, .{ .dom_exception = true });
|
||||
pub const insertAdjacentHTML = bridge.function(Element.insertAdjacentHTML, .{ .dom_exception = true });
|
||||
pub const insertAdjacentElement = bridge.function(Element.insertAdjacentElement, .{ .dom_exception = true });
|
||||
pub const insertAdjacentText = bridge.function(Element.insertAdjacentText, .{ .dom_exception = true });
|
||||
|
||||
const ShadowRootInit = struct {
|
||||
mode: []const u8,
|
||||
|
||||
@@ -115,6 +115,54 @@ pub fn is(self: *Node, comptime T: type) ?*T {
|
||||
return null;
|
||||
}
|
||||
|
||||
/// Given a position, returns target and previous nodes required for
|
||||
/// insertAdjacentHTML, insertAdjacentElement and insertAdjacentText.
|
||||
/// * `target_node` is `*Node` (where we actually insert),
|
||||
/// * `previous_node` is `?*Node`.
|
||||
pub fn findAdjacentNodes(self: *Node, position: []const u8) !struct { *Node, ?*Node } {
|
||||
// Prefer case-sensitive match.
|
||||
// "beforeend" was the most common case in my tests; we might adjust the order
|
||||
// depending on which ones websites prefer most.
|
||||
if (std.mem.eql(u8, position, "beforeend")) {
|
||||
return .{ self, null };
|
||||
}
|
||||
|
||||
if (std.mem.eql(u8, position, "afterbegin")) {
|
||||
// Get the first child; null indicates there are no children.
|
||||
return .{ self, self.firstChild() };
|
||||
}
|
||||
|
||||
if (std.mem.eql(u8, position, "beforebegin")) {
|
||||
// The node must have a parent node in order to use this variant.
|
||||
const parent_node = self.parentNode() orelse return error.NoModificationAllowed;
|
||||
// Parent cannot be Document.
|
||||
switch (parent_node._type) {
|
||||
.document, .document_fragment => return error.NoModificationAllowed,
|
||||
else => {},
|
||||
}
|
||||
|
||||
return .{ parent_node, self };
|
||||
}
|
||||
|
||||
if (std.mem.eql(u8, position, "afterend")) {
|
||||
// The node must have a parent node in order to use this variant.
|
||||
const parent_node = self.parentNode() orelse return error.NoModificationAllowed;
|
||||
// Parent cannot be Document.
|
||||
switch (parent_node._type) {
|
||||
.document, .document_fragment => return error.NoModificationAllowed,
|
||||
else => {},
|
||||
}
|
||||
|
||||
// Get the next sibling or null; null indicates our node is the only one.
|
||||
return .{ parent_node, self.nextSibling() };
|
||||
}
|
||||
|
||||
// Returned if:
|
||||
// * position is not one of the four listed values.
|
||||
// * The input is XML that is not well-formed.
|
||||
return error.Syntax;
|
||||
}
|
||||
|
||||
pub fn firstChild(self: *const Node) ?*Node {
|
||||
const children = self._children orelse return null;
|
||||
return children.first();
|
||||
|
||||
Reference in New Issue
Block a user