perspective_viewer/components/
column_dropdown.rs1use web_sys::*;
14use yew::prelude::*;
15
16use super::column_selector::InPlaceColumn;
17use super::modal::*;
18use crate::utils::WeakScope;
19
20static CSS: &str = include_str!(concat!(env!("OUT_DIR"), "/css/column-dropdown.css"));
21
22pub enum ColumnDropDownMsg {
23 SetValues(Vec<InPlaceColumn>, f64),
24 SetCallback(Callback<InPlaceColumn>),
25 ItemDown,
26 ItemUp,
27 ItemSelect,
28}
29
30pub struct ColumnDropDown {
31 values: Option<Vec<InPlaceColumn>>,
32 selected: usize,
33 width: f64,
34 on_select: Option<Callback<InPlaceColumn>>,
35}
36
37#[derive(Properties, PartialEq)]
38pub struct ColumnDropDownProps {
39 #[prop_or_default]
40 pub weak_link: WeakScope<ColumnDropDown>,
41}
42
43impl ModalLink<ColumnDropDown> for ColumnDropDownProps {
44 fn weak_link(&self) -> &'_ WeakScope<ColumnDropDown> {
45 &self.weak_link
46 }
47}
48
49impl Component for ColumnDropDown {
50 type Message = ColumnDropDownMsg;
51 type Properties = ColumnDropDownProps;
52
53 fn create(ctx: &Context<Self>) -> Self {
54 ctx.set_modal_link();
55 Self {
56 values: Some(vec![]),
57 selected: 0,
58 width: 0.0,
59 on_select: None,
60 }
61 }
62
63 fn update(&mut self, _ctx: &Context<Self>, msg: Self::Message) -> bool {
64 match msg {
65 ColumnDropDownMsg::SetCallback(callback) => {
66 self.on_select = Some(callback);
67 false
68 },
69 ColumnDropDownMsg::SetValues(values, width) => {
70 self.values = Some(values);
71 self.selected = 0;
72 self.width = width;
73 true
74 },
75 ColumnDropDownMsg::ItemSelect => {
76 if let Some(ref values) = self.values {
77 match values.get(self.selected) {
78 None => {
79 console::error_1(&"Selected out-of-bounds".into());
80 false
81 },
82 Some(x) => {
83 self.on_select.as_ref().unwrap().emit(x.clone());
84 false
85 },
86 }
87 } else {
88 console::error_1(&"No Values".into());
89 false
90 }
91 },
92 ColumnDropDownMsg::ItemDown => {
93 self.selected += 1;
94 if let Some(ref values) = self.values {
95 if self.selected >= values.len() {
96 self.selected = 0;
97 };
98 };
99
100 true
101 },
102 ColumnDropDownMsg::ItemUp => {
103 if let Some(ref values) = self.values {
104 if self.selected < 1 {
105 self.selected = values.len();
106 }
107 }
108
109 self.selected -= 1;
110 true
111 },
112 }
113 }
114
115 fn changed(&mut self, _ctx: &Context<Self>, _old: &Self::Properties) -> bool {
116 false
117 }
118
119 fn view(&self, _ctx: &Context<Self>) -> Html {
120 let body = html! {
121 if let Some(ref values) = self.values {
122 if !values.is_empty() {
123 { for values
124 .iter()
125 .enumerate()
126 .map(|(idx, value)| {
127 let click = self.on_select.as_ref().unwrap().reform({
128 let value = value.clone();
129 move |_: MouseEvent| value.clone()
130 });
131
132 let row = match value {
133 InPlaceColumn::Column(col) => html! {
134 <span>{ col }</span>
135 },
136 InPlaceColumn::Expression(col) => html! {
137 <span id="add-expression">{ col.name.clone() }</span>
138 },
139 };
140
141 html! {
142 if idx == self.selected {
143 <span onmousedown={ click } class="selected">{ row }</span>
144 } else {
145 <span onmousedown={ click }>{ row }</span>
146 }
147 }
148 }) }
149 } else {
150 <span class="no-results" />
151 }
152 }
153 };
154
155 let position = format!(
156 ":host{{min-width:{}px;max-width:{}px}}",
157 self.width, self.width
158 );
159
160 html! { <><style>{ &CSS }</style><style>{ position }</style>{ body }</> }
161 }
162}