use perspective_client::{ViewWindow, clone};
use perspective_js::json;
use perspective_js::utils::{ApiResult, JsValueSerdeExt};
use wasm_bindgen::prelude::*;
use web_sys::*;
use crate::js::JsPerspectiveViewerPlugin;
use crate::presentation::Presentation;
use crate::queries::get_viewer_config;
use crate::renderer::{ColumnConfigMap, Renderer};
use crate::session::Session;
use crate::utils::{AddListener, Subscription};
fn dispatch_event<T: Into<JsValue>>(elem: &HtmlElement, name: &str, event: T) -> ApiResult<()> {
let event_init = web_sys::CustomEventInit::new();
event_init.set_detail(&event.into());
let event = web_sys::CustomEvent::new_with_event_init_dict(
format!("perspective-{}", name).as_str(),
&event_init,
)?;
elem.dispatch_event(&event)?;
Ok(())
}
fn dispatch_column_settings_open_changed(
elem: &HtmlElement,
open: bool,
column_name: Option<String>,
) {
let event_init = web_sys::CustomEventInit::new();
event_init.set_detail(&JsValue::from(
json!({"open": open, "column_name": column_name}),
));
let event = web_sys::CustomEvent::new_with_event_init_dict(
"perspective-toggle-column-settings",
&event_init,
);
elem.dispatch_event(&event.unwrap()).unwrap();
}
fn dispatch_plugin_changed(elem: &HtmlElement, plugin: &JsPerspectiveViewerPlugin) {
let event_init = web_sys::CustomEventInit::new();
event_init.set_detail(plugin);
let event =
web_sys::CustomEvent::new_with_event_init_dict("perspective-plugin-update", &event_init);
elem.dispatch_event(&event.unwrap()).unwrap();
}
fn dispatch_config_update(
elem: &HtmlElement,
session: &Session,
renderer: &Renderer,
presentation: &Presentation,
) {
clone!(session, renderer, presentation);
let elem = elem.clone();
perspective_js::utils::ApiFuture::spawn(async move {
let viewer_config = get_viewer_config(&session, &renderer, &presentation).await?;
if viewer_config.view_config != Default::default()
&& Some(&viewer_config) != presentation.last_dispatched_config.borrow().as_ref()
{
let json_config = JsValue::from_serde_ext(&viewer_config)?;
let event_init = web_sys::CustomEventInit::new();
event_init.set_detail(&json_config);
let event = web_sys::CustomEvent::new_with_event_init_dict(
"perspective-config-update",
&event_init,
);
*presentation.last_dispatched_config.borrow_mut() = Some(viewer_config);
elem.dispatch_event(&event.unwrap()).unwrap();
}
Ok(())
});
}
pub fn wire_custom_events(
elem: &HtmlElement,
session: &Session,
renderer: &Renderer,
presentation: &Presentation,
) -> Vec<Subscription> {
let theme_sub = presentation.theme_config_updated.add_listener({
clone!(elem, session, renderer, presentation);
move |_| dispatch_config_update(&elem, &session, &renderer, &presentation)
});
let settings_sub = presentation.settings_open_changed.add_listener({
clone!(elem, session, renderer, presentation);
move |open: bool| {
dispatch_event(&elem, "toggle-settings", open).unwrap();
dispatch_config_update(&elem, &session, &renderer, &presentation);
}
});
let before_settings_sub = presentation.settings_before_open_changed.add_listener({
clone!(elem);
move |open: bool| {
dispatch_event(&elem, "toggle-settings-before", open).unwrap();
}
});
let column_settings_sub = presentation.column_settings_open_changed.add_listener({
clone!(elem);
move |(open, column_name)| {
dispatch_column_settings_open_changed(&elem, open, column_name);
}
});
let plugin_sub = renderer.plugin_changed.add_listener({
clone!(elem, session, renderer, presentation);
move |plugin| {
dispatch_plugin_changed(&elem, &plugin);
dispatch_config_update(&elem, &session, &renderer, &presentation);
}
});
let view_sub = session.view_created.add_listener({
clone!(elem, session, renderer, presentation);
move |_| dispatch_config_update(&elem, &session, &renderer, &presentation)
});
let title_sub = session.title_changed.add_listener({
clone!(elem, session, renderer, presentation);
move |_| dispatch_config_update(&elem, &session, &renderer, &presentation)
});
let unload_sub = session.table_unloaded.add_listener({
clone!(elem);
move |x: bool| {
if !x {
dispatch_event(&elem, "table-delete-before", JsValue::UNDEFINED).unwrap();
} else {
dispatch_event(&elem, "table-delete", JsValue::UNDEFINED).unwrap()
}
}
});
let select_sub = renderer.selection_changed.add_listener({
clone!(elem, session, renderer, presentation);
move |window: Option<ViewWindow>| {
let detail = JsValue::from_serde_ext(&window).unwrap();
dispatch_event(&elem, "select", &detail).unwrap();
dispatch_config_update(&elem, &session, &renderer, &presentation);
}
});
let column_style_sub = renderer.column_style_changed.add_listener({
clone!(elem, session, renderer, presentation);
move |cfg: ColumnConfigMap| {
let detail = JsValue::from_serde_ext(&cfg).unwrap();
dispatch_event(&elem, "column-style-change", &detail).unwrap();
dispatch_config_update(&elem, &session, &renderer, &presentation);
}
});
let status_click_sub = session.status_indicator_clicked.add_listener({
clone!(elem);
move |_| dispatch_event(&elem, "status-indicator-click", JsValue::UNDEFINED).unwrap()
});
let statusbar_ptr_sub = presentation.statusbar_pointer_event.add_listener({
clone!(elem);
move |event: PointerEvent| {
dispatch_event(&elem, &format!("statusbar-{}", event.type_()), &event).unwrap();
}
});
vec![
theme_sub,
before_settings_sub,
settings_sub,
column_settings_sub,
plugin_sub,
view_sub,
title_sub,
unload_sub,
select_sub,
column_style_sub,
status_click_sub,
statusbar_ptr_sub,
]
}