script/dom/element/
attributes.rs

1/* This Source Code Form is subject to the terms of the Mozilla Public
2 * License, v. 2.0. If a copy of the MPL was not distributed with this
3 * file, You can obtain one at https://mozilla.org/MPL/2.0/. */
4
5use html5ever::{LocalName, ns};
6use js::context::JSContext;
7use style::attr::AttrValue;
8use stylo_atoms::Atom;
9
10use crate::dom::bindings::codegen::Bindings::AttrBinding::AttrMethods;
11use crate::dom::bindings::codegen::UnionTypes::{TrustedHTMLOrString, TrustedScriptURLOrUSVString};
12use crate::dom::bindings::str::{DOMString, USVString};
13use crate::dom::element::Element;
14use crate::dom::node::NodeTraits;
15use crate::script_runtime::CanGc;
16
17impl Element {
18    pub(crate) fn get_int_attribute(&self, local_name: &LocalName, default: i32) -> i32 {
19        match self.get_attribute(local_name) {
20            Some(ref attribute) => match *attribute.value() {
21                AttrValue::Int(_, value) => value,
22                _ => unreachable!("Expected an AttrValue::Int: implement parse_plain_attribute"),
23            },
24            None => default,
25        }
26    }
27
28    pub(crate) fn set_atomic_attribute(
29        &self,
30        local_name: &LocalName,
31        value: DOMString,
32        can_gc: CanGc,
33    ) {
34        self.set_attribute(local_name, AttrValue::from_atomic(value.into()), can_gc);
35    }
36
37    pub(crate) fn set_bool_attribute(&self, local_name: &LocalName, value: bool, can_gc: CanGc) {
38        if self.has_attribute(local_name) == value {
39            return;
40        }
41        if value {
42            self.set_string_attribute(local_name, DOMString::new(), can_gc);
43        } else {
44            self.remove_attribute(&ns!(), local_name, can_gc);
45        }
46    }
47
48    pub(crate) fn get_url_attribute(&self, local_name: &LocalName) -> USVString {
49        let Some(attribute) = self.get_attribute(local_name) else {
50            return Default::default();
51        };
52        let value = &**attribute.value();
53        self.owner_document()
54            .encoding_parse_a_url(value)
55            .map(|parsed| USVString(parsed.into_string()))
56            .unwrap_or_else(|_| USVString(value.to_owned()))
57    }
58
59    pub(crate) fn set_url_attribute(
60        &self,
61        local_name: &LocalName,
62        value: USVString,
63        can_gc: CanGc,
64    ) {
65        self.set_attribute(local_name, AttrValue::String(value.to_string()), can_gc);
66    }
67
68    pub(crate) fn get_trusted_type_url_attribute(
69        &self,
70        local_name: &LocalName,
71    ) -> TrustedScriptURLOrUSVString {
72        let Some(attribute) = self.get_attribute(local_name) else {
73            return TrustedScriptURLOrUSVString::USVString(USVString::default());
74        };
75        let value = &**attribute.value();
76        self.owner_document()
77            .encoding_parse_a_url(value)
78            .map(|parsed| TrustedScriptURLOrUSVString::USVString(USVString(parsed.into_string())))
79            .unwrap_or_else(|_| TrustedScriptURLOrUSVString::USVString(USVString(value.to_owned())))
80    }
81
82    pub(crate) fn get_trusted_html_attribute(&self, local_name: &LocalName) -> TrustedHTMLOrString {
83        TrustedHTMLOrString::String(self.get_string_attribute(local_name))
84    }
85
86    pub(crate) fn get_string_attribute(&self, local_name: &LocalName) -> DOMString {
87        self.get_attribute(local_name)
88            .map(|attribute| attribute.Value())
89            .unwrap_or_default()
90    }
91
92    pub(crate) fn set_string_attribute(
93        &self,
94        local_name: &LocalName,
95        value: DOMString,
96        can_gc: CanGc,
97    ) {
98        self.set_attribute(local_name, AttrValue::String(value.into()), can_gc);
99    }
100
101    /// Used for string attribute reflections where absence of the attribute returns `null`,
102    /// e.g. `element.ariaLabel` returning `null` when the `aria-label` attribute is absent.
103    pub(crate) fn get_nullable_string_attribute(
104        &self,
105        local_name: &LocalName,
106    ) -> Option<DOMString> {
107        if self.has_attribute(local_name) {
108            Some(self.get_string_attribute(local_name))
109        } else {
110            None
111        }
112    }
113
114    /// Used for string attribute reflections where setting `null`/`undefined` removes the
115    /// attribute, e.g. `element.ariaLabel = null` removing the `aria-label` attribute.
116    pub(crate) fn set_nullable_string_attribute(
117        &self,
118        cx: &mut JSContext,
119        local_name: &LocalName,
120        value: Option<DOMString>,
121    ) {
122        match value {
123            Some(val) => {
124                self.set_string_attribute(local_name, val, CanGc::from_cx(cx));
125            },
126            None => {
127                self.remove_attribute(&ns!(), local_name, CanGc::from_cx(cx));
128            },
129        }
130    }
131
132    pub(crate) fn get_tokenlist_attribute(&self, local_name: &LocalName) -> Vec<Atom> {
133        self.get_attribute(local_name)
134            .map(|attribute| attribute.value().as_tokens().to_vec())
135            .unwrap_or_default()
136    }
137
138    pub(crate) fn set_tokenlist_attribute(
139        &self,
140        local_name: &LocalName,
141        value: DOMString,
142        can_gc: CanGc,
143    ) {
144        self.set_attribute(
145            local_name,
146            AttrValue::from_serialized_tokenlist(value.into()),
147            can_gc,
148        );
149    }
150
151    pub(crate) fn set_atomic_tokenlist_attribute(
152        &self,
153        local_name: &LocalName,
154        tokens: Vec<Atom>,
155        can_gc: CanGc,
156    ) {
157        self.set_attribute(local_name, AttrValue::from_atomic_tokens(tokens), can_gc);
158    }
159
160    pub(crate) fn set_int_attribute(&self, local_name: &LocalName, value: i32, can_gc: CanGc) {
161        self.set_attribute(local_name, AttrValue::Int(value.to_string(), value), can_gc);
162    }
163
164    pub(crate) fn get_uint_attribute(&self, local_name: &LocalName, default: u32) -> u32 {
165        match self.get_attribute(local_name) {
166            Some(ref attribute) => match *attribute.value() {
167                AttrValue::UInt(_, value) => value,
168                _ => unreachable!("Expected an AttrValue::UInt: implement parse_plain_attribute"),
169            },
170            None => default,
171        }
172    }
173
174    pub(crate) fn set_uint_attribute(&self, local_name: &LocalName, value: u32, can_gc: CanGc) {
175        self.set_attribute(
176            local_name,
177            AttrValue::UInt(value.to_string(), value),
178            can_gc,
179        );
180    }
181}