Skip to main content

tablo_test/protocol/
sections.rs

1//! Reads a page's `Section` blocks: `[data-section]` for each, `[data-section-title]` for its
2//! heading, and a `<details>` without `open` for one the page renders folded.
3
4use super::dom::{attr_value, strip_text, tags_where};
5
6/// One `Section` block.
7#[derive(Debug, Clone, PartialEq, Eq)]
8pub struct Section {
9    /// The heading's text: the title, then the description.
10    pub heading: String,
11    /// Whether the section folds its body away on a click of its heading.
12    pub collapsible: bool,
13    /// Whether the page shows the section's body: always for a section that does not collapse.
14    pub open: bool,
15    /// The keys the controls in the section post, in document order, each once.
16    pub keys: Vec<String>,
17}
18
19/// The sections `html` renders, in document order: a nested section's after the one holding it,
20/// whose `keys` hold the nested section's too.
21pub fn sections(html: &str) -> Vec<Section> {
22    tags_where(html, |_, attrs| attr_value(attrs, "data-section").is_some())
23        .into_iter()
24        .map(|(tag, attrs, inner)| {
25            let heading = tags_where(&inner, |_, attrs| {
26                attr_value(attrs, "data-section-title").is_some()
27            })
28            .into_iter()
29            .next()
30            .map(|(_, _, heading)| strip_text(&heading))
31            .unwrap_or_default();
32            let mut keys: Vec<String> = Vec::new();
33            for (_, attrs, _) in tags_where(&inner, |_, attrs| attr_value(attrs, "name").is_some())
34            {
35                let key = attr_value(&attrs, "name").unwrap_or_default();
36                if !keys.contains(&key) {
37                    keys.push(key);
38                }
39            }
40            let collapsible = tag == "details";
41            Section {
42                heading,
43                collapsible,
44                open: !collapsible || attrs.iter().any(|(name, _)| name == "open"),
45                keys,
46            }
47        })
48        .collect()
49}