use super::{BoxDynElement, IAttrValue, INodeType, InsertPosition, MaybeDoc, Texts};
use crate::utils::{get_class_list, retain_by_index, to_static_str};
use crate::{constants::ATTR_CLASS, error::Error as IError};
use crate::{
constants::DEF_NODES_LEN,
selector::{
rule::{MatchAllHandle, MatchOneHandle},
Combinator, QueryProcess, Selector, SelectorSegment,
},
};
use std::collections::HashSet;
use std::{
cmp::Ordering,
collections::VecDeque,
ops::{Bound, RangeBounds},
};
use std::{collections::HashMap, error::Error};
fn get_tree_indexs(ele: &BoxDynElement) -> VecDeque<usize> {
let mut indexs: VecDeque<usize> = VecDeque::with_capacity(DEF_NODES_LEN);
fn loop_handle(ele: &BoxDynElement, indexs: &mut VecDeque<usize>) {
indexs.push_front(ele.index());
if let Some(parent) = &ele.parent() {
loop_handle(parent, indexs);
}
}
loop_handle(ele, &mut indexs);
indexs
}
fn compare_indexs(a: &VecDeque<usize>, b: &VecDeque<usize>) -> Ordering {
let a_total = a.len();
let b_total = b.len();
let loop_total = if a_total > b_total { b_total } else { a_total };
for i in 0..loop_total {
let a_index = a[i];
let b_index = b[i];
match a_index.cmp(&b_index) {
Ordering::Equal => continue,
order => return order,
}
}
a_total.cmp(&b_total)
}
enum ElementRelation {
Ancestor,
Equal,
Descendant,
Feauture,
}
fn relation_of(a: &VecDeque<usize>, b: &VecDeque<usize>) -> ElementRelation {
let a_total = a.len();
let b_total = b.len();
let loop_total = if a_total > b_total { b_total } else { a_total };
let mut equal_num = 0;
for i in 0..loop_total {
let a_index = a[i];
let b_index = b[i];
match a_index.cmp(&b_index) {
Ordering::Equal => {
equal_num += 1;
continue;
}
_ => break,
}
}
let a_left = a_total - equal_num;
let b_left = b_total - equal_num;
match (a_left == 0, b_left == 0) {
(false, false) => ElementRelation::Feauture,
(false, true) => ElementRelation::Descendant,
(true, true) => ElementRelation::Equal,
(true, false) => ElementRelation::Ancestor,
}
}
#[derive(Debug, PartialEq, Eq)]
pub(crate) enum FilterType {
Filter,
Not,
Is,
IsAll,
}
#[derive(Default)]
pub struct Elements<'a> {
nodes: Vec<BoxDynElement<'a>>,
}
impl<'a> Elements<'a> {
pub(crate) fn trigger_method<F, T: Default>(&self, method: &str, selector: &str, handle: F) -> T
where
F: Fn(&mut Selector) -> T,
{
if !self.is_empty() {
const USE_LOOKUP: bool = false;
let s = Selector::from_str(selector, USE_LOOKUP);
if let Ok(mut s) = s {
return handle(&mut s);
}
self.trigger_method_throw_error(method, Box::new(s.unwrap_err()));
}
Default::default()
}
pub(crate) fn trigger_method_throw_error(&self, method: &str, error: Box<dyn Error>) {
if let Some(doc) = &self
.get(0)
.expect("Use index 0 when length > 0")
.owner_document()
{
doc.trigger_error(Box::new(IError::MethodOnInvalidSelector {
method: String::from(method),
error: error.to_string(),
}));
}
}
pub fn new() -> Self {
Default::default()
}
pub(crate) fn with_node(ele: &BoxDynElement) -> Self {
Elements {
nodes: vec![ele.cloned()],
}
}
pub fn with_nodes(nodes: Vec<BoxDynElement<'a>>) -> Self {
Elements { nodes }
}
pub fn with_capacity(size: usize) -> Self {
Elements {
nodes: Vec::with_capacity(size),
}
}
pub fn get(&self, index: usize) -> Option<&BoxDynElement<'a>> {
self.get_ref().get(index)
}
pub fn get_ref(&self) -> &Vec<BoxDynElement<'a>> {
&self.nodes
}
pub(crate) fn get_mut_ref(&mut self) -> &mut Vec<BoxDynElement<'a>> {
&mut self.nodes
}
pub(crate) fn push(&mut self, ele: BoxDynElement<'a>) {
self.get_mut_ref().push(ele);
}
}
impl<'a> Elements<'a> {
pub fn for_each<F>(&mut self, mut handle: F) -> &mut Self
where
F: FnMut(usize, &mut BoxDynElement) -> bool,
{
for (index, ele) in self.get_mut_ref().iter_mut().enumerate() {
if !handle(index, ele) {
break;
}
}
self
}
pub fn each<F>(&mut self, handle: F) -> &mut Self
where
F: FnMut(usize, &mut BoxDynElement) -> bool,
{
self.for_each(handle)
}
pub fn map<F, T: Sized>(&self, handle: F) -> Vec<T>
where
F: Fn(usize, &BoxDynElement) -> T,
{
let mut result: Vec<T> = Vec::with_capacity(self.length());
for (index, ele) in self.get_ref().iter().enumerate() {
result.push(handle(index, ele));
}
result
}
pub fn length(&self) -> usize {
self.nodes.len()
}
pub fn is_empty(&self) -> bool {
self.length() == 0
}
pub fn document(&self) -> MaybeDoc {
for ele in self.get_ref() {
if let Some(doc) = ele.owner_document() {
return Some(doc);
}
}
None
}
}
impl<'a> Elements<'a> {
fn unique_sibling(&self, asc: bool) -> Elements<'a> {
let total = self.length();
let mut parents_indexs: HashSet<VecDeque<usize>> = HashSet::with_capacity(total);
let mut uniques = Elements::with_capacity(total);
let mut prev_parent: Option<BoxDynElement> = None;
let mut has_root = false;
let mut handle = |ele: &BoxDynElement| {
if let Some(parent) = &ele.parent() {
if let Some(prev_parent) = &prev_parent {
if parent.is(prev_parent) {
return;
}
}
prev_parent = Some(parent.cloned());
let indexs = get_tree_indexs(parent);
if parents_indexs.get(&indexs).is_none() {
parents_indexs.insert(indexs);
uniques.push(ele.cloned());
}
} else if !has_root {
has_root = true;
uniques.push(ele.cloned());
}
};
if asc {
for ele in self.get_ref() {
handle(ele);
}
} else {
for ele in self.get_ref().iter().rev() {
handle(ele)
}
}
uniques
}
fn unique_sibling_first(&self) -> Elements<'a> {
self.unique_sibling(true)
}
fn unique_sibling_last(&self) -> Elements<'a> {
self.unique_sibling(false)
}
fn unique_all_siblings(&self) -> Vec<(BoxDynElement<'a>, bool)> {
let total = self.length();
let mut parents_indexs: HashMap<VecDeque<usize>, (usize, bool)> = HashMap::with_capacity(total);
let mut uniques: Vec<(BoxDynElement, bool)> = Vec::with_capacity(total);
let mut prev_parent: Option<BoxDynElement> = None;
let mut continued = false;
for ele in self.get_ref() {
if let Some(parent) = &ele.parent() {
if let Some(prev_parent) = &prev_parent {
if parent.is(prev_parent) {
if !continued {
if let Some(pair) = uniques.last_mut() {
*pair = (parent.cloned(), true);
}
continued = true;
}
continue;
}
}
continued = false;
prev_parent = Some(parent.cloned());
let indexs = get_tree_indexs(parent);
if let Some((index, setted)) = parents_indexs.get_mut(&indexs) {
if !*setted {
if let Some(pair) = uniques.get_mut(*index) {
*pair = (parent.cloned(), true);
}
*setted = true;
}
} else {
parents_indexs.insert(indexs, (uniques.len(), false));
uniques.push((ele.cloned(), false));
}
}
}
uniques
}
fn unique_parents(&self) -> Elements<'a> {
let mut ancestors: Vec<(VecDeque<usize>, &BoxDynElement)> = Vec::with_capacity(self.length());
for ele in self.get_ref() {
let ele_indexs = get_tree_indexs(ele);
let mut need_add = false;
if !ancestors.is_empty() {
let mut sub_indexs: Vec<usize> = Vec::new();
for (index, (orig_ele_indexs, _)) in ancestors.iter().enumerate() {
match relation_of(&ele_indexs, orig_ele_indexs) {
ElementRelation::Feauture => {
need_add = true;
break;
}
ElementRelation::Ancestor => {
sub_indexs.push(index);
need_add = true;
}
_ => break,
}
}
if !sub_indexs.is_empty() {
retain_by_index(&mut ancestors, &sub_indexs);
}
} else {
need_add = true;
}
if need_add {
ancestors.push((ele_indexs, ele));
}
}
let mut result = Elements::with_capacity(ancestors.len());
for (_, ele) in ancestors {
result.push(ele.cloned());
}
result
}
fn sort(&mut self) {
self.get_mut_ref().sort_by(|a, b| {
let a_index = get_tree_indexs(a);
let b_index = get_tree_indexs(b);
compare_indexs(&a_index, &b_index)
});
}
fn unique(&mut self) {
self.get_mut_ref().dedup_by(|a, b| a.is(b));
}
fn sort_and_unique(&mut self) {
self.sort();
self.unique();
}
}
impl<'a> Elements<'a> {
fn select_with_comb(&self, method: &str, selector: &str, comb: Combinator) -> Elements<'a> {
if selector.is_empty() {
let segment = Selector::make_comb_all(comb);
let selector = Selector::from_segment(segment);
return self.find_selector(&selector);
}
self.trigger_method(method, selector, |selector| {
selector.head_combinator(comb);
self.find_selector(&selector)
})
}
fn select_with_comb_until(
&self,
method: &str,
selector: &str,
filter: &str,
contains: bool,
comb: Combinator,
) -> Elements<'a> {
let selector = selector.parse::<Selector>();
if let Ok(selector) = &selector {
let segment = Selector::make_comb_all(comb);
let next_selector = Selector::from_segment(segment);
let mut result = Elements::with_capacity(DEF_NODES_LEN);
let (next_ok, filter) = if !filter.is_empty() {
let filter = filter.parse::<Selector>();
if let Ok(filter) = filter {
(true, Some(filter))
} else {
self.trigger_method_throw_error(method, Box::new(filter.unwrap_err()));
(false, None)
}
} else {
(true, None)
};
if next_ok {
for ele in self.get_ref() {
let mut cur_eles = Elements::with_node(ele);
loop {
cur_eles = cur_eles.find_selector(&next_selector);
if !cur_eles.is_empty() {
let meet_until = cur_eles.filter_type_handle(&selector, &FilterType::Is).1;
if meet_until && !contains {
break;
}
let should_add = if let Some(filter) = &filter {
cur_eles.filter_type_handle(filter, &FilterType::Is).1
} else {
true
};
if should_add {
result.push(
cur_eles
.get(0)
.expect("Elements get 0 must have when length > 0")
.cloned(),
);
}
if meet_until {
break;
}
} else {
break;
}
}
}
return result;
}
} else {
self.trigger_method_throw_error(method, Box::new(selector.unwrap_err()));
}
Elements::new()
}
pub fn prev(&self, selector: &str) -> Elements<'a> {
self.select_with_comb("prev", selector, Combinator::Prev)
}
pub fn prev_all(&self, selector: &str) -> Elements<'a> {
let uniques = self.unique_sibling_last();
uniques.select_with_comb("prev_all", selector, Combinator::PrevAll)
}
pub fn prev_until(&self, selector: &str, filter: &str, contains: bool) -> Elements<'a> {
let uniques = self.unique_sibling_last();
uniques.select_with_comb_until("prev_until", selector, filter, contains, Combinator::Prev)
}
pub fn next(&self, selector: &str) -> Elements<'a> {
self.select_with_comb("next", selector, Combinator::Next)
}
pub fn next_all(&self, selector: &str) -> Elements<'a> {
let uniques = self.unique_sibling_first();
uniques.select_with_comb("next_all", selector, Combinator::NextAll)
}
pub fn next_until(&self, selector: &str, filter: &str, contains: bool) -> Elements<'a> {
let uniques = self.unique_sibling_first();
uniques.select_with_comb_until("next_until", selector, filter, contains, Combinator::Next)
}
pub fn siblings(&self, selector: &str) -> Elements<'a> {
let uniques = self.unique_all_siblings();
let mut siblings_selector: Selector;
let siblings_comb = Combinator::Siblings;
let mut child_selector: Selector;
let child_comb = Combinator::Children;
let selector = selector.trim();
if selector.is_empty() {
siblings_selector = Selector::from_segment(Selector::make_comb_all(siblings_comb));
child_selector = Selector::from_segment(Selector::make_comb_all(child_comb));
} else {
let sib_selector = selector.parse::<Selector>();
if let Ok(sib_selector) = sib_selector {
child_selector = selector
.parse::<Selector>()
.expect("The selector has detected");
child_selector.head_combinator(child_comb);
siblings_selector = sib_selector;
siblings_selector.head_combinator(siblings_comb);
} else {
self.trigger_method_throw_error(
"siblings",
Box::new(IError::InvalidTraitMethodCall {
method: "siblings".to_string(),
message: format!(
"Invalid selector:{}",
sib_selector.err().expect("Selector parse error")
),
}),
);
return Elements::new();
}
}
let mut result = Elements::with_capacity(DEF_NODES_LEN);
for (ele, is_parent) in &uniques {
let eles = Elements::with_node(ele);
let finded = if *is_parent {
eles.find_selector(&child_selector)
} else {
eles.find_selector(&siblings_selector)
};
result.get_mut_ref().extend(finded);
}
result.sort();
result
}
pub fn children(&self, selector: &str) -> Elements<'a> {
self.select_with_comb("children", selector, Combinator::Children)
}
pub fn parent(&self, selector: &str) -> Elements<'a> {
let uniques = self.unique_sibling_first();
uniques.select_with_comb("parent", selector, Combinator::Parent)
}
pub fn parents(&self, selector: &str) -> Elements<'a> {
let uniques = self.unique_sibling_first();
let mut result = uniques.select_with_comb("parents", selector, Combinator::ParentAll);
result.sort_and_unique();
result
}
pub fn parents_until(&self, selector: &str, filter: &str, contains: bool) -> Elements<'a> {
let uniques = self.unique_sibling_first();
let mut result = uniques.select_with_comb_until(
"parents_until",
selector,
filter,
contains,
Combinator::Parent,
);
result.sort_and_unique();
result
}
pub fn closest(&self, selector: &str) -> Elements<'a> {
if selector.is_empty() {
return Elements::new();
}
const METHOD: &str = "closest";
let selector = selector.parse::<Selector>();
if let Ok(selector) = selector {
let total = self.length();
let mut result = Elements::with_capacity(total);
let mut propagations = Elements::with_capacity(total);
for ele in self.get_ref() {
let mut cur_eles = Elements::with_node(ele);
if cur_eles.filter_type_handle(&selector, &FilterType::Is).1 {
result.get_mut_ref().push(cur_eles.get_mut_ref().remove(0));
} else {
propagations
.get_mut_ref()
.push(cur_eles.get_mut_ref().remove(0));
}
}
if !propagations.is_empty() {
let uniques = propagations.unique_sibling_first();
for ele in uniques.get_ref() {
let mut cur_eles = Elements::with_node(ele);
loop {
if cur_eles.filter_type_handle(&selector, &FilterType::Is).1 {
result.get_mut_ref().push(cur_eles.get_mut_ref().remove(0));
break;
}
if let Some(parent) = &cur_eles
.get(0)
.expect("Elements must have one node")
.parent()
{
cur_eles = Elements::with_node(parent);
} else {
break;
}
}
}
result.sort_and_unique();
}
result
} else {
self.trigger_method_throw_error(METHOD, Box::new(selector.unwrap_err()));
Elements::new()
}
}
fn find_selector(&self, selector: &Selector) -> Elements<'a> {
let mut result = Elements::with_capacity(DEF_NODES_LEN);
if !self.is_empty() {
for p in &selector.process {
let QueryProcess { should_in, query } = p;
let first_query = &query[0];
let mut group: Option<Elements> = None;
let mut start_rule_index: usize = 0;
let mut is_empty = false;
if let Some(lookup) = should_in {
let mut cur_group = Elements::with_capacity(DEF_NODES_LEN);
let finded = Elements::select(self, first_query, Some(&Combinator::ChildrenAll));
if !finded.is_empty() {
let tops = Elements::select(self, &lookup[0], None);
if !tops.is_empty() {
start_rule_index = 1;
let mut prev_ele: Option<&BoxDynElement> = None;
let mut is_find = false;
let first_comb = &first_query[0].1;
for ele in finded.get_ref() {
if prev_ele.is_some()
&& Elements::is_sibling(ele, prev_ele.expect("Has test is_some"))
{
match first_comb {
Combinator::Next => {
if is_find {
continue;
}
}
Combinator::NextAll => {
if is_find {
cur_group.push(ele.cloned());
continue;
}
}
_ => {
if is_find {
cur_group.push(ele.cloned());
}
continue;
}
};
}
if tops.has_ele(ele, &first_comb, Some(&lookup[1..])) {
cur_group.push(ele.cloned());
is_find = true;
} else {
is_find = false;
}
prev_ele = Some(ele);
}
}
}
is_empty = cur_group.is_empty();
group = Some(cur_group);
}
if !is_empty {
let query = &query[start_rule_index..];
if !query.is_empty() {
let mut is_empty = false;
let mut group = Elements::select(group.as_ref().unwrap_or(self), &query[0], None);
for rules in &query[1..] {
group = Elements::select(&group, rules, None);
if group.is_empty() {
is_empty = true;
break;
}
}
if !is_empty {
result = result.add(group);
}
} else {
let group = group.unwrap_or_else(|| self.cloned());
if !group.is_empty() {
result = result.add(group);
}
}
}
}
}
result
}
pub fn find(&self, selector: &str) -> Elements<'a> {
self.trigger_method("find", selector, |selector| self.find_selector(selector))
}
fn select_by_rule(
elements: &Elements<'a>,
rule_item: &SelectorSegment,
comb: Option<&Combinator>,
) -> Elements<'a> {
let cur_comb = comb.unwrap_or(&rule_item.1);
let (matcher, ..) = rule_item;
let mut result = Elements::with_capacity(DEF_NODES_LEN);
use Combinator::*;
match cur_comb {
ChildrenAll => {
let uniques = elements.unique_parents();
if let Some(handle) = &matcher.one_handle {
let exec = |ele: &BoxDynElement, result: &mut Elements| {
fn loop_handle(ele: &BoxDynElement, result: &mut Elements, handle: &MatchOneHandle) {
let child_nodes = ele.child_nodes();
for node in child_nodes {
if matches!(node.node_type(), INodeType::Element) {
let child_ele = node
.typed()
.into_element()
.expect("Call typed for element node");
let has_sub_child = child_ele.child_nodes_length() > 0;
if has_sub_child {
if handle(&child_ele, None) {
result.get_mut_ref().push(child_ele.cloned());
}
loop_handle(&child_ele, result, handle);
} else {
if handle(&child_ele, None) {
result.get_mut_ref().push(child_ele);
}
}
}
}
}
loop_handle(ele, result, handle)
};
for ele in uniques.get_ref() {
exec(ele, &mut result);
}
} else {
let handle = matcher.get_all_handle();
let exec = |ele: &BoxDynElement, result: &mut Elements| {
fn loop_handle(ele: &BoxDynElement, result: &mut Elements, handle: &MatchAllHandle) {
let childs = ele.children();
if !childs.is_empty() {
let matched_childs = handle(&childs, None);
let matched_childs = matched_childs.get_ref();
let total_matched = matched_childs.len();
let mut cmp_index = 0;
for child in childs.get_ref() {
if cmp_index < total_matched {
let cmp_child = &matched_childs[cmp_index];
if child.is(&cmp_child) {
cmp_index += 1;
result.get_mut_ref().push(child.cloned());
}
}
loop_handle(child, result, handle);
}
}
}
loop_handle(ele, result, handle)
};
for ele in uniques.get_ref() {
exec(ele, &mut result);
}
};
}
Children => {
if let Some(handle) = &matcher.one_handle {
for ele in elements.get_ref() {
let child_nodes = ele.child_nodes();
for node in child_nodes {
if matches!(node.node_type(), INodeType::Element) {
let child_ele = node
.typed()
.into_element()
.expect("Call typed for element node");
if handle(&child_ele, None) {
result.get_mut_ref().push(child_ele);
}
}
}
}
} else {
let handle = matcher.get_all_handle();
for ele in elements.get_ref() {
let childs = ele.children();
let match_childs = handle(&childs, None);
if !match_childs.is_empty() {
result.get_mut_ref().extend(match_childs);
}
}
}
}
Parent => {
let uniques = elements.unique_sibling_first();
if let Some(handle) = &matcher.one_handle {
for ele in uniques.get_ref() {
if let Some(parent) = ele.parent() {
if handle(&parent, None) {
result.get_mut_ref().push(parent);
}
}
}
} else {
let handle = matcher.get_all_handle();
let mut parents = Elements::with_capacity(uniques.length());
for ele in uniques.get_ref() {
if let Some(parent) = ele.parent() {
parents.push(parent);
}
}
let matched_parents = handle(&parents, None);
if !matched_parents.is_empty() {
result.get_mut_ref().extend(matched_parents);
}
}
}
ParentAll => {
if let Some(handle) = &matcher.one_handle {
let exec = |ele: &BoxDynElement, result: &mut Elements| {
fn loop_handle(ele: &BoxDynElement, result: &mut Elements, handle: &MatchOneHandle) {
if let Some(parent) = ele.parent() {
loop_handle(&parent, result, handle);
if handle(&parent, None) {
result.get_mut_ref().push(parent);
}
}
}
loop_handle(ele, result, handle);
};
for ele in elements.get_ref() {
exec(ele, &mut result);
}
result.sort_and_unique();
} else {
fn loop_handle(ele: &BoxDynElement, parents: &mut Elements) {
if let Some(parent) = ele.parent() {
loop_handle(&parent, parents);
parents.push(parent);
}
}
let mut all_parents = Elements::with_capacity(10);
for ele in elements.get_ref() {
loop_handle(ele, &mut all_parents);
}
all_parents.sort_and_unique();
let handle = matcher.get_all_handle();
let matched_parents = handle(&all_parents, None);
if !matched_parents.is_empty() {
result.get_mut_ref().extend(matched_parents);
}
}
}
NextAll => {
let uniques = elements.unique_sibling_first();
for ele in uniques.get_ref() {
let nexts = ele.next_element_siblings();
let matched_nexts = matcher.apply(&nexts, None);
if !matched_nexts.is_empty() {
result.get_mut_ref().extend(matched_nexts);
}
}
}
Next => {
let mut nexts = Elements::with_capacity(elements.length());
if let Some(handle) = &matcher.one_handle {
for ele in elements.get_ref() {
if let Some(next) = ele.next_element_sibling() {
if handle(&next, None) {
nexts.push(next);
}
}
}
result = nexts;
} else {
for ele in elements.get_ref() {
if let Some(next) = ele.next_element_sibling() {
nexts.push(next);
}
}
result = matcher.apply(&nexts, None);
}
}
PrevAll => {
let uniques = elements.unique_sibling_last();
for ele in uniques.get_ref() {
let nexts = ele.previous_element_siblings();
result.get_mut_ref().extend(matcher.apply(&nexts, None));
}
}
Prev => {
let mut prevs = Elements::with_capacity(elements.length());
if let Some(handle) = &matcher.one_handle {
for ele in elements.get_ref() {
if let Some(prev) = ele.previous_element_sibling() {
if handle(&prev, None) {
prevs.push(prev);
}
}
}
result = prevs;
} else {
for ele in elements.get_ref() {
if let Some(prev) = ele.previous_element_sibling() {
prevs.push(prev);
}
}
result = matcher.apply(&prevs, None);
}
}
Siblings => {
if elements.length() > 1000 {
let uniques = elements.unique_all_siblings();
for (ele, is_parent) in uniques {
let eles = if !is_parent {
ele.siblings()
} else {
ele.children()
};
result.get_mut_ref().extend(matcher.apply(&eles, None));
}
} else {
for ele in elements.get_ref() {
let siblings = ele.siblings();
result.get_mut_ref().extend(matcher.apply(&siblings, None));
}
result.sort_and_unique();
}
}
Chain => {
result = matcher.apply(&elements, None);
}
};
result
}
fn select(
elements: &Elements<'a>,
rules: &[SelectorSegment],
comb: Option<&Combinator>,
) -> Elements<'a> {
let first_rule = &rules[0];
let comb = comb.unwrap_or(&first_rule.1);
let mut elements = if first_rule.0.in_cache && matches!(comb, Combinator::ChildrenAll) {
let (matcher, ..) = first_rule;
let cached = matcher.apply(&elements, Some(true));
let count = cached.length();
if count > 0 {
let mut result = Elements::with_capacity(count);
for ele in cached.get_ref() {
if elements.has_ele(ele, comb, None) {
result.push(ele.cloned());
}
}
result.sort_and_unique();
result
} else {
Elements::new()
}
} else {
Elements::select_by_rule(&elements, first_rule, Some(comb))
};
if !elements.is_empty() && rules.len() > 1 {
for rule in &rules[1..] {
elements = Elements::select_by_rule(&elements, rule, None);
if elements.is_empty() {
break;
}
}
}
elements
}
pub fn cloned(&self) -> Elements<'a> {
let mut result = Elements::with_capacity(self.length());
for ele in &self.nodes {
result.push(ele.cloned());
}
result
}
pub(crate) fn has_ele(
&self,
ele: &BoxDynElement,
comb: &Combinator,
lookup: Option<&[Vec<SelectorSegment>]>,
) -> bool {
let mut elements = Elements::with_node(ele);
let mut lookup_comb = comb.reverse();
if let Some(lookup) = lookup {
for rules in lookup.iter().rev() {
let finded = Elements::select(&elements, rules, Some(&lookup_comb));
if finded.is_empty() {
return false;
}
lookup_comb = rules[0].1.reverse();
elements = finded;
}
}
use Combinator::*;
match lookup_comb {
Parent => {
for ele in elements.get_ref() {
if let Some(parent) = &ele.parent() {
if self.includes(&parent) {
return true;
}
}
}
}
ParentAll => {
for ele in elements.get_ref() {
if let Some(parent) = &ele.parent() {
if self.includes(&parent) {
return true;
}
if let Some(ancestor) = &parent.parent() {
if self.includes(&ancestor) {
return true;
}
if self.has_ele(&ancestor, comb, None) {
return true;
}
}
}
}
}
Prev => {
for ele in elements.get_ref() {
if let Some(prev) = &ele.previous_element_sibling() {
if self.includes(&prev) {
return true;
}
}
}
}
PrevAll => {
for ele in elements.get_ref() {
let prevs = ele.previous_element_siblings();
for prev in prevs.get_ref() {
if self.includes(prev) {
return true;
}
}
}
}
Chain => {
for ele in elements.get_ref() {
if self.includes(ele) {
return true;
}
}
}
_ => panic!("Unsupported lookup combinator:{:?}", comb),
};
false
}
pub(crate) fn filter_type_handle(
&self,
selector: &Selector,
filter_type: &FilterType,
) -> (Elements<'a>, bool) {
let eles = self.get_ref();
let total = eles.len();
let mut result = Elements::with_capacity(total);
let mut all_matched = false;
let chain_comb = Combinator::Chain;
let mut root: Option<Elements> = None;
for process in selector.process.iter() {
let QueryProcess { query, .. } = process;
let query_num = query.len();
let mut filtered = Elements::new();
if query_num > 0 {
let last_query = &query[query_num - 1];
let last_query_first_rule = &last_query[0];
filtered =
Elements::select_by_rule(self, last_query_first_rule, Some(&chain_comb)).cloned();
if !filtered.is_empty() && last_query.len() > 1 {
for rule in &last_query[1..] {
filtered = Elements::select_by_rule(&filtered, rule, None);
if filtered.is_empty() {
break;
}
}
}
if !filtered.is_empty() && query_num > 1 {
root = root.or_else(|| {
let root_element = filtered
.get(0)
.expect("Filtered length greater than 0")
.root();
Some(Elements::with_node(&root_element))
});
let root_eles = root.as_ref().expect("root element must have");
let lookup = Some(&query[..query_num - 1]);
let mut lasts = Elements::with_capacity(filtered.length());
let comb = &last_query_first_rule.1;
for ele in filtered.get_ref() {
if root_eles.has_ele(ele, comb, lookup) {
lasts.get_mut_ref().push(ele.cloned());
}
}
filtered = lasts;
}
}
if !filtered.is_empty() {
match filter_type {
FilterType::Is => {
all_matched = true;
break;
}
_ => {
result = result.add(filtered);
}
}
}
}
match filter_type {
FilterType::IsAll => {
all_matched = result.length() == total;
}
FilterType::Not => {
if result.is_empty() {
result = self.cloned();
} else {
result = self.not_in(&result);
}
}
_ => {
}
}
(result, all_matched)
}
fn filter_in_handle(&self, search: &Elements, filter_type: FilterType) -> (Elements<'a>, bool) {
let eles = self.get_ref();
let total = eles.len();
let mut result = Elements::with_capacity(total);
let mut all_matched = false;
match filter_type {
FilterType::Filter => {
let mut start_index = 0;
let search_total = search.length();
for ele in eles {
if let Some(index) = search.index_of(ele, start_index) {
start_index = index + 1;
result.push(ele.cloned());
if start_index >= search_total {
break;
}
}
}
}
FilterType::Not => {
let mut start_index = 0;
for ele in eles {
if let Some(index) = search.index_of(ele, start_index) {
start_index = index + 1;
} else {
result.push(ele.cloned());
}
}
}
FilterType::Is => {
for ele in eles {
if search.includes(ele) {
all_matched = true;
break;
}
}
}
FilterType::IsAll => {
if total <= search.length() {
let mut is_all_matched = true;
let mut start_index = 0;
for ele in eles {
if let Some(index) = search.index_of(ele, start_index) {
start_index = index + 1;
} else {
is_all_matched = false;
break;
}
}
all_matched = is_all_matched;
}
}
}
(result, all_matched)
}
pub fn filter(&self, selector: &str) -> Elements<'a> {
const METHOD: &str = "filter";
self.trigger_method(METHOD, selector, |selector| {
self.filter_type_handle(&selector, &FilterType::Filter).0
})
}
pub fn filter_by<F>(&self, handle: F) -> Elements<'a>
where
F: Fn(usize, &BoxDynElement) -> bool,
{
let mut result = Elements::with_capacity(self.length());
for (index, ele) in self.get_ref().iter().enumerate() {
if handle(index, ele) {
result.push(ele.cloned());
}
}
result
}
pub fn filter_in(&self, search: &Elements) -> Elements<'a> {
self.filter_in_handle(search, FilterType::Filter).0
}
pub fn is(&self, selector: &str) -> bool {
const METHOD: &str = "is";
self.trigger_method(METHOD, selector, |selector| {
self.filter_type_handle(selector, &FilterType::Is).1
})
}
pub fn is_by<F>(&self, handle: F) -> bool
where
F: Fn(usize, &BoxDynElement) -> bool,
{
let mut flag = false;
for (index, ele) in self.get_ref().iter().enumerate() {
if handle(index, ele) {
flag = true;
break;
}
}
flag
}
pub fn is_in(&self, search: &Elements) -> bool {
self.filter_in_handle(search, FilterType::Is).1
}
pub fn is_all(&self, selector: &str) -> bool {
const METHOD: &str = "is_all";
self.trigger_method(METHOD, selector, |selector| {
self.filter_type_handle(&selector, &FilterType::IsAll).1
})
}
pub fn is_all_by<F>(&self, handle: F) -> bool
where
F: Fn(usize, &BoxDynElement) -> bool,
{
let mut flag = true;
for (index, ele) in self.get_ref().iter().enumerate() {
if !handle(index, ele) {
flag = false;
break;
}
}
flag
}
pub fn is_all_in(&self, search: &Elements) -> bool {
self.filter_in_handle(search, FilterType::IsAll).1
}
pub fn not(&self, selector: &str) -> Elements<'a> {
const METHOD: &str = "not";
self.trigger_method(METHOD, selector, |selector| {
self.filter_type_handle(&selector, &FilterType::Not).0
})
}
pub fn not_by<F>(&self, handle: F) -> Elements<'a>
where
F: Fn(usize, &BoxDynElement) -> bool,
{
let mut result = Elements::with_capacity(self.length());
for (index, ele) in self.get_ref().iter().enumerate() {
if !handle(index, ele) {
result.push(ele.cloned());
}
}
result
}
pub fn not_in(&self, search: &Elements) -> Elements<'a> {
self.filter_in_handle(search, FilterType::Not).0
}
pub fn has(&self, selector: &str) -> Elements<'a> {
const METHOD: &str = "has";
fn loop_handle(ele: &BoxDynElement, selector: &Selector) -> bool {
let childs = ele.children();
if !childs.is_empty() {
let (_, all_matched) = childs.filter_type_handle(selector, &FilterType::Is);
if all_matched {
return true;
}
for child in childs.get_ref() {
if loop_handle(child, selector) {
return true;
}
}
}
false
}
self.trigger_method(METHOD, selector, |selector| {
self.filter_by(|_, ele| loop_handle(ele, selector))
})
}
pub fn has_in(&self, search: &Elements) -> Elements<'a> {
fn loop_handle(ele: &BoxDynElement, search: &Elements) -> bool {
let childs = ele.children();
if !childs.is_empty() {
let (_, all_matched) = childs.filter_in_handle(search, FilterType::Is);
if all_matched {
return true;
}
for child in childs.get_ref() {
if loop_handle(child, search) {
return true;
}
}
}
false
}
self.filter_by(|_, ele| loop_handle(ele, &search))
}
}
impl<'a> Elements<'a> {
pub fn eq(&self, index: usize) -> Elements<'a> {
if let Some(ele) = self.get(index) {
Elements::with_node(ele)
} else {
Elements::new()
}
}
pub fn first(&self) -> Elements<'a> {
self.eq(0)
}
pub fn last(&self) -> Elements<'a> {
self.eq(self.length() - 1)
}
pub fn slice<T: RangeBounds<usize>>(&self, range: T) -> Elements<'a> {
let mut start = 0;
let mut end = self.length();
match range.start_bound() {
Bound::Unbounded => {
}
Bound::Included(&cur_start) => {
if cur_start < end {
start = cur_start;
} else {
return Elements::new();
}
}
_ => {
}
};
match range.end_bound() {
Bound::Unbounded => {
}
Bound::Excluded(&cur_end) => {
if cur_end < end {
end = cur_end;
}
}
Bound::Included(&cur_end) => {
let cur_end = cur_end + 1;
if cur_end < end {
end = cur_end;
}
}
}
let mut result = Elements::with_capacity(end - start);
let eles = self.get_ref();
for ele in &eles[start..end] {
result.push(ele.cloned());
}
result
}
pub fn add(&self, eles: Elements<'a>) -> Elements<'a> {
if self.is_empty() {
return eles;
}
if eles.is_empty() {
return self.cloned();
}
let first_eles = self;
let second_eles = &eles;
let first_count = first_eles.length();
let second_count = second_eles.length();
let avg = second_count / 3;
let mut prevs: Vec<usize> = Vec::with_capacity(avg);
let mut mids: Vec<(usize, usize)> = Vec::with_capacity(avg);
let mut afters: Vec<usize> = Vec::with_capacity(avg);
let mut sec_left_index = 0;
let sec_right_index = second_count - 1;
let mut first_indexs: HashMap<usize, VecDeque<usize>> = HashMap::with_capacity(first_count);
let mut fir_left_index = 0;
let fir_right_index = first_count - 1;
let first = first_eles.get_ref();
let second = second_eles.get_ref();
fn get_first_index_cached<'a>(
first_indexs: &'a mut HashMap<usize, VecDeque<usize>>,
first: &[BoxDynElement],
index: usize,
) -> &'a mut VecDeque<usize> {
first_indexs
.entry(index)
.or_insert_with(|| get_tree_indexs(&first[index]))
};
while fir_left_index <= fir_right_index && sec_left_index <= sec_right_index {
let sec_left = &second[sec_left_index];
let sec_left_level = get_tree_indexs(sec_left);
let fir_left_level = get_first_index_cached(&mut first_indexs, &first, fir_left_index);
match compare_indexs(&sec_left_level, &fir_left_level) {
Ordering::Equal => {
sec_left_index += 1;
fir_left_index += 1;
}
Ordering::Greater => {
let fir_right_level = get_first_index_cached(&mut first_indexs, &first, fir_right_index);
match compare_indexs(&sec_left_level, &fir_right_level) {
Ordering::Greater => {
afters.extend(sec_left_index..=sec_right_index);
break;
}
Ordering::Less => {
let mut l = fir_left_index;
let mut r = fir_right_index;
let mut mid = (l + r) / 2;
let mut find_equal = false;
while mid != l {
let mid_level = get_first_index_cached(&mut first_indexs, &first, mid);
match compare_indexs(&sec_left_level, &mid_level) {
Ordering::Greater => {
l = mid;
mid = (l + r) / 2;
}
Ordering::Less => {
r = mid;
mid = (l + r) / 2;
}
Ordering::Equal => {
find_equal = true;
break;
}
}
}
if !find_equal {
mids.push((sec_left_index, mid + 1));
}
fir_left_index = mid;
sec_left_index += 1;
}
Ordering::Equal => {
afters.extend(sec_left_index + 1..=sec_right_index);
break;
}
}
}
Ordering::Less => {
let sec_right = &second[sec_right_index];
let sec_right_level = get_tree_indexs(sec_right);
match compare_indexs(&sec_right_level, &fir_left_level) {
Ordering::Less => {
prevs.extend(sec_left_index..=sec_right_index);
break;
}
Ordering::Greater => {
prevs.push(sec_left_index);
sec_left_index += 1;
}
Ordering::Equal => {
prevs.extend(sec_left_index..sec_right_index);
break;
}
}
}
}
}
let prevs_count = prevs.len();
let mids_count = mids.len();
let afters_count = afters.len();
let mut result = Elements::with_capacity(first_count + prevs_count + mids_count + afters_count);
if prevs_count > 0 {
for index in prevs {
let ele = &second[index];
result.push(ele.cloned());
}
}
let mut mid_loop = 0;
for (index, ele) in first_eles.get_ref().iter().enumerate() {
if mid_loop < mids_count {
let cur_mids = &mids[mid_loop..];
for (sec_index, mid_index) in cur_mids {
if *mid_index == index {
mid_loop += 1;
let mid_ele = &second[*sec_index];
result.push(mid_ele.cloned());
} else {
break;
}
}
}
result.push(ele.cloned());
}
if afters_count > 0 {
for index in afters {
let ele = &second[index];
result.push(ele.cloned());
}
}
result
}
fn includes(&self, ele: &BoxDynElement) -> bool {
self.get_ref().iter().any(|n| ele.is(n))
}
fn index_of(&self, ele: &BoxDynElement, start_index: usize) -> Option<usize> {
let total = self.length();
if start_index < total {
let nodes = self.get_ref();
for (index, cur_ele) in nodes[start_index..].iter().enumerate() {
if ele.is(cur_ele) {
return Some(start_index + index);
}
}
}
None
}
fn is_sibling(cur: &BoxDynElement, other: &BoxDynElement) -> bool {
if let Some(parent) = cur.parent() {
if let Some(other_parent) = other.parent() {
return parent.is(&other_parent);
}
}
false
}
}
impl<'a> Elements<'a> {
pub fn text(&self) -> &str {
let mut result = String::with_capacity(50);
for ele in self.get_ref() {
result.push_str(ele.text_content());
}
to_static_str(result)
}
pub fn set_text(&mut self, content: &str) -> &mut Self {
for ele in self.get_mut_ref() {
ele.set_text(content);
}
self
}
pub fn html(&self) -> &str {
if let Some(ele) = self.get(0) {
return ele.inner_html();
}
""
}
pub fn set_html(&mut self, content: &str) -> &mut Self {
for ele in self.get_mut_ref() {
ele.set_html(content);
}
self
}
pub fn outer_html(&self) -> &str {
if let Some(ele) = self.get(0) {
return ele.outer_html();
}
""
}
pub fn texts(&self, limit_depth: u32) -> Texts<'a> {
let mut result = Texts::with_capacity(DEF_NODES_LEN);
for ele in self.get_ref() {
if let Some(text_nodes) = ele.texts(limit_depth) {
result.get_mut_ref().extend(text_nodes);
}
}
result
}
}
impl<'a> Elements<'a> {
pub fn attr(&self, attr_name: &str) -> Option<IAttrValue> {
if let Some(ele) = self.get(0) {
return ele.get_attribute(attr_name);
}
None
}
pub fn set_attr(&mut self, attr_name: &str, value: Option<&str>) -> &mut Self {
for ele in self.get_mut_ref() {
ele.set_attribute(attr_name, value);
}
self
}
pub fn remove_attr(&mut self, attr_name: &str) -> &mut Self {
for ele in self.get_mut_ref() {
ele.remove_attribute(attr_name);
}
self
}
pub fn has_class(&self, class_name: &str) -> bool {
let class_name = class_name.trim();
if !class_name.is_empty() {
let class_list = get_class_list(class_name);
for ele in self.get_ref() {
let class_value = ele.get_attribute(ATTR_CLASS);
if let Some(IAttrValue::Value(cls, _)) = class_value {
let orig_class_list = get_class_list(&cls);
for class_name in &class_list {
if orig_class_list.contains(class_name) {
return true;
}
}
}
}
}
false
}
pub fn add_class(&mut self, class_name: &str) -> &mut Self {
let class_name = class_name.trim();
if !class_name.is_empty() {
let class_list = get_class_list(class_name);
for ele in self.get_mut_ref() {
let class_value = ele.get_attribute(ATTR_CLASS);
if let Some(IAttrValue::Value(cls, _)) = class_value {
let mut orig_class_list = get_class_list(&cls);
for class_name in &class_list {
if !orig_class_list.contains(class_name) {
orig_class_list.push(class_name);
}
}
ele.set_attribute(ATTR_CLASS, Some(orig_class_list.join(" ").as_str()));
continue;
}
ele.set_attribute(ATTR_CLASS, Some(class_name));
}
}
self
}
pub fn remove_class(&mut self, class_name: &str) -> &mut Self {
let class_name = class_name.trim();
if !class_name.is_empty() {
let class_list = get_class_list(class_name);
for ele in self.get_mut_ref() {
let class_value = ele.get_attribute(ATTR_CLASS);
if let Some(IAttrValue::Value(cls, _)) = class_value {
let mut orig_class_list = get_class_list(&cls);
let mut removed_indexs: Vec<usize> = Vec::with_capacity(class_list.len());
for class_name in &class_list {
if let Some(index) = orig_class_list.iter().position(|name| name == class_name) {
removed_indexs.push(index);
}
}
if !removed_indexs.is_empty() {
retain_by_index(&mut orig_class_list, &removed_indexs);
ele.set_attribute(ATTR_CLASS, Some(orig_class_list.join(" ").as_str()));
}
}
}
}
self
}
pub fn toggle_class(&mut self, class_name: &str) -> &mut Self {
let class_name = class_name.trim();
if !class_name.is_empty() {
let class_list = get_class_list(class_name);
let total = class_list.len();
for ele in self.get_mut_ref() {
let class_value = ele.get_attribute(ATTR_CLASS);
if let Some(IAttrValue::Value(cls, _)) = class_value {
let mut orig_class_list = get_class_list(&cls);
let mut removed_indexs: Vec<usize> = Vec::with_capacity(total);
let mut added_class_list: Vec<&str> = Vec::with_capacity(total);
for class_name in &class_list {
if let Some(index) = orig_class_list.iter().position(|name| name == class_name) {
removed_indexs.push(index);
} else {
added_class_list.push(class_name);
}
}
let mut need_set = false;
if !removed_indexs.is_empty() {
retain_by_index(&mut orig_class_list, &removed_indexs);
need_set = true;
}
if !added_class_list.is_empty() {
orig_class_list.extend(added_class_list);
need_set = true;
}
if need_set {
ele.set_attribute(ATTR_CLASS, Some(orig_class_list.join(" ").as_str()));
}
continue;
}
ele.set_attribute(ATTR_CLASS, Some(class_name));
}
}
self
}
}
impl<'a> Elements<'a> {
pub fn remove(self) {
for ele in self.into_iter() {
if let Some(parent) = ele.parent().as_mut() {
parent.remove_child(ele);
}
}
}
pub fn empty(&mut self) -> &mut Self {
self.set_text("");
self
}
fn insert(&mut self, dest: &Elements, position: &InsertPosition) -> &mut Self {
for ele in self.get_mut_ref() {
for inserted in dest.get_ref().iter().rev() {
ele.insert_adjacent(position, inserted);
}
}
self
}
pub fn append(&mut self, elements: &mut Elements) -> &mut Self {
self.insert(elements, &InsertPosition::BeforeEnd);
self
}
pub fn append_to(&mut self, elements: &mut Elements) -> &mut Self {
elements.append(self);
self
}
pub fn prepend(&mut self, elements: &mut Elements) -> &mut Self {
self.insert(elements, &InsertPosition::AfterBegin);
self
}
pub fn prepend_to(&mut self, elements: &mut Elements) -> &mut Self {
elements.prepend(self);
self
}
pub fn insert_before(&mut self, elements: &mut Elements) -> &mut Self {
elements.before(self);
self
}
pub fn before(&mut self, elements: &mut Elements) -> &mut Self {
self.insert(elements, &InsertPosition::BeforeBegin);
self
}
pub fn insert_after(&mut self, elements: &mut Elements) -> &mut Self {
elements.after(self);
self
}
pub fn after(&mut self, elements: &mut Elements) -> &mut Self {
self.insert(elements, &InsertPosition::AfterEnd);
self
}
}
impl<'a> IntoIterator for Elements<'a> {
type Item = BoxDynElement<'a>;
type IntoIter = Box<dyn Iterator<Item = Self::Item> + 'a>;
fn into_iter(self) -> Self::IntoIter {
Box::new(self.nodes.into_iter())
}
}
impl<'a> From<Vec<BoxDynElement<'a>>> for Elements<'a> {
fn from(nodes: Vec<BoxDynElement<'a>>) -> Self {
Elements { nodes }
}
}