Your browser sucks, JavaScript disabled! Gunnar's console needs JavaScript and WebAssembly. Git over SSH on port 2222 does not.

nordisk/holger-ui

src/webio.rs

//! Browser-side I/O helpers (wasm-only): file reads and named downloads.

use wasm_bindgen::JsCast;

/// Hand the bytes to the browser as a named download via a temporary object
/// URL. The URL is revoked immediately after the click — the blob lives on
/// until the download completes.
pub fn save_bytes(file_name: &str, data: &[u8], content_type: &str) -> Result<(), String> {
    let array = js_sys::Uint8Array::from(data);
    let parts = js_sys::Array::of1(&array.buffer());
    let opts = web_sys::BlobPropertyBag::new();
    if !content_type.is_empty() {
        opts.set_type(content_type);
    }
    let blob = web_sys::Blob::new_with_buffer_source_sequence_and_options(&parts, &opts)
        .map_err(|_| "blob construction failed")?;
    let url = web_sys::Url::create_object_url_with_blob(&blob)
        .map_err(|_| "object URL creation failed")?;
    let document = web_sys::window()
        .and_then(|w| w.document())
        .ok_or("no document")?;
    let a: web_sys::HtmlAnchorElement = document
        .create_element("a")
        .map_err(|_| "createElement failed")?
        .dyn_into()
        .map_err(|_| "anchor cast failed")?;
    a.set_href(&url);
    a.set_download(file_name);
    a.click();
    let _ = web_sys::Url::revoke_object_url(&url);
    Ok(())
}

/// Read the picked file's bytes off the main thread via `File.arrayBuffer()`.
pub async fn read_file(file: &web_sys::File) -> Result<Vec<u8>, String> {
    let buf = wasm_bindgen_futures::JsFuture::from(file.array_buffer())
        .await
        .map_err(|_| "arrayBuffer() rejected")?;
    Ok(js_sys::Uint8Array::new(&buf).to_vec())
}

/// Set the browser-tab title — every routed view names itself.
pub fn set_title(title: &str) {
    if let Some(doc) = web_sys::window().and_then(|w| w.document()) {
        doc.set_title(&format!("{title} · holger console"));
    }
}

/// Local wall-clock HH:MM:SS — mutation results carry WHEN they happened.
pub fn now_hms() -> String {
    let d = js_sys::Date::new_0();
    format!(
        "{:02}:{:02}:{:02}",
        d.get_hours(),
        d.get_minutes(),
        d.get_seconds()
    )
}

/// Put text on the clipboard (async Clipboard API; falls back to a rejected
/// future outside secure contexts — the caller reports, never panics).
pub async fn copy_text(text: &str) -> Result<(), String> {
    let clipboard = web_sys::window()
        .map(|w| w.navigator().clipboard())
        .ok_or("no window")?;
    wasm_bindgen_futures::JsFuture::from(clipboard.write_text(text))
        .await
        .map(|_| ())
        .map_err(|_| "clipboard write refused (needs a secure context)".to_string())
}