Files
galaxy/crates/galaxyui/src/windowing/winit/wasm.rs
T

98 lines
3.4 KiB
Rust

use crate::{clipboard::ClipboardContent, Clipboard};
use js_sys::{Array, Object};
use wasm_bindgen::{self, prelude::*, JsCast};
use web_sys::{Blob, BlobPropertyBag};
pub struct WebClipboard {
inner: web_sys::Clipboard,
saved_content: ClipboardContent,
}
impl WebClipboard {
pub fn new() -> Self {
Self {
inner: gloo::utils::window().navigator().clipboard(),
saved_content: Default::default(),
}
}
}
impl Default for WebClipboard {
fn default() -> Self {
Self::new()
}
}
impl Clipboard for WebClipboard {
fn write(&mut self, contents: ClipboardContent) {
match create_item_list(&contents) {
Ok(item_list) => {
// This returns a Promise, which succeeds iff the copy succeeds. There's nothing we can do
// if the copy fails, though, and this API doesn't support async, so we just ignore the
// promise. It's not necessary to hold a reference to the promise for the copy to succeed.
let _ = self.inner.write(&item_list);
}
Err(error) => {
// Fall back to just writing plain text.
// ClipboardItems are not supported in Firefox yet.
log::warn!("Failed to construct clipboard data: {error:?}");
let _ = self.inner.write_text(&contents.plain_text);
}
}
}
fn read(&mut self) -> ClipboardContent {
std::mem::take(&mut self.saved_content)
}
fn save(&mut self, content: ClipboardContent) {
self.saved_content = content;
}
}
fn create_item_list(contents: &ClipboardContent) -> Result<Array, JsValue> {
// The Clipboard.write method
// (https://developer.mozilla.org/en-US/docs/Web/API/Clipboard/write)
// requires an array of ClipboardItem objects
// (https://developer.mozilla.org/en-US/docs/Web/API/ClipboardItem).
// This function constructs a single element array containing a ClipboardItem, which contains
// both plain text and html data that's being copied.
let items = Object::new();
// We always have plain text data.
let text_blob = create_blob(&contents.plain_text, "text/plain")?;
js_sys::Reflect::set(&items, &JsValue::from_str("text/plain"), &text_blob)?;
// We sometimes have html data.
if let Some(html) = &contents.html {
let html_blob = create_blob(html, "text/html")?;
js_sys::Reflect::set(&items, &JsValue::from_str("text/html"), &html_blob)?;
}
// web_sys doesn't have this constructor, so we have to do things the hard way.
let clipboard_item_constructor: js_sys::Function = js_sys::Reflect::get(
&JsValue::from(gloo::utils::window()),
&JsValue::from_str("ClipboardItem"),
)?
.dyn_into()?;
let clipboard_item =
js_sys::Reflect::construct(&clipboard_item_constructor, &Array::of1(&items))?;
// Write the ClipboardItem to the clipboard
let item_list = Array::new();
item_list.push(&clipboard_item);
Ok(item_list)
}
fn create_blob(contents: &str, type_: &str) -> Result<Blob, JsValue> {
// See the JS Blob constructor docs for more info:
// https://developer.mozilla.org/en-US/docs/Web/API/Blob/Blob
let blob_parts = Array::new();
blob_parts.push(&JsValue::from_str(contents));
let blob_opts = BlobPropertyBag::new();
blob_opts.set_type(type_);
Blob::new_with_str_sequence_and_options(&blob_parts, &blob_opts)
}