use std::cell::RefCell;
use std::rc::Rc;
use perspective_js::utils::global;
use wasm_bindgen::prelude::*;
use wasm_bindgen_futures::spawn_local;
use web_sys::*;
use yew::prelude::*;
use super::viewer::PerspectiveViewerElement;
use crate::components::copy_dropdown::CopyDropDownMenu;
use crate::components::portal::PortalModal;
use crate::components::style::StyleProvider;
use crate::js::*;
use crate::renderer::*;
use crate::tasks::*;
use crate::utils::*;
use crate::*;
type TargetState = Rc<RefCell<Option<HtmlElement>>>;
#[derive(Properties, PartialEq)]
struct CopyDropDownWrapperProps {
renderer: Renderer,
callback: Callback<ExportFile>,
target: TargetState,
custom_element: HtmlElement,
#[prop_or_default]
theme: String,
}
enum CopyDropDownWrapperMsg {
Open,
Close,
}
struct CopyDropDownWrapper {
target: Option<HtmlElement>,
}
impl Component for CopyDropDownWrapper {
type Message = CopyDropDownWrapperMsg;
type Properties = CopyDropDownWrapperProps;
fn create(_ctx: &Context<Self>) -> Self {
Self { target: None }
}
fn update(&mut self, ctx: &Context<Self>, msg: Self::Message) -> bool {
match msg {
CopyDropDownWrapperMsg::Open => {
self.target = ctx.props().target.borrow().clone();
true
},
CopyDropDownWrapperMsg::Close => {
self.target = None;
true
},
}
}
fn view(&self, ctx: &Context<Self>) -> Html {
let on_close = ctx.link().callback(|_| CopyDropDownWrapperMsg::Close);
html! {
<StyleProvider root={ctx.props().custom_element.clone()}>
<PortalModal
tag_name="perspective-copy-menu"
target={self.target.clone()}
own_focus=true
{on_close}
theme={ctx.props().theme.clone()}
>
<CopyDropDownMenu
renderer={ctx.props().renderer.clone()}
callback={ctx.props().callback.clone()}
/>
</PortalModal>
</StyleProvider>
}
}
}
#[wasm_bindgen]
#[derive(Clone)]
pub struct CopyDropDownMenuElement {
elem: HtmlElement,
target: TargetState,
root: Rc<RefCell<Option<AppHandle<CopyDropDownWrapper>>>>,
}
impl CustomElementMetadata for CopyDropDownMenuElement {
const CUSTOM_ELEMENT_NAME: &'static str = "perspective-copy-menu";
}
#[wasm_bindgen]
impl CopyDropDownMenuElement {
#[wasm_bindgen(constructor)]
pub fn new(elem: HtmlElement) -> Self {
Self {
elem,
target: Default::default(),
root: Default::default(),
}
}
pub fn open(&self, target: HtmlElement) {
*self.target.borrow_mut() = Some(target);
if let Some(root) = self.root.borrow().as_ref() {
root.send_message(CopyDropDownWrapperMsg::Open);
}
}
pub fn hide(&self) -> ApiResult<()> {
if let Some(root) = self.root.borrow().as_ref() {
root.send_message(CopyDropDownWrapperMsg::Close);
}
Ok(())
}
pub fn __set_model(&self, parent: &PerspectiveViewerElement) {
self.set_config_model(parent)
}
pub fn connected_callback(&self) {}
}
impl CopyDropDownMenuElement {
pub fn new_from_model<A>(model: &A) -> Self
where
A: GetViewerConfigModel + StateProvider,
<A as StateProvider>::State: HasPresentation + HasRenderer + HasSession,
{
let dropdown = global::document()
.create_element("perspective-copy-menu")
.unwrap()
.unchecked_into::<HtmlElement>();
let elem = Self::new(dropdown);
elem.set_config_model(model);
elem
}
pub fn set_config_model<A>(&self, model: &A)
where
A: GetViewerConfigModel + StateProvider,
<A as StateProvider>::State: HasPresentation + HasRenderer + HasSession,
{
let callback = Callback::from({
let model = model.clone_state();
let target = self.target.clone();
let root = self.root.clone();
move |x: ExportFile| {
let model = model.clone();
let target = target.clone();
let root = root.clone();
spawn_local(async move {
let mime = x.method.mimetype(x.is_chart);
let task = model.export_method_to_blob(x.method);
let result = copy_to_clipboard(task, mime).await;
crate::maybe_log!({
result?;
*target.borrow_mut() = None;
if let Some(root) = root.borrow().as_ref() {
root.send_message(CopyDropDownWrapperMsg::Close);
}
})
})
}
});
let renderer = model.renderer().clone();
let init = ShadowRootInit::new(ShadowRootMode::Open);
let shadow_root = self
.elem
.attach_shadow(&init)
.unwrap()
.unchecked_into::<Element>();
let props = yew::props!(CopyDropDownWrapperProps {
renderer,
callback,
target: self.target.clone(),
custom_element: self.elem.clone()
});
let handle = yew::Renderer::with_root_and_props(shadow_root, props).render();
*self.root.borrow_mut() = Some(handle);
}
}