perspective_viewer/components/
export_dropdown.rs1use std::rc::Rc;
14
15use presentation::Presentation;
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 presentation: Presentation,
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
45#[derive(Default)]
46pub struct ExportDropDownMenu {
47 title: String,
48 _sub: Option<Subscription>,
49 input_ref: NodeRef,
50 invalid: bool,
51}
52
53pub enum ExportDropDownMenuMsg {
54 TitleChange,
55}
56
57fn get_menu_items(name: &str, is_chart: bool) -> Vec<ExportDropDownMenuItem> {
58 vec![
59 ExportDropDownMenuItem::OptGroup(
60 "Current View".into(),
61 if is_chart {
62 vec![
63 ExportMethod::Csv.new_file(name, is_chart),
64 ExportMethod::Json.new_file(name, is_chart),
65 ExportMethod::Ndjson.new_file(name, is_chart),
66 ExportMethod::Arrow.new_file(name, is_chart),
67 ExportMethod::Html.new_file(name, is_chart),
68 ExportMethod::Plugin.new_file(name, is_chart),
69 ]
70 } else {
71 vec![
72 ExportMethod::Csv.new_file(name, is_chart),
73 ExportMethod::Json.new_file(name, is_chart),
74 ExportMethod::Ndjson.new_file(name, is_chart),
75 ExportMethod::Arrow.new_file(name, is_chart),
76 ExportMethod::Html.new_file(name, is_chart),
77 ]
78 },
79 ),
80 ExportDropDownMenuItem::OptGroup("All".into(), vec![
81 ExportMethod::CsvAll.new_file(name, is_chart),
82 ExportMethod::JsonAll.new_file(name, is_chart),
83 ExportMethod::NdjsonAll.new_file(name, is_chart),
84 ExportMethod::ArrowAll.new_file(name, is_chart),
85 ]),
86 ExportDropDownMenuItem::OptGroup("Config".into(), vec![
87 ExportMethod::JsonConfig.new_file(name, is_chart),
88 ]),
89 ]
90}
91
92impl Component for ExportDropDownMenu {
93 type Message = ExportDropDownMenuMsg;
94 type Properties = ExportDropDownMenuProps;
95
96 fn view(&self, ctx: &Context<Self>) -> yew::virtual_dom::VNode {
97 let callback = ctx.link().callback(|_| ExportDropDownMenuMsg::TitleChange);
98 let plugin = ctx.props().renderer.get_active_plugin().unwrap();
99 let is_chart = plugin.name().as_str() != "Datagrid";
102 html! {
103 <StyleProvider root={ctx.props().root.clone()}>
104 <span class="dropdown-group-label">{ "Save as" }</span>
105 <input
106 class={if self.invalid { "invalid" } else { "" }}
107 oninput={callback}
108 ref={&self.input_ref}
109 value={self.title.to_owned()}
110 />
111 <DropDownMenu<ExportFile>
112 values={Rc::new(get_menu_items(&self.title, is_chart))}
113 callback={&ctx.props().callback}
114 />
115 </StyleProvider>
116 }
117 }
118
119 fn update(&mut self, _ctx: &Context<Self>, msg: Self::Message) -> bool {
120 match msg {
121 ExportDropDownMenuMsg::TitleChange => {
122 self.title = self
123 .input_ref
124 .cast::<web_sys::HtmlInputElement>()
125 .unwrap()
126 .value();
127
128 self.invalid = self.title.is_empty();
129 true
130 },
131 }
132 }
133
134 fn create(ctx: &Context<Self>) -> Self {
135 ctx.set_modal_link();
136 let _sub = Some(
137 ctx.props()
138 .renderer
139 .plugin_changed
140 .add_listener(ctx.link().callback(|_| ExportDropDownMenuMsg::TitleChange)),
141 );
142
143 Self {
144 title: ctx
145 .props()
146 .presentation
147 .get_title()
148 .unwrap_or_else(|| "untitled".to_owned()),
149 _sub,
150 ..Default::default()
151 }
152 }
153}