Bug 202136

Summary: Implement async clipboard API
Product: WebKit Reporter: Thomas Steiner <tomac>
Component: New BugsAssignee: Nobody <webkit-unassigned>
Status: RESOLVED DUPLICATE    
Severity: Normal CC: beidson, costan, david.malcom.graham, huangdarwin, me, rniwa, stephen, wenson_hsieh
Priority: P2    
Version: Safari Technology Preview   
Hardware: Unspecified   
OS: Unspecified   

Description Thomas Steiner 2019-09-23 23:50:07 PDT
Clipboard API and events (https://w3c.github.io/clipboard-apis/) describes APIs for accessing data on the system clipboard. It provides operations for overriding the default clipboard actions (cut, copy and paste), and for directly accessing the clipboard contents.
There are text convenience methods `readText()` (https://w3c.github.io/clipboard-apis/#dom-clipboard-readtext) and `writeText()` (https://w3c.github.io/clipboard-apis/#dom-clipboard-writetext) that are hopefully non-controversial, and more advanced features that eventually provide raw clipboard access. It would be nice if WebKit could add at least the textual methods as their usage is growing: https://chromestatus.com/metrics/feature/timeline/popularity/2372.

Related reading: https://developers.google.com/web/updates/2018/03/clipboardapi and https://developers.google.com/web/updates/2019/07/image-support-for-async-clipboard.
Comment 1 Ryosuke Niwa 2019-10-01 14:03:08 PDT
Are you respecting about the async clipboard API? or raw clipboard API? Or simply cut, copy, & paste?

It's unclear which aspects of this new API is needed for what purpose.
Comment 2 Thomas Steiner 2019-10-02 01:17:05 PDT
In the simplest shape, this is about programmatically copying and pasting text with the Async Clipboard API:

```js
async function copyPageURL() {
  try {
    await navigator.clipboard.writeText(location.href);
    console.log('Page URL copied to clipboard');
  } catch (err) {
    console.error('Failed to copy: ', err);
  }
}

async function getClipboardText() {
  try {
    const text = await navigator.clipboard.readText();
    console.log('Clipboard contents: ', text);
  } catch (err) {
    console.error('Failed to read clipboard contents: ', err);
  }
}
```


In the advanced form, this is about copying and pasting binary data, like PNG images:

```js
try {
  const imgURL = 'https://developers.google.com/web/updates/images/generic/file.png';
  const data = await fetch(imgURL);
  const blob = await data.blob();
  await navigator.clipboard.write([
    new ClipboardItem(Object.defineProperty({}, blob.type, {
      value: blob,
      enumerable: true
    }))
  ]);
  console.log('Image copied.');
} catch(e) {
  console.error(e, e.message);
}

async function getClipboardContents() {
  try {
    const clipboardItems = await navigator.clipboard.read();
    for (const clipboardItem of clipboardItems) {
      try {
        for (const type of clipboardItem.types) {
          const blob = await clipboardItem.getType(type);
          console.log(URL.createObjectURL(blob));
        }
      } catch (e) {
        console.error(e, e.message);
      }
    }
  } catch (e) {
    console.error(e, e.message);
  }
}
```

On Chrome, we re-encode images for security reasons and currently only support PNG images, but eventually want to broaden this to more image formats, and ultimately anything (but it's still in the farther away future).
Comment 3 Victor Costan 2019-10-02 09:42:46 PDT
How about renaming the bug to "Implement the Async Clipboard API"?

For the purpose of this bug, I recommend that we focus on the async imperative API for reading/writing text and images from/to the clipboard. This is an all-around better API than execCommand("copy" / "paste").

As far as I know, Chrome hasn't implemented change events yet, so we don't know if there are any subtleties hiding there. Raw Clipboard Access should be an entirely separate discussion :)
Comment 4 Darwin Huang 2019-10-02 11:10:58 PDT
+1. navigator.clipboard.{read,write,readText,writeText}() has more consensus and is specified / implemented in Blink and Gecko, so it may be good for that to be the focus of this bug.

(Raw Clipboard is not yet specified, and I believe simple cut/copy/paste is mostly already supported in a similar manner across rendering engines.)
Comment 5 David Graham 2019-11-06 10:19:31 PST
We use `writeText` in the [github/clipboard-copy-element][1] custom element if it's available and fall back to a more complex `execCommand("copy")` flow if not. Supporting at least `writeText` would allow us to eventually remove the execCommand code.

[1]: https://github.com/github/clipboard-copy-element/blob/e505506cefbf082e4491396b71809f95239562d7/src/clipboard.js#L14-L18
Comment 6 Brady Eidson 2020-02-24 09:29:14 PST
Pretty sure this is done and enabled as of https://bugs.webkit.org/show_bug.cgi?id=205322

*** This bug has been marked as a duplicate of bug 205322 ***
Comment 7 Victor Costan 2020-02-24 09:31:17 PST
This is great news! Thank you very much!!
Comment 8 Thomas Steiner 2020-02-25 00:53:20 PST
Great news indeed. Thanks from my side as well!
Comment 9 Ryosuke Niwa 2020-02-25 20:41:16 PST
FWIW, async clipboard API is now supported in the latest betas of iOS 13.4 and macOS Catalina 10.15.4. Please try them out.
Comment 10 Thomas Steiner 2020-02-25 23:31:06 PST
I can confirm that this works! 🎉 Thanks, team WebKit!

Tried with https://googlechrome.github.io/samples/async-clipboard/ on an iOS device on iOS 13.4 beta 2 (build 17E5233g) and on Safari Tech Preview 100 on 10.15.3.