ravenrs_app_a11y/
names.rs1use ravenrs_app::{Action, FieldInfo, ModelNode};
10
11#[derive(Clone, Debug, PartialEq, Eq)]
13#[non_exhaustive]
14pub struct AccessibleText {
15 pub name: String,
17 pub description: Option<String>,
20 pub renamed: bool,
22}
23
24impl AccessibleText {
25 pub fn of_field(field: &FieldInfo, item: Option<&ModelNode>, caption: &str) -> Self {
28 let said = |name: &str, declared: &Option<String>| {
29 item.and_then(|item| item.text(name))
30 .map(str::to_owned)
31 .or_else(|| declared.clone())
32 .filter(|text| !text.trim().is_empty())
33 };
34 let named = said("AccessibleName", &field.accessible_name);
35 Self {
36 renamed: named.as_deref().is_some_and(|name| name != caption),
37 name: named.unwrap_or_else(|| caption.to_owned()),
38 description: said("AccessibleDescription", &field.accessible_description),
39 }
40 }
41
42 pub fn of_action(action: &Action) -> Self {
44 let named = action.accessible_name_text().filter(|text| !text.trim().is_empty());
45 Self {
46 renamed: named.is_some_and(|name| name != action.caption()),
47 name: named.unwrap_or(action.caption()).to_owned(),
48 description: action.accessible_description_text().map(str::to_owned),
49 }
50 }
51
52 pub fn says_more(&self) -> bool {
54 self.renamed || self.description.is_some()
55 }
56}
57
58#[cfg(test)]
59mod tests {
60 use super::*;
61 use ravenrs_app::FieldKind;
62
63 #[test]
64 fn the_caption_is_the_name_unless_the_model_says_otherwise() {
65 let field = FieldInfo::new("until", FieldKind::Date).caption("Até");
66 let plain = AccessibleText::of_field(&field, None, "Até");
67 assert_eq!((plain.name.as_str(), plain.renamed, plain.says_more()), ("Até", false, false));
68
69 let field = field.accessible_name("Fim do período").accessible_description("O último dia");
70 let declared = AccessibleText::of_field(&field, None, "Até");
71 assert_eq!(declared.name, "Fim do período");
72 assert_eq!(declared.description.as_deref(), Some("O último dia"));
73 assert!(declared.renamed);
74
75 let item = ModelNode::new("until").with("AccessibleName", "End of the period");
76 let translated = AccessibleText::of_field(&field, Some(&item), "Until");
77 assert_eq!(translated.name, "End of the period", "the model's item comes first");
78 }
79
80 #[test]
81 fn an_action_is_its_caption_unless_it_says_otherwise() {
82 let next = Action::simple("Next", "›");
83 assert_eq!(AccessibleText::of_action(&next).name, "›");
84 let next =
85 next.accessible_name("Próximo registro").accessible_description("Abre o seguinte da lista");
86 let text = AccessibleText::of_action(&next);
87 assert_eq!(text.name, "Próximo registro");
88 assert!(text.renamed && text.says_more());
89 }
90}