perspective_viewer/components/column_selector/
empty_column.rs

1// ┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓
2// ┃ ██████ ██████ ██████       █      █      █      █      █ █▄  ▀███ █       ┃
3// ┃ ▄▄▄▄▄█ █▄▄▄▄▄ ▄▄▄▄▄█  ▀▀▀▀▀█▀▀▀▀▀ █ ▀▀▀▀▀█ ████████▌▐███ ███▄  ▀█ █ ▀▀▀▀▀ ┃
4// ┃ █▀▀▀▀▀ █▀▀▀▀▀ █▀██▀▀ ▄▄▄▄▄ █ ▄▄▄▄▄█ ▄▄▄▄▄█ ████████▌▐███ █████▄   █ ▄▄▄▄▄ ┃
5// ┃ █      ██████ █  ▀█▄       █ ██████      █      ███▌▐███ ███████▄ █       ┃
6// ┣━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┫
7// ┃ Copyright (c) 2017, the Perspective Authors.                              ┃
8// ┃ ╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌ ┃
9// ┃ This file is part of the Perspective library, distributed under the terms ┃
10// ┃ of the [Apache License 2.0](https://www.apache.org/licenses/LICENSE-2.0). ┃
11// ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛
12
13use std::collections::HashSet;
14
15use perspective_client::config::Expression;
16use web_sys::*;
17use yew::prelude::*;
18
19use crate::components::style::LocalStyle;
20use crate::css;
21use crate::custom_elements::ColumnDropDownElement;
22
23#[derive(Default)]
24pub struct EmptyColumn {
25    input_ref: NodeRef,
26}
27
28#[derive(Clone, Debug)]
29pub enum InPlaceColumn {
30    Column(String),
31    Expression(Expression<'static>),
32}
33
34#[derive(Properties)]
35pub struct EmptyColumnProps {
36    pub column_dropdown: ColumnDropDownElement,
37    pub exclude: HashSet<String>,
38    pub on_select: Callback<InPlaceColumn>,
39}
40
41impl PartialEq for EmptyColumnProps {
42    fn eq(&self, _other: &Self) -> bool {
43        false
44    }
45}
46
47pub enum EmptyColumnMsg {
48    KeyDown(u32),
49    Blur,
50    Input,
51}
52
53use EmptyColumnMsg::*;
54
55impl Component for EmptyColumn {
56    type Message = EmptyColumnMsg;
57    type Properties = EmptyColumnProps;
58
59    fn view(&self, ctx: &Context<Self>) -> Html {
60        let onblur = ctx.link().callback(|_| Blur);
61        let oninput = ctx.link().callback(|_| Input);
62        let onkeydown = ctx
63            .link()
64            .callback(|event: KeyboardEvent| KeyDown(event.key_code()));
65
66        html! {
67            <div class="pivot-column column-empty">
68                <LocalStyle href={css!("empty-column")} />
69                <input
70                    spellcheck="false"
71                    ref={self.input_ref.clone()}
72                    {onblur}
73                    {onkeydown}
74                    {oninput}
75                    class="column-empty-input"
76                />
77            </div>
78        }
79    }
80
81    fn changed(&mut self, _ctx: &Context<Self>, _old_props: &Self::Properties) -> bool {
82        if let Some(elem) = self.input_ref.cast::<HtmlInputElement>() {
83            elem.blur().unwrap();
84        }
85
86        false
87    }
88
89    fn destroy(&mut self, ctx: &Context<Self>) {
90        ctx.props().column_dropdown.hide().unwrap();
91    }
92
93    fn update(&mut self, ctx: &Context<Self>, msg: Self::Message) -> bool {
94        match msg {
95            Blur => {
96                ctx.props().column_dropdown.hide().unwrap();
97                if let Some(elem) = self.input_ref.cast::<HtmlInputElement>() {
98                    elem.set_value("");
99                }
100
101                false
102            },
103            KeyDown(40) => {
104                ctx.props().column_dropdown.item_down();
105                false
106            },
107            KeyDown(38) => {
108                ctx.props().column_dropdown.item_up();
109                false
110            },
111            KeyDown(13) => {
112                ctx.props().column_dropdown.item_select();
113                ctx.props().column_dropdown.hide().unwrap();
114                false
115            },
116            KeyDown(_) => false,
117            Input => {
118                if let Some(elem) = self.input_ref.cast::<HtmlInputElement>() {
119                    ctx.props().column_dropdown.autocomplete(
120                        elem,
121                        ctx.props().exclude.clone(),
122                        ctx.props().on_select.clone(),
123                    );
124                }
125
126                false
127            },
128        }
129    }
130
131    fn create(_ctx: &Context<Self>) -> Self {
132        Self::default()
133    }
134}