use gloo::{events::EventListener, timers::callback::Timeout}; use web_sys::{Element, HtmlElement, HtmlImageElement}; use crate::utils::{SelectorExt, by_id, selector_and_clone}; pub enum Level { Success, Error, Info, Warning, Unknown, } const TIME_ANIMATION: u32 = 500; // [ms]. const TIME_DISPLAYED: u32 = 5_000; // [ms]. pub fn show_message(message: &str) { show_message_level(Level::Unknown, message); } pub fn show_message_level(level: Level, message: &str) { show_message_content(level, Content::Message(message)) } pub fn show_element_level(level: Level, selector: &str) { show_element_level_and_initialize(level, selector, |_| {}) } pub fn show_element_level_and_initialize(level: Level, selector: &str, initializer: T) where T: Fn(Element), { let content_element: Element = selector_and_clone(selector); initializer(content_element.clone()); show_message_content(level, Content::Element(content_element)) } enum Content<'a> { Message(&'a str), Element(Element), } fn show_message_content(level: Level, content: Content) { let toast_element: HtmlElement = selector_and_clone("#toasts .toast"); let toast_icon: HtmlImageElement = toast_element.selector(".icon"); let toast_content: HtmlElement = toast_element.selector(".content"); match level { Level::Success => toast_icon.set_src("/static/success.svg"), Level::Error => toast_icon.set_src("/static/error.svg"), Level::Info => toast_icon.set_src("/static/info.svg"), Level::Warning => toast_icon.set_src("/static/warning.svg"), Level::Unknown => toast_icon.remove(), } match content { Content::Message(message) => toast_content.set_inner_html(message), Content::Element(element) => { let _ = toast_content.append_child(&element); } } toast_element.style().set_css_text(&format!( "display: block; animation: fadein {}ms, fadeout {}ms {}ms;", TIME_ANIMATION, TIME_ANIMATION, TIME_DISPLAYED )); // FIXME: Here the two events will leak memory. How to fix that? // Save them in a global vec variable and remove them manually? let close_button: HtmlElement = toast_element.selector(".close"); let toast_element_cloned = toast_element.clone(); EventListener::once(&close_button, "click", move |_event| { toast_element_cloned.remove(); }) .forget(); let toasts: HtmlElement = by_id("toasts"); toasts.append_child(&toast_element).unwrap(); Timeout::new(TIME_DISPLAYED, move || { toast_element.remove(); }) .forget(); }