web_sys_query/query/
attributes.rs

1//! Attributes
2
3use crate::{
4    error::Error,
5    query::{Collection, Element},
6};
7use wasm_bindgen::JsCast;
8
9/// Attribute manipulation methods
10impl Element {
11    /// Add CSS class.
12    pub fn add_class(&self, class: &str) -> Result<(), Error> {
13        self.0.class_list().add_1(class).map_err(Into::into)
14    }
15
16    /// Return the matching attribute, if found.
17    pub fn attr(&self, key: &str) -> Option<String> {
18        if key == "id" {
19            return Some(self.0.id());
20        }
21
22        self.0.get_attribute(key)
23    }
24
25    /// Set the attribute to the specified value.
26    pub fn set_attr(&self, key: &str, value: &str) -> Result<(), Error> {
27        if key == "id" {
28            self.0.set_id(value);
29            return Ok(());
30        }
31
32        self.0.set_attribute(key, value).map_err(Into::into)
33    }
34
35    /// Check if element has a matching CSS class.
36    pub fn has_class(&self, class: &str) -> bool {
37        self.0.class_list().contains(class)
38    }
39
40    /// Get the inner HTML of the element.
41    pub fn html(&self) -> String {
42        self.0.inner_html()
43    }
44
45    /// Set the inner HTML of the element.
46    pub fn set_html(&self, html: &str) {
47        self.0.set_inner_html(html)
48    }
49
50    // TODO: .prop()
51
52    /// Remove the attribute.
53    pub fn remove_attr(&self, key: &str) -> Result<(), Error> {
54        if key == "id" {
55            return Err(Error::CannotRemoveAttribute(self.0.id()));
56        }
57
58        self.0.remove_attribute(key).map_err(Into::into)
59    }
60
61    /// Remove CSS class from list.
62    pub fn remove_class(&self, class: &str) -> Result<(), Error> {
63        self.0.class_list().remove_1(class).map_err(Into::into)
64    }
65
66    // TODO: .remove_prop()
67
68    /// Return the matching attribute, if found.
69    pub fn toggle_class(&self, class: &str) -> Result<bool, Error> {
70        self.0.class_list().toggle(class).map_err(Into::into)
71    }
72
73    pub fn val(&self) -> Result<String, Error> {
74        // TODO: there must be a nicer and generic way to figure out
75        // if the Node has a `value` property.  jQuery looks for the
76        // value property or function but I'm not sure if this can be
77        // done in Rust on the raw `JsValue` object.
78        if let Some(node) = self.0.dyn_ref::<web_sys::HtmlButtonElement>() {
79            Ok(node.value())
80        } else if let Some(node) = self.0.dyn_ref::<web_sys::HtmlDataElement>() {
81            Ok(node.value())
82        } else if let Some(node) = self.0.dyn_ref::<web_sys::HtmlInputElement>() {
83            Ok(node.value())
84        } else if let Some(node) = self.0.dyn_ref::<web_sys::HtmlOptionElement>() {
85            Ok(node.value())
86        } else if let Some(node) = self.0.dyn_ref::<web_sys::HtmlOutputElement>() {
87            Ok(node.value())
88        } else if let Some(node) = self.0.dyn_ref::<web_sys::HtmlParamElement>() {
89            Ok(node.value())
90        } else if let Some(node) = self.0.dyn_ref::<web_sys::HtmlSelectElement>() {
91            Ok(node.value())
92        } else if let Some(node) = self.0.dyn_ref::<web_sys::HtmlTextAreaElement>() {
93            Ok(node.value())
94        } else {
95            Err(Error::NoValue("string"))
96        }
97    }
98
99    pub fn val_f64(&self) -> Result<f64, Error> {
100        if let Some(node) = self.0.dyn_ref::<web_sys::HtmlMeterElement>() {
101            Ok(node.value())
102        } else if let Some(node) = self.0.dyn_ref::<web_sys::HtmlProgressElement>() {
103            Ok(node.value())
104        } else {
105            Err(Error::NoValue("float"))
106        }
107    }
108
109    pub fn val_i32(&self) -> Result<i32, Error> {
110        if let Some(node) = self.0.dyn_ref::<web_sys::HtmlLiElement>() {
111            Ok(node.value())
112        } else {
113            Err(Error::NoValue("float"))
114        }
115    }
116
117    pub fn set_val(&self, value: &str) -> Result<(), Error> {
118        if let Some(node) = self.0.dyn_ref::<web_sys::HtmlButtonElement>() {
119            node.set_value(value)
120        } else if let Some(node) = self.0.dyn_ref::<web_sys::HtmlDataElement>() {
121            node.set_value(value)
122        } else if let Some(node) = self.0.dyn_ref::<web_sys::HtmlInputElement>() {
123            node.set_value(value)
124        } else if let Some(node) = self.0.dyn_ref::<web_sys::HtmlOptionElement>() {
125            node.set_value(value)
126        } else if let Some(node) = self.0.dyn_ref::<web_sys::HtmlOutputElement>() {
127            node.set_value(value)
128        } else if let Some(node) = self.0.dyn_ref::<web_sys::HtmlParamElement>() {
129            node.set_value(value)
130        } else if let Some(node) = self.0.dyn_ref::<web_sys::HtmlSelectElement>() {
131            node.set_value(value)
132        } else if let Some(node) = self.0.dyn_ref::<web_sys::HtmlTextAreaElement>() {
133            node.set_value(value)
134        } else {
135            return Err(Error::NoValue("string"));
136        }
137
138        Ok(())
139    }
140
141    pub fn set_val_f64(&self, value: f64) -> Result<(), Error> {
142        if let Some(node) = self.0.dyn_ref::<web_sys::HtmlMeterElement>() {
143            node.set_value(value)
144        } else if let Some(node) = self.0.dyn_ref::<web_sys::HtmlProgressElement>() {
145            node.set_value(value)
146        } else {
147            return Err(Error::NoValue("float"));
148        }
149
150        Ok(())
151    }
152
153    pub fn set_val_i32(&self, value: i32) -> Result<(), Error> {
154        if let Some(node) = self.0.dyn_ref::<web_sys::HtmlLiElement>() {
155            node.set_value(value)
156        } else {
157            return Err(Error::NoValue("float"));
158        }
159
160        Ok(())
161    }
162}
163
164/// Attribute manipulation methods
165impl Collection {
166    pub fn add_class(&self, class: &str) -> Result<(), Error> {
167        for element in self.0.iter() {
168            element.add_class(class)?;
169        }
170
171        Ok(())
172    }
173
174    pub fn attr(&self, key: &str) -> Vec<String> {
175        self.0.iter().filter_map(|elem| elem.attr(key)).collect()
176    }
177
178    pub fn set_attr(&self, key: &str, value: &str) -> Result<(), Error> {
179        for element in self.0.iter() {
180            element.set_attr(key, value)?;
181        }
182
183        Ok(())
184    }
185
186    pub fn has_class(&self, class: &str) -> bool {
187        self.0.iter().any(|elem| elem.has_class(class))
188    }
189
190    pub fn html(&self) -> String {
191        self.0.iter().map(|elem| elem.html()).collect()
192    }
193
194    pub fn set_html(&self, html: &str) {
195        self.0.iter().for_each(|elem| elem.set_html(html))
196    }
197
198    pub fn remove_attr(&self, key: &str) -> Result<(), Error> {
199        for element in self.0.iter() {
200            element.remove_attr(key)?;
201        }
202
203        Ok(())
204    }
205
206    pub fn remove_class(&self, class: &str) -> Result<(), Error> {
207        for element in self.0.iter() {
208            element.remove_class(class)?;
209        }
210
211        Ok(())
212    }
213
214    /// Return the matching attribute, if found.
215    pub fn toggle_class(&self, class: &str) -> Result<(), Error> {
216        for element in self.0.iter() {
217            element.toggle_class(class)?;
218        }
219
220        Ok(())
221    }
222
223    pub fn val(&self) -> Vec<String> {
224        self.0
225            .iter()
226            .map(|elem| elem.val().unwrap_or_default())
227            .collect()
228    }
229
230    pub fn val_f64(&self) -> Vec<f64> {
231        self.0
232            .iter()
233            .map(|elem| elem.val_f64().unwrap_or_default())
234            .collect()
235    }
236
237    pub fn val_i32(&self) -> Vec<i32> {
238        self.0
239            .iter()
240            .map(|elem| elem.val_i32().unwrap_or_default())
241            .collect()
242    }
243
244    pub fn set_val(&self, value: &str) {
245        self.0.iter().for_each(|elem| {
246            elem.set_val(value).ok();
247        });
248    }
249
250    pub fn set_val_f64(&self, value: f64) {
251        self.0.iter().for_each(|elem| {
252            elem.set_val_f64(value).ok();
253        });
254    }
255
256    pub fn set_val_i32(&self, value: i32) {
257        self.0.iter().for_each(|elem| {
258            elem.set_val_i32(value).ok();
259        });
260    }
261}