Skip to main content

tablo_test/protocol/
page_filters.rs

1//! Reads a page's filter bar: the `[data-page-filters]` form, what its controls submit as they
2//! stand, and its `[data-page-filters-reset]` link.
3
4use super::dom::{attr_value, elements, is_selected, open_tags, tags_where};
5
6/// A page's filter bar.
7#[derive(Debug, Clone, PartialEq, Eq)]
8pub struct PageFilterBar {
9    /// Each `(name, value)` the form submits as it stands, in document order: the request's other
10    /// parameters it carries, each select's selected option and each date input's day, blank
11    /// ones included.
12    pub submits: Vec<(String, String)>,
13    /// Where the reset link leads, shown once the request holds a value.
14    pub reset: Option<String>,
15}
16
17/// The filter bar `html` renders, or `None` without one.
18pub fn page_filter_bar(html: &str) -> Option<PageFilterBar> {
19    let (_, _, form) = tags_where(html, |tag, attrs| {
20        tag == "form" && attr_value(attrs, "data-page-filters").is_some()
21    })
22    .into_iter()
23    .next()?;
24    let mut submits: Vec<(usize, String, String)> = open_tags(&form)
25        .into_iter()
26        .filter(|(tag, _, _)| tag == "input")
27        .filter_map(|(_, attrs, at)| {
28            Some((
29                at,
30                attr_value(&attrs, "name")?,
31                attr_value(&attrs, "value").unwrap_or_default(),
32            ))
33        })
34        .collect();
35    let selects = open_tags(&form)
36        .into_iter()
37        .filter(|(tag, _, _)| tag == "select")
38        .map(|(_, attrs, at)| (at, attr_value(&attrs, "name")));
39    for ((at, name), (_, _, inner)) in selects.zip(elements(&form, "select")) {
40        let Some(name) = name else { continue };
41        let options = elements(&inner, "option");
42        let chosen = options
43            .iter()
44            .find(|(_, attrs, _)| is_selected(attrs))
45            .or(options.first())
46            .and_then(|(_, attrs, _)| attr_value(attrs, "value"))
47            .unwrap_or_default();
48        submits.push((at, name, chosen));
49    }
50    submits.sort_by_key(|(at, _, _)| *at);
51    let reset = tags_where(&form, |tag, attrs| {
52        tag == "a" && attr_value(attrs, "data-page-filters-reset").is_some()
53    })
54    .into_iter()
55    .next()
56    .and_then(|(_, attrs, _)| attr_value(&attrs, "href"));
57    Some(PageFilterBar {
58        submits: submits
59            .into_iter()
60            .map(|(_, name, value)| (name, value))
61            .collect(),
62        reset,
63    })
64}