Skip to main content

perspective_viewer/components/
export_dropdown.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::rc::Rc;
14
15use session::Session;
16use yew::prelude::*;
17
18use super::containers::dropdown_menu::*;
19use super::modal::{ModalLink, SetModalLink};
20use super::style::StyleProvider;
21use crate::model::*;
22use crate::renderer::*;
23use crate::utils::*;
24use crate::*;
25
26pub type ExportDropDownMenuItem = DropDownMenuItem<ExportFile>;
27
28#[derive(Properties, PartialEq)]
29pub struct ExportDropDownMenuProps {
30    pub renderer: Renderer,
31    pub session: Session,
32    pub callback: Callback<ExportFile>,
33    pub root: web_sys::HtmlElement,
34
35    #[prop_or_default]
36    weak_link: WeakScope<ExportDropDownMenu>,
37}
38
39impl ModalLink<ExportDropDownMenu> for ExportDropDownMenuProps {
40    fn weak_link(&self) -> &'_ utils::WeakScope<ExportDropDownMenu> {
41        &self.weak_link
42    }
43}
44
45pub enum ExportDropDownMenuMsg {
46    TitleChange,
47}
48
49#[derive(Default)]
50pub struct ExportDropDownMenu {
51    title: String,
52    _sub: Option<Subscription>,
53    input_ref: NodeRef,
54    invalid: bool,
55}
56
57impl Component for ExportDropDownMenu {
58    type Message = ExportDropDownMenuMsg;
59    type Properties = ExportDropDownMenuProps;
60
61    fn view(&self, ctx: &Context<Self>) -> yew::virtual_dom::VNode {
62        let callback = ctx.link().callback(|_| ExportDropDownMenuMsg::TitleChange);
63        let plugin = ctx.props().renderer.get_active_plugin().unwrap();
64        // let has_render = js_sys::Reflect::has(&plugin,
65        // js_intern::js_intern!("render")).unwrap();
66        let is_chart = plugin.name().as_str() != "Datagrid";
67        html! {
68            <StyleProvider root={ctx.props().root.clone()}>
69                <span class="dropdown-group-label">{ "Save as" }</span>
70                <input
71                    class={if self.invalid { "invalid" } else { "" }}
72                    oninput={callback}
73                    ref={&self.input_ref}
74                    value={self.title.to_owned()}
75                />
76                <DropDownMenu<ExportFile>
77                    values={Rc::new(get_menu_items(&self.title, is_chart))}
78                    callback={&ctx.props().callback}
79                />
80            </StyleProvider>
81        }
82    }
83
84    fn update(&mut self, _ctx: &Context<Self>, msg: Self::Message) -> bool {
85        match msg {
86            ExportDropDownMenuMsg::TitleChange => {
87                self.title = self
88                    .input_ref
89                    .cast::<web_sys::HtmlInputElement>()
90                    .unwrap()
91                    .value();
92
93                self.invalid = self.title.is_empty();
94                true
95            },
96        }
97    }
98
99    fn create(ctx: &Context<Self>) -> Self {
100        ctx.set_modal_link();
101        let _sub = Some(
102            ctx.props()
103                .renderer
104                .plugin_changed
105                .add_listener(ctx.link().callback(|_| ExportDropDownMenuMsg::TitleChange)),
106        );
107
108        Self {
109            title: ctx
110                .props()
111                .session
112                .get_title()
113                .unwrap_or_else(|| "untitled".to_owned()),
114            _sub,
115            ..Default::default()
116        }
117    }
118}
119
120fn get_menu_items(name: &str, is_chart: bool) -> Vec<ExportDropDownMenuItem> {
121    vec![
122        ExportDropDownMenuItem::OptGroup(
123            "Current View".into(),
124            if is_chart {
125                vec![
126                    ExportMethod::Csv.new_file(name, is_chart),
127                    ExportMethod::Json.new_file(name, is_chart),
128                    ExportMethod::Ndjson.new_file(name, is_chart),
129                    ExportMethod::Arrow.new_file(name, is_chart),
130                    ExportMethod::Html.new_file(name, is_chart),
131                    ExportMethod::Plugin.new_file(name, is_chart),
132                ]
133            } else {
134                vec![
135                    ExportMethod::Csv.new_file(name, is_chart),
136                    ExportMethod::Json.new_file(name, is_chart),
137                    ExportMethod::Ndjson.new_file(name, is_chart),
138                    ExportMethod::Arrow.new_file(name, is_chart),
139                    ExportMethod::Html.new_file(name, is_chart),
140                ]
141            },
142        ),
143        ExportDropDownMenuItem::OptGroup("All".into(), vec![
144            ExportMethod::CsvAll.new_file(name, is_chart),
145            ExportMethod::JsonAll.new_file(name, is_chart),
146            ExportMethod::NdjsonAll.new_file(name, is_chart),
147            ExportMethod::ArrowAll.new_file(name, is_chart),
148        ]),
149        ExportDropDownMenuItem::OptGroup("Config".into(), vec![
150            ExportMethod::JsonConfig.new_file(name, is_chart),
151        ]),
152    ]
153}