Skip to main content

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::column_dropdown::ColumnDropDownElement;
20
21#[derive(Properties)]
22pub struct EmptyColumnProps {
23    /// The autocomplete dropdown element.
24    pub column_dropdown: ColumnDropDownElement,
25
26    /// Values to exclude from autocomplete
27    pub exclude: HashSet<String>,
28
29    /// Fires when a value is selected.
30    pub on_select: Callback<InPlaceColumn>,
31}
32
33impl PartialEq for EmptyColumnProps {
34    fn eq(&self, _other: &Self) -> bool {
35        false
36    }
37}
38
39#[derive(Clone, Debug, PartialEq)]
40pub enum InPlaceColumn {
41    Column(String),
42    Expression(Expression<'static>),
43}
44
45pub enum EmptyColumnMsg {
46    KeyDown(u32),
47    Blur,
48    Input,
49}
50
51use EmptyColumnMsg::*;
52
53#[derive(Default)]
54pub struct EmptyColumn {
55    input_ref: NodeRef,
56}
57
58impl Component for EmptyColumn {
59    type Message = EmptyColumnMsg;
60    type Properties = EmptyColumnProps;
61
62    fn view(&self, ctx: &Context<Self>) -> Html {
63        let onblur = ctx.link().callback(|_| Blur);
64        let oninput = ctx.link().callback(|_| Input);
65        let onkeydown = ctx
66            .link()
67            .callback(|event: KeyboardEvent| KeyDown(event.key_code()));
68
69        html! {
70            <div class="pivot-column column-empty">
71                <input
72                    spellcheck="false"
73                    ref={self.input_ref.clone()}
74                    {onblur}
75                    {onkeydown}
76                    {oninput}
77                    class="column-empty-input"
78                />
79            </div>
80        }
81    }
82
83    fn changed(&mut self, _ctx: &Context<Self>, _old_props: &Self::Properties) -> bool {
84        if let Some(elem) = self.input_ref.cast::<HtmlInputElement>() {
85            elem.blur().unwrap();
86        }
87
88        false
89    }
90
91    fn destroy(&mut self, ctx: &Context<Self>) {
92        ctx.props().column_dropdown.hide().unwrap();
93    }
94
95    fn update(&mut self, ctx: &Context<Self>, msg: Self::Message) -> bool {
96        match msg {
97            Blur => {
98                ctx.props().column_dropdown.hide().unwrap();
99                if let Some(elem) = self.input_ref.cast::<HtmlInputElement>() {
100                    elem.set_value("");
101                }
102
103                false
104            },
105            KeyDown(40) => {
106                ctx.props().column_dropdown.item_down();
107                false
108            },
109            KeyDown(38) => {
110                ctx.props().column_dropdown.item_up();
111                false
112            },
113            KeyDown(13) => {
114                ctx.props().column_dropdown.item_select();
115                ctx.props().column_dropdown.hide().unwrap();
116                false
117            },
118            KeyDown(_) => false,
119            Input => {
120                if let Some(elem) = self.input_ref.cast::<HtmlInputElement>() {
121                    ctx.props().column_dropdown.autocomplete(
122                        elem,
123                        ctx.props().exclude.clone(),
124                        ctx.props().on_select.clone(),
125                    );
126                }
127
128                false
129            },
130        }
131    }
132
133    fn create(_ctx: &Context<Self>) -> Self {
134        Self::default()
135    }
136}