From 96db0620e1760997c2905a2c855534d4d0f23b6d Mon Sep 17 00:00:00 2001 From: Mykola Humanov Date: Thu, 14 Nov 2024 18:26:50 +0200 Subject: [PATCH] src/node/node_ref.rs: implemented `NodeRef::insert_after` --- CHANGELOG.md | 2 +- src/dom_tree.rs | 85 ++++++++++++++++++++++++------------ src/node/node_ref.rs | 18 ++++---- src/selection.rs | 5 +-- tests/node-manipulation.rs | 41 +++++++++++++++-- tests/selection-traversal.rs | 11 +++-- 6 files changed, 116 insertions(+), 46 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 8810c4f..cedfee1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -14,7 +14,7 @@ This allows querying into the `noscript` element. ## Added - Implemented `Ord` trait for `NodeId` - +- Implemented `NodeRef::insert_after` method, which allows to insert a node after the selected node. ## [0.9.1] - 2024-11-10 diff --git a/src/dom_tree.rs b/src/dom_tree.rs index e6d071f..80f33f7 100644 --- a/src/dom_tree.rs +++ b/src/dom_tree.rs @@ -411,7 +411,7 @@ impl Tree { } } - #[deprecated(since="0.9.1", note="please use `insert_before_of` instead")] + #[deprecated(since = "0.9.1", note = "please use `insert_before_of` instead")] /// Append a sibling node in the tree before the given node. pub fn append_prev_sibling_of(&self, id: &NodeId, new_sibling_id: &NodeId) { self.insert_before_of(id, new_sibling_id); @@ -448,6 +448,37 @@ impl Tree { } } + /// Append a sibling node in the tree after the given node. + pub fn insert_after_of(&self, id: &NodeId, new_sibling_id: &NodeId) { + self.remove_from_parent(new_sibling_id); + let mut nodes = self.nodes.borrow_mut(); + let node = match nodes.get_mut(id.value) { + Some(node) => node, + None => return, + }; + + let parent_id = node.parent; + let next_sibling_id = node.next_sibling; + + node.next_sibling = Some(*new_sibling_id); + + if let Some(new_sibling) = nodes.get_mut(new_sibling_id.value) { + new_sibling.parent = parent_id; + new_sibling.prev_sibling = Some(*id); + new_sibling.next_sibling = next_sibling_id; + }; + + if let Some(parent) = parent_id.and_then(|id| nodes.get_mut(id.value)) { + if parent.last_child == Some(*id) { + parent.last_child = Some(*new_sibling_id); + } + } + + if let Some(next_sibling) = next_sibling_id.and_then(|id| nodes.get_mut(id.value)) { + next_sibling.prev_sibling = Some(*new_sibling_id); + } + } + /// Changes the parent of children nodes of a node. pub fn reparent_children_of(&self, id: &NodeId, new_parent_id: Option) { let mut nodes = self.nodes.borrow_mut(); @@ -564,33 +595,33 @@ impl Tree { base_id } - - fn copy_tree_nodes(&self, source_tree: &Tree, id_map: &InnerHashMap) -> Vec { + fn copy_tree_nodes( + &self, + source_tree: &Tree, + id_map: &InnerHashMap, + ) -> Vec { let mut new_nodes: Vec = vec![]; let source_nodes = source_tree.nodes.borrow(); let tree_nodes_it = id_map.iter().flat_map(|(old_id, new_id)| { - source_nodes.get(*old_id).map(|sn| - TreeNode { - id: NodeId::new(*new_id), - parent: sn - .parent - .and_then(|old_id| id_map.get(&old_id.value).map(|id| NodeId::new(*id))), - prev_sibling: sn - .prev_sibling - .and_then(|old_id| id_map.get(&old_id.value).map(|id| NodeId::new(*id))), - next_sibling: sn - .next_sibling - .and_then(|old_id| id_map.get(&old_id.value).map(|id| NodeId::new(*id))), - first_child: sn - .first_child - .and_then(|old_id| id_map.get(&old_id.value).map(|id| NodeId::new(*id))), - last_child: sn - .last_child - .and_then(|old_id| id_map.get(&old_id.value).map(|id| NodeId::new(*id))), - data: sn.data.clone(), - } - ) - + source_nodes.get(*old_id).map(|sn| TreeNode { + id: NodeId::new(*new_id), + parent: sn + .parent + .and_then(|old_id| id_map.get(&old_id.value).map(|id| NodeId::new(*id))), + prev_sibling: sn + .prev_sibling + .and_then(|old_id| id_map.get(&old_id.value).map(|id| NodeId::new(*id))), + next_sibling: sn + .next_sibling + .and_then(|old_id| id_map.get(&old_id.value).map(|id| NodeId::new(*id))), + first_child: sn + .first_child + .and_then(|old_id| id_map.get(&old_id.value).map(|id| NodeId::new(*id))), + last_child: sn + .last_child + .and_then(|old_id| id_map.get(&old_id.value).map(|id| NodeId::new(*id))), + data: sn.data.clone(), + }) }); new_nodes.extend(tree_nodes_it); new_nodes.sort_by_key(|k| k.id.value); @@ -599,9 +630,9 @@ impl Tree { /// Copies nodes from another tree to the current tree and applies the given function /// to each copied node. The function is called with the ID of each copied node. - /// + /// /// # Arguments - /// + /// /// * `other_nodes` - slice of nodes to be copied /// * `f` - function to be applied to each copied node pub(crate) fn copy_nodes_with_fn(&self, other_nodes: &[NodeRef], f: F) diff --git a/src/node/node_ref.rs b/src/node/node_ref.rs index fd812b5..036bfca 100644 --- a/src/node/node_ref.rs +++ b/src/node/node_ref.rs @@ -156,19 +156,22 @@ impl<'a> NodeRef<'a> { /// Appends another node by id to the parent node of the selected node. /// Another node takes place of the selected node. #[inline] - #[deprecated(since="0.9.1", note="please use `insert_before` instead")] + #[deprecated(since = "0.9.1", note = "please use `insert_before` instead")] pub fn append_prev_sibling(&self, id_provider: P) { self.insert_before(id_provider); } - /// Appends another node by id to the parent node of the selected node. - /// Another node takes place of the selected node. + /// Inserts another node by id before the selected node. + /// Another node takes place of the selected node shifting it to right. #[inline] pub fn insert_before(&self, id_provider: P) { - self.tree - .insert_before_of(&self.id, id_provider.node_id()) + self.tree.insert_before_of(&self.id, id_provider.node_id()) } - + /// Inserts another node by id after the selected node. + /// Another node takes place of the next sibling of the selected node. + pub fn insert_after(&self, id_provider: P) { + self.tree.insert_after_of(&self.id, id_provider.node_id()) + } /// Appends another node by id to the selected node. #[inline] @@ -216,11 +219,10 @@ impl<'a> NodeRef<'a> { } } - /// Appends another node and it's siblings to the parent node /// of the selected node, shifting itself. #[inline] - #[deprecated(since="0.9.1", note="please use `insert_siblings_before` instead")] + #[deprecated(since = "0.9.1", note = "please use `insert_siblings_before` instead")] pub fn append_prev_siblings(&self, id_provider: P) { self.insert_siblings_before(id_provider); } diff --git a/src/selection.rs b/src/selection.rs index 4a5bb19..2433594 100644 --- a/src/selection.rs +++ b/src/selection.rs @@ -443,9 +443,8 @@ impl<'a> Selection<'a> { let sel_nodes = sel.nodes(); for node in self.nodes() { - node.tree.copy_nodes_with_fn(sel_nodes, |new_node_id| { - node.insert_before(&new_node_id) - }); + node.tree + .copy_nodes_with_fn(sel_nodes, |new_node_id| node.insert_before(&new_node_id)); } self.remove() diff --git a/tests/node-manipulation.rs b/tests/node-manipulation.rs index 0637b8c..49a6c3c 100644 --- a/tests/node-manipulation.rs +++ b/tests/node-manipulation.rs @@ -8,7 +8,6 @@ use wasm_bindgen_test::*; mod alloc; - #[cfg_attr(not(target_arch = "wasm32"), test)] #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] fn test_create_element() { @@ -218,8 +217,6 @@ fn test_change_parent_nodes_old() { assert!(doc.select("#outline > #origin > #inline").exists()); } - - #[cfg_attr(not(target_arch = "wasm32"), test)] #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] fn test_node_replace_with_by_node_id() { @@ -396,3 +393,41 @@ fn test_node_prepend_html() { .select("#origin > #first + #second + #third + #inline") .exists()); } + + +#[cfg_attr(not(target_arch = "wasm32"), test)] +#[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] +fn test_node_insert_before() { + let doc = Document::from(REPLACEMENT_CONTENTS); + + let sel = doc.select_single("#before-origin"); + let node = sel.nodes().first().unwrap(); + + let new_node = doc.tree.new_element("p"); + new_node.set_attr("id", "before-before-origin"); + + node.insert_before(&new_node); + + assert!(doc + .select("#before-before-origin + #before-origin + #origin + #after-origin") + .exists()); +} + + +#[cfg_attr(not(target_arch = "wasm32"), test)] +#[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] +fn test_node_insert_after() { + let doc = Document::from(REPLACEMENT_CONTENTS); + + let sel = doc.select_single("#before-origin"); + let node = sel.nodes().first().unwrap(); + + let new_node = doc.tree.new_element("p"); + new_node.set_attr("id", "also-before-origin"); + + node.insert_after(&new_node); + + assert!(doc + .select("#before-origin + #also-before-origin + #origin + #after-origin") + .exists()); +} \ No newline at end of file diff --git a/tests/selection-traversal.rs b/tests/selection-traversal.rs index b20a517..9520e48 100644 --- a/tests/selection-traversal.rs +++ b/tests/selection-traversal.rs @@ -433,7 +433,6 @@ fn test_selection_try_add() { assert_eq!(children_sel.unwrap().length(), 2); } - #[cfg_attr(not(target_arch = "wasm32"), test)] #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] fn test_select_inside_noscript() { @@ -446,8 +445,12 @@ fn test_select_inside_noscript() { - "#.into(); + "# + .into(); let sel = doc.select("noscript div"); - assert_eq!(sel.text(), "Please enable javascript to run this site".into()); -} \ No newline at end of file + assert_eq!( + sel.text(), + "Please enable javascript to run this site".into() + ); +}