awsm_web/file/
save.rs

1use js_sys::Uint8Array;
2use wasm_bindgen::{prelude::*, JsCast};
3
4pub fn save_file(data: &[u8], filename: &str, mime_type: Option<&str>) -> Result<(), JsValue> {
5    // cannot use .view() because the WASM memory changes under our feet
6    let content = Uint8Array::new_with_length(data.len() as u32);
7    content.copy_from(data);
8    
9    let blob_parts = js_sys::Array::new();
10    blob_parts.push(&content);
11
12    let blob = match mime_type {
13        Some(mime_type) => {
14            let mut blob_options = web_sys::BlobPropertyBag::new();
15            blob_options.type_(mime_type);
16            web_sys::Blob::new_with_u8_array_sequence_and_options(&blob_parts, &blob_options)?
17        },
18        None => {
19            web_sys::Blob::new_with_u8_array_sequence(&blob_parts)?
20        }
21    };
22
23    let blob_url = web_sys::Url::create_object_url_with_blob(&blob)?;
24
25    let document = web_sys::window().unwrap().document().unwrap();
26
27    let elem:web_sys::HtmlAnchorElement = document.create_element("a")?.unchecked_into();
28
29    elem.set_attribute("href", &blob_url)?;
30    elem.set_attribute("download", filename)?;
31
32    let body = document.body().ok_or_else(|| JsValue::from_str("unable to get document body"))?;
33    body.append_child(&elem)?;
34
35    elem.click();
36
37    body.remove_child(&elem)?;
38
39    web_sys::Url::revoke_object_url(&blob_url)?;
40
41    Ok(())
42}