diff --git a/html5ever/examples/arena.rs b/html5ever/examples/arena.rs
index 36854caf..08ec7328 100644
--- a/html5ever/examples/arena.rs
+++ b/html5ever/examples/arena.rs
@@ -55,6 +55,7 @@ pub struct Node<'arena> {
}
/// HTML node data which can be an element, a comment, a string, a DOCTYPE, etc...
+#[derive(Clone)]
pub enum NodeData<'arena> {
Document,
Doctype {
@@ -338,6 +339,21 @@ impl<'arena> TreeSink for Sink<'arena> {
new_parent.append(child)
}
}
+
+ fn clone_subtree(&self, node: &Self::Handle) -> Self::Handle {
+ // Allocate the new node in the arena using Clone
+ let cloned_node = self.arena.alloc(Node::new(node.data.clone()));
+
+ // Clone all children and append them
+ let mut child = node.first_child.get();
+ while let Some(current_child) = child {
+ let cloned_child = self.clone_subtree(¤t_child);
+ cloned_node.append(cloned_child);
+ child = current_child.next_sibling.get();
+ }
+
+ cloned_node
+ }
}
/// In this example an "arena" is created and filled with the DOM nodes.
@@ -352,5 +368,33 @@ fn main() {
io::stdin().read_to_end(&mut bytes).unwrap();
let arena = typed_arena::Arena::new();
- html5ever_parse_slice_into_arena(&bytes, &arena);
+ let dom = html5ever_parse_slice_into_arena(&bytes, &arena);
+
+ // Print the DOM structure
+ print_node(dom, 0);
+}
+
+fn print_node<'arena>(node: &Node<'arena>, depth: usize) {
+ let indent = " ".repeat(depth);
+
+ match &node.data {
+ NodeData::Document => println!("{}Document", indent),
+ NodeData::Doctype { name, .. } => println!("{}", indent, name),
+ NodeData::Text { contents } => {
+ let text = contents.borrow();
+ if !text.trim().is_empty() {
+ println!("{}\"{}\"", indent, text.trim());
+ }
+ },
+ NodeData::Comment { contents } => println!("{}", indent, contents),
+ NodeData::Element { name, .. } => println!("{}<{}>", indent, name.local),
+ NodeData::ProcessingInstruction { target, .. } => println!("{}{}>", indent, target),
+ }
+
+ // Print all children
+ let mut child = node.first_child.get();
+ while let Some(current_child) = child {
+ print_node(current_child, depth + 1);
+ child = current_child.next_sibling.get();
+ }
}
diff --git a/html5ever/examples/noop-tree-builder.rs b/html5ever/examples/noop-tree-builder.rs
index f0673462..fc04e2b3 100644
--- a/html5ever/examples/noop-tree-builder.rs
+++ b/html5ever/examples/noop-tree-builder.rs
@@ -113,6 +113,11 @@ impl TreeSink for Sink {
fn remove_from_parent(&self, _target: &usize) {}
fn reparent_children(&self, _node: &usize, _new_parent: &usize) {}
fn mark_script_already_started(&self, _node: &usize) {}
+
+ fn clone_subtree(&self, _node: &Self::Handle) -> Self::Handle {
+ // For this noop example, just return a new placeholder ID
+ self.get_id()
+ }
}
/// In this example we implement the TreeSink trait which takes each parsed elements and insert
diff --git a/html5ever/examples/print-tree-actions.rs b/html5ever/examples/print-tree-actions.rs
index dfa0aedd..3da79ea9 100644
--- a/html5ever/examples/print-tree-actions.rs
+++ b/html5ever/examples/print-tree-actions.rs
@@ -167,6 +167,12 @@ impl TreeSink for Sink {
fn pop(&self, elem: &usize) {
println!("Popped element {elem}");
}
+
+ fn clone_subtree(&self, node: &Self::Handle) -> Self::Handle {
+ println!("Clone subtree for node {node}");
+ // For this example, just return a new placeholder ID
+ self.get_id()
+ }
}
/// Same example as the "noop-tree-builder", but this time every function implemented in our
diff --git a/html5ever/src/tree_builder/mod.rs b/html5ever/src/tree_builder/mod.rs
index f0d89b92..6a29478d 100644
--- a/html5ever/src/tree_builder/mod.rs
+++ b/html5ever/src/tree_builder/mod.rs
@@ -118,6 +118,9 @@ pub struct TreeBuilder {
/// Form element pointer.
form_elem: RefCell)) => {
+ let option_in_stack = self
+ .open_elems
+ .borrow()
+ .iter()
+ .find(|elem| self.html_elem_named(elem, local_name!("option")))
+ .cloned();
+
+ self.process_end_tag_in_body(tag);
+
+ if let Some(option) = option_in_stack {
+ if !self
+ .open_elems
+ .borrow()
+ .iter()
+ .any(|elem| self.sink.same_node(elem, &option))
+ {
+ self.maybe_clone_option_into_selectedcontent(&option);
+ }
+ }
+
+ ProcessResult::Done
+ },
+
Token::Tag(tag!(
)) => {
if !self.in_scope_named(button_scope, local_name!("p")) {
self.sink.parse_error(Borrowed("No tag to close"));
@@ -753,18 +777,37 @@ where
)
},
- Token::Tag(
- tag @ tag!( |
|