Bug 222262
Summary: | Javascript Clipboard API write() does not work after await | ||
---|---|---|---|
Product: | WebKit | Reporter: | Felipe Ruiz <fruiz> |
Component: | UI Events | Assignee: | Nobody <webkit-unassigned> |
Status: | NEW | ||
Severity: | Major | CC: | ap, bfan2, bfulgham, christian, eoconnor, jer.noble, m.andrewgunn100, mjs, rniwa, tomac, webkit-bug-importer, wenson_hsieh |
Priority: | P2 | Keywords: | InRadar |
Version: | Safari 14 | ||
Hardware: | All | ||
OS: | All | ||
See Also: | https://bugs.webkit.org/show_bug.cgi?id=225559 |
Felipe Ruiz
I'm using javascript Clipboard API to copy an image to the clipboard. It works in Chrome and Edge but not in Safari in spite of official documentation of Safari says that it's supported.
Check the documentation: https://webkit.org/blog/10855/
In this example (not my real code), write() throws an error:
document.getElementById("copy").addEventListener("click", async function() {
const response = await fetch('https://upload.wikimedia.org/wikipedia/commons/4/47/PNG_transparency_demonstration_1.png');
const blob = await response.blob();
navigator.clipboard.write([new ClipboardItem({ "image/png": blob })])
.then(function () { console.log('copied'); })
.catch(function (error) { console.log(error); });
});
The given error is:
NotAllowedError: The request is not allowed by the user agent or the platform in the current context, possibly because the user denied permission.
Attachments | ||
---|---|---|
Add attachment proposed patch, testcase, etc. |
Ryosuke Niwa
(In reply to Felipe Ruiz from comment #0)
> I'm using javascript Clipboard API to copy an image to the clipboard. It
> works in Chrome and Edge but not in Safari in spite of official
> documentation of Safari says that it's supported.
The issue is not so much async Clipboard API and the difference in the way user activation is tracked between Blink and WebKit.
> In this example (not my real code), write() throws an error:
>
> document.getElementById("copy").addEventListener("click", async function() {
> const response = await
> fetch('https://upload.wikimedia.org/wikipedia/commons/4/47/
> PNG_transparency_demonstration_1.png');
> const blob = await response.blob();
>
> navigator.clipboard.write([new ClipboardItem({ "image/png": blob })])
> .then(function () { console.log('copied'); })
> .catch(function (error) { console.log(error); });
> });
You need to initiate the write inside click event handler as in:
document.getElementById("copy-html").addEventListener("click", event => {
navigator.clipboard.write([
new ClipboardItem({
"text/png": async () => {
const response = await fetch('https://upload.wikimedia.org/wikipedia/commons/4/47/PNG_transparency_demonstration_1.png');
return await response.blob();
}
}),
]);
});
Felipe Ruiz
(In reply to Ryosuke Niwa from comment #1)
> (In reply to Felipe Ruiz from comment #0)
> > I'm using javascript Clipboard API to copy an image to the clipboard. It
> > works in Chrome and Edge but not in Safari in spite of official
> > documentation of Safari says that it's supported.
>
> The issue is not so much async Clipboard API and the difference in the way
> user activation is tracked between Blink and WebKit.
>
> > In this example (not my real code), write() throws an error:
> >
> > document.getElementById("copy").addEventListener("click", async function() {
> > const response = await
> > fetch('https://upload.wikimedia.org/wikipedia/commons/4/47/
> > PNG_transparency_demonstration_1.png');
> > const blob = await response.blob();
> >
> > navigator.clipboard.write([new ClipboardItem({ "image/png": blob })])
> > .then(function () { console.log('copied'); })
> > .catch(function (error) { console.log(error); });
> > });
>
> You need to initiate the write inside click event handler as in:
>
> document.getElementById("copy-html").addEventListener("click", event => {
> navigator.clipboard.write([
> new ClipboardItem({
> "text/png": async () => {
> const response = await
> fetch('https://upload.wikimedia.org/wikipedia/commons/4/47/
> PNG_transparency_demonstration_1.png');
> return await response.blob();
> }
> }),
> ]);
> });
Hi Ryosuke,
first of all, thanks for your reply. Unfortunately, I have tested your solution and I get the same error message.
Wenson Hsieh
> > You need to initiate the write inside click event handler as in:
> >
> > document.getElementById("copy-html").addEventListener("click", event => {
> > navigator.clipboard.write([
> > new ClipboardItem({
> > "text/png": async () => {
> > const response = await
> > fetch('https://upload.wikimedia.org/wikipedia/commons/4/47/
> > PNG_transparency_demonstration_1.png');
> > return await response.blob();
> > }
> > }),
> > ]);
> > });
>
>
> Hi Ryosuke,
>
> first of all, thanks for your reply. Unfortunately, I have tested your
> solution and I get the same error message.
Hi Felipe,
I adapted the above code as a test case here: https://whsieh.github.io/examples/dice, and it seems to work in Safari on macOS with a couple of adjustments:
- Changing the "text/png" above to "image/png".
- Making the corresponding value for the "image/png" type a Promise instead of an async function.
Please make sure that you're also testing in a secure context (https), where the clipboard API is available.
Thanks!
Wenson
Radar WebKit Bug Importer
<rdar://problem/74860840>
Thomas Steiner
The different implementations unfortunately at the moment force developers to write code like this:
```js
copyButton.addEventListener('click', async () => {
try {
// Safari treats user activation differently:
// https://bugs.webkit.org/show_bug.cgi?id=222262.
navigator.clipboard.write([
new ClipboardItem({
'text/plain': new Promise(async (resolve) => {
const svg = svgOutput.innerHTML;
resolve(new Blob([svg], { type: 'text/plain' }));
}),
}),
]);
} catch {
// Chromium
const svg = svgOutput.innerHTML;
const blob = new Blob([svg], { type: 'text/plain' });
navigator.clipboard.write([
new ClipboardItem({
[blob.type]: blob,
}),
]);
}
});
```
Chromium is working on adding support for delayed generation of clipboard items (see https://crbug.com/1014310).
At the same time it would be great if WebKit didn't expire the user activation.
Alexey Proskuryakov
*** Bug 244812 has been marked as a duplicate of this bug. ***