accessibility_rs/engine/rules/utils/
nodes.rs1use crate::engine::rules::rule::Validation;
2use accessibility_scraper::ElementRef;
3use accessibility_scraper::Selector;
4use selectors::Element;
5
6type ElementNodes<'a> = Vec<(ElementRef<'a>, Option<taffy::NodeId>)>;
7
8pub fn has_alt(ele: ElementRef<'_>) -> bool {
10 match ele.attr("role") {
11 Some(role) => {
12 if role == "presentation" {
13 return true;
14 }
15 }
16 _ => (),
17 };
18 has_alt_prop(ele)
19}
20
21pub fn has_alt_prop(ele: ElementRef<'_>) -> bool {
23 match ele.attr("alt") {
24 Some(_) => true,
25 _ => false,
26 }
27}
28
29pub fn has_prop(ele: ElementRef<'_>, prop: &str) -> bool {
31 match ele.attr(prop) {
32 Some(_) => true,
33 _ => false,
34 }
35}
36
37pub fn has_prop_value(ele: ElementRef<'_>, prop: &str) -> bool {
39 match ele.attr(prop) {
40 Some(p) => !p.is_empty(),
41 _ => false,
42 }
43}
44
45pub fn is_empty(nodes: &ElementNodes) -> (bool, Vec<String>) {
47 let mut valid = true;
48 let mut elements = Vec::new();
49
50 for ele in nodes {
51 let ele = ele.0;
52 let empty = ele.inner_html().trim().is_empty();
53 if empty {
54 valid = false;
55 elements.push(get_unique_selector(&ele))
56 }
57 }
58
59 (valid, elements)
60}
61
62pub fn validate_empty_nodes(nodes: &ElementNodes, id: &'static str) -> Validation {
64 let (valid, elements) = is_empty(&nodes);
65 Validation::new(valid, id, elements, Default::default())
66}
67
68pub fn single_selector(ele: &ElementRef<'_>, node_selector: &str) -> bool {
70 match ele.tree().root().first_child() {
71 Some(child) => match ElementRef::wrap(child) {
72 Some(element) => match Selector::parse(node_selector) {
73 Ok(s) => {
74 let e = element.select(&s);
75 e.count() == 1
76 }
77 _ => false,
78 },
79 _ => false,
80 },
81 _ => false,
82 }
83}
84
85pub fn get_unique_selector(ele: &ElementRef<'_>) -> String {
87 if ele.has_attribute("id") {
88 "#".to_string() + ele.attr("id").unwrap_or_default()
89 } else {
90 let mut selector = String::new();
91 let node_name = ele.value().name();
92
93 if node_name == "body" || node_name == "html" {
94 node_name.to_string()
95 } else {
96 let node_name = ele.value().name();
97
98 if selector.is_empty() && ele.has_attribute("class") {
99 let node_selector = node_name.to_string() + &ele.value().local_name.to_string();
100 let only_selector = single_selector(ele, &node_selector);
101 if only_selector {
102 selector = node_selector;
103 }
104 }
105
106 if !selector.is_empty() {
107 selector
108 } else {
109 if single_selector(ele, &node_name) {
110 node_name.to_string()
111 } else {
112 let pos = get_sibling_position(ele);
113
114 let s = match ele.parent_element() {
115 Some(p) => {
116 if selector.is_empty() {
117 get_unique_selector(&p)
118 } else {
119 selector
120 }
121 }
122 _ => ele.value().name().to_string(),
123 };
124
125 s + ">:nth-child(" + &pos.to_string() + ")"
126 }
127 }
128 }
129 }
130}
131
132pub fn get_sibling_position(ele: &ElementRef<'_>) -> u8 {
134 let mut i = 1;
135
136 if ele.has_siblings() {
137 let mut sibling = ele.prev_sibling();
138
139 while let Some(e) = sibling {
140 i += 1;
141 sibling = e.prev_sibling();
142 }
143 }
144
145 i
146}
147
148pub fn validate_missing_attr(
150 nodes: &ElementNodes,
151 attr: &'static str,
152 id: &'static str,
153) -> Validation {
154 let mut elements = Vec::new();
155 let mut valid = true;
156
157 nodes.iter().for_each(|e| {
158 if e.0.attr(attr).unwrap_or_default().is_empty() {
159 valid = false;
160 elements.push(get_unique_selector(&e.0))
161 }
162 });
163
164 Validation::new(valid, id, elements, Default::default())
165}