use super::WebDocument;
use crate::text_validation::text_value;
use js_sys::Reflect;
use std::{future::Future, io};
use wasm_bindgen::{JsCast, JsValue};
use wasm_bindgen_futures::JsFuture;
use web_sys::{Clipboard, Navigator};
#[derive(Clone)]
pub struct WebClipboard {
clipboard: Clipboard,
}
pub(super) fn from_document(document: &WebDocument) -> io::Result<WebClipboard> {
let window = document
.document
.default_view()
.ok_or_else(|| unsupported("Browser document has no Window"))?;
let navigator: Navigator = window.navigator();
let value = Reflect::get(navigator.as_ref(), &JsValue::from_str("clipboard"))
.map_err(|_| unsupported("Browser clipboard API lookup failed"))?;
let clipboard = value
.dyn_into::<Clipboard>()
.map_err(|_| unsupported("Browser clipboard API is unavailable"))?;
Ok(WebClipboard { clipboard })
}
impl WebClipboard {
pub fn read_text(&self) -> impl Future<Output = io::Result<String>> + 'static {
let read = JsFuture::from(self.clipboard.read_text());
async move {
let value = read
.await
.map_err(|_| clipboard_error("Browser clipboard read was rejected"))?;
let text = value
.as_string()
.ok_or_else(|| clipboard_error("Browser clipboard returned non-text data"))?;
text_value(text)
}
}
pub fn write_text(
&self,
text: &str,
) -> io::Result<impl Future<Output = io::Result<()>> + 'static> {
let text = text_value(text.to_owned())?;
let write = JsFuture::from(self.clipboard.write_text(&text));
Ok(async move {
write
.await
.map(|_| ())
.map_err(|_| clipboard_error("Browser clipboard write was rejected"))
})
}
}
fn unsupported(message: &'static str) -> io::Error {
io::Error::new(io::ErrorKind::Unsupported, message)
}
fn clipboard_error(message: &'static str) -> io::Error {
io::Error::other(message)
}