duid_core/core/html/attributes/
mod.rs1
2#[macro_use]
3mod attribute_macros;
4mod attribute_value;
5mod style;
6mod attribute;
7
8use crate::core::{
9 events::Event,
10 events::listener::Listener
11};
12pub use attribute_macros::*;
13pub use attribute_value::AttributeValue;
14pub use jss::Value;
15pub use style::Style;
16pub use attribute::*;
17
18
19pub fn style<MSG>(
20 style_name: &'static str,
21 value: impl Into<Value>,
22) -> Attribute<MSG> {
23 attr(
24 style_name,
25 AttributeValue::from_styles([Style::new("", value.into())]),
26 )
27}
28
29pub fn styles<MSG>(
30 pairs: impl IntoIterator<Item = (impl ToString, impl Into<Value>)>,
31) -> Attribute<MSG> {
32 let styles = pairs.into_iter().map(|(key, value)| {
33 Style::new(key.to_string(), Into::<Value>::into(value))
34 });
35 attr("style", AttributeValue::from_styles(styles))
36}
37
38pub fn styles_values<MSG>(
39 pairs: impl IntoIterator<Item = (impl ToString, impl Into<Value>)>,
40) -> Attribute<MSG> {
41 let styles = pairs
42 .into_iter()
43 .map(|(key, value)| Style::new(key.to_string(), value));
44 attr("style", AttributeValue::from_styles(styles))
45}
46
47
48pub fn styles_flag<MSG>(
49 trio: impl IntoIterator<Item = (impl ToString, impl Into<Value>, bool)>,
50) -> Attribute<MSG> {
51 let styles = trio.into_iter().filter_map(|(key, value, flag)| {
52 if flag {
53 Some(Style::new(key, value))
54 } else {
55 None
56 }
57 });
58 attr("style", AttributeValue::from_styles(styles))
59}
60
61
62pub fn classes_flag<MSG>(
63 pair: impl IntoIterator<Item = (impl ToString, bool)>,
64) -> Attribute<MSG> {
65 let class_list = pair.into_iter().filter_map(|(class, flag)| {
66 if flag {
67 Some(class.to_string())
68 } else {
69 None
70 }
71 });
72
73 classes(class_list)
74}
75
76
77pub fn classes<MSG>(
78 class_list: impl IntoIterator<Item = impl ToString>,
79) -> Attribute<MSG> {
80 let class_values: Vec<_> = class_list
81 .into_iter()
82 .map(|v| AttributeValue::from_value(Value::from(v.to_string()))).collect();
83
84 Attribute::with_multiple_values(None, "class", &class_values)
85}
86
87
88pub fn class_namespaced<MSG>(
89 namespace: impl ToString,
90 class_names: impl ToString,
91) -> Attribute<MSG> {
92 class(jss::class_namespaced(namespace, class_names))
93}
94
95
96pub fn classes_flag_namespaced<MSG>(
97 namespace: impl ToString,
98 pair: impl IntoIterator<Item = (impl ToString, bool)>,
99) -> Attribute<MSG> {
100 let class_list = pair.into_iter().filter_map(|(class_name, flag)| {
101 if flag {
102 Some(jss::class_namespaced(namespace.to_string(), class_name))
103 } else {
104 None
105 }
106 });
107 classes(class_list)
108}
109
110
111pub fn attrs_flag<MSG>(
112 trio: impl IntoIterator<Item = (&'static str, impl Into<Value>, bool)>,
113) -> impl IntoIterator<Item = Attribute<MSG>> {
114 trio.into_iter().filter_map(|(key, value, flag)| {
115 if flag {
116 Some(into_attr(key, value.into()))
117 } else {
118 None
119 }
120 })
121}
122
123
124pub fn maybe_attr<MSG>(
125 name: &'static str,
126 value: Option<impl Into<Value>>,
127) -> Attribute<MSG> {
128 if let Some(value) = value {
129 into_attr(name, value)
130 } else {
131 empty_attr()
132 }
133}
134
135
136pub fn checked<MSG>(is_checked: bool) -> Attribute<MSG> {
137 if is_checked {
138 #[cfg(not(feature = "with-dom"))]
139 {
140 into_attr("checked", "checked")
141 }
142 #[cfg(feature = "with-dom")]
143 {
144 into_attr("checked", true)
145 }
146 } else {
147 empty_attr()
148 }
149}
150
151
152pub fn disabled<MSG>(is_disabled: bool) -> Attribute<MSG> {
153 if is_disabled {
154 into_attr("disabled", true)
155 } else {
156 empty_attr()
157 }
158}
159
160
161pub fn inner_html<V, MSG>(inner_html: V) -> Attribute<MSG>
162where
163 V: Into<Value> + Clone,
164{
165 attr(
166 "inner_html",
167 AttributeValue::function_call(inner_html.into()),
168 )
169}
170
171
172pub fn focus<MSG>(is_focus: bool) -> Attribute<MSG> {
173 into_attr("focus", is_focus)
174}
175
176
177pub fn into_attr<V: Into<Value>, MSG>(att: &'static str, v: V) -> Attribute<MSG> {
178 attr(att, AttributeValue::from_value(v.into()))
179}
180
181
182pub fn empty_attr<MSG>() -> Attribute<MSG> {
183 attr("", AttributeValue::Empty)
184}
185
186#[doc(hidden)]
187pub(crate) fn merge_plain_attributes_values<MSG>(
188 attr_values: &[&AttributeValue<MSG>],
189) -> Option<String> {
190 let plain_values: Vec<String> = attr_values
191 .iter()
192 .flat_map(|att_value| match att_value {
193 AttributeValue::Simple(simple) => Some(simple.to_string()),
194 AttributeValue::FunctionCall(fvalue) => Some(fvalue.to_string()),
195 _ => None,
196 })
197 .collect();
198 if !plain_values.is_empty() {
199 Some(plain_values.join(" "))
200 } else {
201 None
202 }
203}
204
205#[doc(hidden)]
206pub(crate) fn merge_styles_attributes_values<MSG>(
207 attr_values: &[&AttributeValue<MSG>],
208) -> Option<String> {
209 use std::fmt::Write;
210
211 let styles_values: Vec<String> = attr_values
212 .iter()
213 .flat_map(|att_value| match att_value {
214 AttributeValue::Style(styles) => {
215 let mut style_str = String::new();
216 styles.iter().for_each(|s| {
217 write!(style_str, "{}", s).expect("must write")
218 });
219 Some(style_str)
220 }
221 _ => None,
222 })
223 .collect();
224
225 if !styles_values.is_empty() {
226 Some(styles_values.join(" "))
227 } else {
228 None
229 }
230}
231
232pub struct SegregatedAttributes<'a, MSG> {
233 pub listeners: Vec<&'a Listener<Event, MSG>>,
234 pub plain_values: Vec<&'a AttributeValue<MSG>>,
235 pub styles: Vec<&'a AttributeValue<MSG>>,
236 pub function_calls: Vec<&'a AttributeValue<MSG>>,
237}
238
239#[doc(hidden)]
240pub(crate) fn partition_callbacks_from_plain_styles_and_func_calls<MSG>(
241 attr: &Attribute<MSG>,
242) -> SegregatedAttributes<MSG> {
243 let mut listeners = vec![];
244 let mut plain_values = vec![];
245 let mut styles = vec![];
246 let mut function_calls = vec![];
247 for av in attr.value() {
248 match av {
249 AttributeValue::Simple(_plain) => {
250 plain_values.push(av);
251 }
252 AttributeValue::FunctionCall(_call) => {
253 function_calls.push(av);
254 }
255 AttributeValue::Style(_) => {
256 styles.push(av);
257 }
258 AttributeValue::EventListener(cb) => {
259 listeners.push(cb);
260 }
261 _ => (),
262 }
263 }
264 SegregatedAttributes {
265 listeners,
266 plain_values,
267 styles,
268 function_calls,
269 }
270}