1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147
use crate::{Element, Node, Selector};
/// Used to insert or remove elements by `Selector`, and trim the dom.
pub trait Editable {
/// Remove all empty text nodes from `self`.
///
/// ```
/// use html_editor::parse;
/// use html_editor::prelude::*;
///
/// let html = r#"
/// <!DOCTYPE html>
/// <html>
/// <head></head>
/// <body></body>
/// </html>"#;
///
/// let html = parse(html).unwrap().trim().html();
/// assert_eq!(html, r#"<!DOCTYPE html><html><head></head><body></body></html>"#)
/// ```
fn trim(&mut self) -> &mut Self;
/// Insert `node` as the last child to all elements that matches the `selector`.
///
/// ```
/// use html_editor::{parse, Node, Selector};
/// use html_editor::prelude::*;
///
/// let html = r#"<div><span>Ok</span></div>"#;
///
/// let selector = Selector::from("div");
/// let html = parse(html)
/// .unwrap()
/// .insert_to(&selector, Node::new_element(
/// "span",
/// vec![],
/// vec![Node::Text("Cancel".to_string())]
/// ))
/// .html();
/// assert_eq!(html, r#"<div><span>Ok</span><span>Cancel</span></div>"#)
/// ```
fn insert_to(&mut self, selector: &Selector, target: Node) -> &mut Self;
/// Remove all elements that matches the `selector`.
///
/// ```
/// use html_editor::{parse, Selector};
/// use html_editor::prelude::*;
///
/// let html = r#"
/// <div>
/// <div class="recommend"></div>
/// <div class="results"></div>
/// <div class="ad"></div>
/// </div>"#;
///
/// let selector = Selector::from(".ad");
/// let html = parse(html).unwrap().remove_by(&selector).html();
/// assert_eq!(html, r#"
/// <div>
/// <div class="recommend"></div>
/// <div class="results"></div>
///
/// </div>"#)
/// ```
fn remove_by(&mut self, selector: &Selector) -> &mut Self;
}
impl Editable for Vec<Node> {
fn trim(&mut self) -> &mut Self {
self.retain(|node| {
match node {
Node::Doctype => true,
Node::Comment(_) => false,
Node::Text(text) => !text.trim().is_empty(),
Node::Element { .. } => true
}
});
for node in self.iter_mut() {
if let Node::Element { children, .. } = node {
children.trim();
}
}
self
}
fn insert_to(&mut self, selector: &Selector, target: Node) -> &mut Self {
for node in self.iter_mut() {
if let Node::Element {
name,
attrs,
children,
} = node
{
children.insert_to(selector, target.clone());
if selector.matches(&Element {
name: name.clone(),
attrs: attrs.clone(),
children: vec![],
}) {
children.push(target.clone());
}
}
}
self
}
fn remove_by(&mut self, selector: &Selector) -> &mut Self {
self.retain(|node| {
if let Node::Element { name, attrs, .. } = node {
let element = Element {
name: name.clone(),
attrs: attrs.clone(),
children: vec![],
};
return !selector.matches(&element);
}
true
});
for node in self.iter_mut() {
if let Node::Element { children, .. } = node {
children.remove_by(selector);
}
}
self
}
}
impl Editable for Element {
fn trim(&mut self) -> &mut Self {
self.children.trim();
self
}
fn insert_to(&mut self, selector: &Selector, target: Node) -> &mut Self {
self.children.insert_to(selector, target.clone());
if selector.matches(self) {
self.children.push(target);
}
self
}
fn remove_by(&mut self, selector: &Selector) -> &mut Self {
self.children.remove_by(selector);
self
}
}