-
Notifications
You must be signed in to change notification settings - Fork 75
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add support for wasm32 + web #160
base: master
Are you sure you want to change the base?
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thank you for the PR. I think the approach here makes sense for typical web applications. I'm not a web developer though 😅.
Question: Do you have the ability to test this in Safari? I know their Clipboard APIs are a bit different compared to Firefox and Chromium. I have the ability to test it myself but would need an example WASM app to run.
src/platform/wasm.rs
Outdated
const GLOBAL_CLIPBOARD_OBJECT: &str = "__arboard_global_clipboard"; | ||
|
||
pub(crate) fn new() -> Result<Self, Error> { | ||
let window = web_sys::window().ok_or(Error::ClipboardNotSupported)?; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Question: Can this approach work in service workers/background workers? If not we can keep this hardcoded to window
instead of global
but that should be documented in the Clipboard
documentation or similar.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Unfortunately web workers cannot be supported - the clipboard API is not available in web workers (see the note on this page). I will add some documentation to mention this.
src/platform/wasm.rs
Outdated
} | ||
|
||
pub(crate) fn clear(self) -> Result<(), Error> { | ||
let _ = self.clipboard.inner.write(&js_sys::Array::default()); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should the various clipboard calls failing return Error::Unknown
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The calls with let _ =
don't fail immediately; they return a Promise
that resolves once the browser has updated the clipboard contents. Since this is a synchronous API, I just fire and forget the promise here.
The only instances in which these calls asynchronously fail (according to Mozilla docs) is if the page doesn't have permission to write to the user's clipboard. Clipboard permissions are granted with transient activation - that is, once the user interacts with the page, writing to the clipboard is allowed.
It would be nice if there was a way to report the error here. The fire and forget approach is a bit jank - but it does work for my use case, which is just handling normal copy/paste interactions with egui
on the web.
I've gone ahead and attempted to address your feedback! The web has some security restrictions on what's possible, but this PR works perfectly for me with
I sadly don't have access to a Mac right now. However, I've put together a really simple example web app for testing. You should be able to just clone the repository and run |
Hi, just a quick update: I don't have the bandwidth at the moment to finish up the testing and reviewing for this PR. I apologize for the late communication but I'll need to circle back to it later, likely in October. |
This PR implements the ability to cut, copy, and paste text on the web/WASM platforms. This allows libraries like
egui-winit
to use the clipboard on the web (see emilk/egui#4270). This is accomplished in the following way:window.navigator.clipboard.write()
paste
event listener to the root HTML document, which stores theevent.clipboardData.getData("text")
value into a global variable. Whenever the clipboard contents are requested from Rust, the global variable is read. Note that this means the user must actually perform a paste before the clipboard contents become visible to Rust. This is a caveat, but it's the only way that I could find to implement synchronous pasting.event.clipboardData.files
array, whereasync
is required to read the data.