tablo_test/protocol/
tabs.rs1use super::dom::{attr_value, strip_text, tags_where};
7
8#[derive(Debug, Clone, PartialEq, Eq)]
10pub struct Tab {
11 pub label: String,
13 pub badge: Option<String>,
15 pub active: bool,
17 pub errored: bool,
19 pub keys: Vec<String>,
21}
22
23pub fn tabs(html: &str) -> Vec<Tab> {
26 tags_where(html, |tag, attrs| {
27 tag == "button" && attr_value(attrs, "role").as_deref() == Some("tab")
28 })
29 .into_iter()
30 .map(|(_, attrs, inner)| {
31 let panel = attr_value(&attrs, "aria-controls").and_then(|id| {
32 tags_where(html, |_, attrs| {
33 attr_value(attrs, "id").as_deref() == Some(id.as_str())
34 })
35 .into_iter()
36 .next()
37 });
38 let shown = panel
39 .as_ref()
40 .is_some_and(|(_, attrs, _)| !attrs.iter().any(|(name, _)| name == "hidden"));
41 let mut keys: Vec<String> = Vec::new();
42 if let Some((_, _, panel)) = &panel {
43 for (_, attrs, _) in tags_where(panel, |_, attrs| attr_value(attrs, "name").is_some()) {
44 let key = attr_value(&attrs, "name").unwrap_or_default();
45 if !keys.contains(&key) {
46 keys.push(key);
47 }
48 }
49 }
50 let (label, badge) = match inner.find("data-tab-badge") {
52 Some(at) => {
53 let start = inner[..at].rfind('<').unwrap_or(at);
54 (&inner[..start], Some(strip_text(&inner[start..])))
55 }
56 None => (inner.as_str(), None),
57 };
58 Tab {
59 label: strip_text(label),
60 badge,
61 active: shown && attr_value(&attrs, "aria-selected").as_deref() == Some("true"),
62 errored: attrs.iter().any(|(name, _)| name == "data-tab-error"),
63 keys,
64 }
65 })
66 .collect()
67}