use std::path::PathBuf; use std::{io, io::Write}; use web_sys::js_sys::Array; use web_sys::wasm_bindgen::{JsCast, JsValue}; use web_sys::{Blob, BlobPropertyBag, HtmlAnchorElement, HtmlCanvasElement, Url}; pub fn get_canvas_element() -> Option { let document = web_sys::window()?.document()?; let canvas = document.get_element_by_id("nodetoy")?; canvas.dyn_into::().ok() } pub struct DownloadFile { data: Vec, filename: PathBuf, options: BlobPropertyBag, } impl DownloadFile { pub fn new(filename: PathBuf, mime_type: &str) -> Self { let options = BlobPropertyBag::new(); options.set_type(mime_type); Self { data: Vec::new(), filename, options, } } pub fn save(&self) -> Result<(), JsValue> { let string = unsafe { str::from_utf8_unchecked(&self.data) }; let parts = Array::of1(&JsValue::from_str(string)); let blob = Blob::new_with_str_sequence_and_options(&parts, &self.options)?; let url = Url::create_object_url_with_blob(&blob)?; let document = web_sys::window().unwrap().document().unwrap(); let a: HtmlAnchorElement = document.create_element("a")?.dyn_into()?; a.set_href(&url); a.set_download(&self.filename.as_os_str().to_string_lossy()); a.click(); Url::revoke_object_url(&url)?; Ok(()) } } impl Write for DownloadFile { fn write(&mut self, buf: &[u8]) -> io::Result { self.data.write(buf) } fn flush(&mut self) -> io::Result<()> { self.data.flush() } } impl Drop for DownloadFile { fn drop(&mut self) { self.save().unwrap() } }