diff --git a/files/en-us/web/api/clipboard/write/index.md b/files/en-us/web/api/clipboard/write/index.md index c0e7d1520ca3d19..d93e469ba984b27 100644 --- a/files/en-us/web/api/clipboard/write/index.md +++ b/files/en-us/web/api/clipboard/write/index.md @@ -73,13 +73,45 @@ A `try..catch` block could be used to catch any errors writing the data. ### Write canvas contents to the clipboard -This example draws a blue rectangle to the canvas and writes the canvas to a blob in the clipboard when you click the canvas. -An event listener is triggered on [`paste` events](/en-US/docs/Web/API/Element/paste_event) in an element where we want to display the clipboard contents as an image. +This example draws a blue rectangle to the canvas. +You can click the rectangle to copy the content of the canvas into the clipboard as an image, and then select another element and paste in the content from the clipboard. -The [FileReader API](/en-US/docs/Web/API/FileReader) allows us to read the blob using the [`readAsDataUrl`](/en-US/docs/Web/API/FileReader/readAsDataURL) method and create an `` element with the canvas contents: +#### HTML + +The HTML just defines our `` element and the `
` element with id `target` where the canvas image will be pasted. + +```html + + +
Paste here.
+``` + +#### JavaScript + +First we define an `async` function to copy a canvas to a blob. +This wraps the old callback-style {{domxref("HTMLCanvasElement.toBlob()")}} method into the more intuitive `Promise` based function. + +```js +// Async/await method replacing toBlob() callback +async function getBlobFromCanvas(canvas) { + return new Promise((resolve, reject) => { + canvas.toBlob((blob) => { + if (blob) { + resolve(blob); + } else { + reject(new Error("Canvas toBlob failed")); + } + }); + }); +} +``` + +Next we set up our canvas and add an event listener for the `click` event. + +When you click the blue rectangle the code first checks if the clipboard supports data of type `"image/png"`. +If so, the canvas displaying the rectangle is copied into a blob, and then the blob is added to a `ClipboardItem` and then written to the clipboard. ```js -const target = document.getElementById("target"); const canvas = document.getElementById("canvas"); // Set up canvas @@ -88,24 +120,33 @@ ctx.fillStyle = "cornflowerblue"; ctx.fillRect(0, 0, 100, 100); canvas.addEventListener("click", copyCanvasContentsToClipboard); +const target = document.getElementById("target"); -function copyCanvasContentsToClipboard() { - return new Promise((resolve, reject) => { +async function copyCanvasContentsToClipboard() { + if (ClipboardItem.supports("image/png")) { // Copy canvas to blob - canvas.toBlob(async (blob) => { - try { - // Create ClipboardItem with blob and its type, and add to an array - const data = [new ClipboardItem({ [blob.type]: blob })]; - // Write the data to the clipboard - await navigator.clipboard.write(data); - resolve(); - } catch (e) { - reject(e); - } - }); - }); + try { + const blob = await getBlobFromCanvas(canvas); + // Create ClipboardItem with blob and it's type, and add to an array + const data = [new ClipboardItem({ [blob.type]: blob })]; + // Write the data to the clipboard + await navigator.clipboard.write(data); + } catch (error) { + console.log(error); + } + } else { + console.log("image/png is not supported"); + } } +``` +Note that clipboard support for PNG files is a mandatory part of the specification, so we don't actually need the check using {{domxref("ClipboardItem.supports_static", "ClipboardItem.supports()")}} above (it always returns `true`). +The check would be more useful in cases where we're fetching an optional file type, or a resource where we don't know the type in advance. + +We then define an event listener for [`paste` events](/en-US/docs/Web/API/Element/paste_event) on then element where we want to display the clipboard contents as an image. +The [FileReader API](/en-US/docs/Web/API/FileReader) allows us to read the blob using the [`readAsDataUrl`](/en-US/docs/Web/API/FileReader/readAsDataURL) method and create an `` element with the canvas contents: + +```js target.addEventListener("paste", (event) => { const items = (event.clipboardData || window.clipboardData).items; const blob = items[0].getAsFile(); @@ -132,14 +173,12 @@ body { } img { margin: 0.5rem; -} ``` -```html - +#### Result -
Paste here.
-``` +The result is shown below. +First click on the blue square, and then select the text "Paste here" and use your OS-specific keyboard combinatations to paste from the clipboard (such as `Ctrl+V` on Windows). {{embedlivesample("write_canvas_contents_to_the_clipboard", "", "300")}} diff --git a/files/en-us/web/api/clipboarditem/clipboarditem/index.md b/files/en-us/web/api/clipboarditem/clipboarditem/index.md index 23e03b2ec95339e..d8797a5d4a5fa29 100644 --- a/files/en-us/web/api/clipboarditem/clipboarditem/index.md +++ b/files/en-us/web/api/clipboarditem/clipboarditem/index.md @@ -42,16 +42,19 @@ This item is then written to the clipboard, using the {{domxref("Clipboard.write ```js async function writeClipImg() { try { - const imgURL = "/myimage.png"; - const data = await fetch(imgURL); - const blob = await data.blob(); - - await navigator.clipboard.write([ - new ClipboardItem({ - [blob.type]: blob, - }), - ]); - console.log("Fetched image copied."); + if (ClipboardItem.supports("image/png")) { + const imgURL = "/myimage.png"; + const data = await fetch(imgURL); + const blob = await data.blob(); + await navigator.clipboard.write([ + new ClipboardItem({ + [blob.type]: blob, + }), + ]); + console.log("Fetched image copied."); + } else { + console.log("image png is not suported"); + } } catch (err) { console.error(err.name, err.message); } diff --git a/files/en-us/web/api/clipboarditem/index.md b/files/en-us/web/api/clipboarditem/index.md index 87a5aec9f08c697..b946316a768a64b 100644 --- a/files/en-us/web/api/clipboarditem/index.md +++ b/files/en-us/web/api/clipboarditem/index.md @@ -27,6 +27,13 @@ _This interface provides the following properties._ - {{domxref("ClipboardItem.presentationStyle", "presentationStyle")}} {{ReadOnlyInline}} - : Returns one of the following: `"unspecified"`, `"inline"` or `"attachment"`. +## Static methods + +_This interface defines the following methods._ + +- {{domxref("ClipboardItem.supports_static", "ClipboardItem.supports()")}} + - : Checks whether a given {{Glossary("MIME type")}} is supported by the clipboard. This enables a website to detect whether a MIME type is supported by the clipboard before attempting to write data. + ## Instance methods _This interface defines the following methods._ @@ -38,21 +45,25 @@ _This interface defines the following methods._ ### Writing to the clipboard -Here we're writing a new {{domxref("ClipboardItem.ClipboardItem", "ClipboardItem()")}} to the system clipboard by requesting a PNG image using the {{domxref("Fetch API")}}, and in turn, the {{domxref("Response.blob()", "responses' blob()")}} method, to create the new `ClipboardItem`. +Here we use {{domxref("ClipboardItem.supports_static", "supports()")}} to check whether the `image/svg+xml` MIME data type is supported. +If it is, we fetch the image with the ["Fetch API"](/en-US/docs/Web/API/Fetch_API), and then read it into a {{domxref("Blob")}}, which we can use to create a `ClipboardItem` that is written to the clipboard. ```js async function writeClipImg() { try { - const imgURL = "/myimage.png"; - const data = await fetch(imgURL); - const blob = await data.blob(); - - await navigator.clipboard.write([ - new ClipboardItem({ - [blob.type]: blob, - }), - ]); - console.log("Fetched image copied."); + if (ClipboardItem.supports("image/svg+xml")) { + const imgURL = "/myimage.svg"; + const data = await fetch(imgURL); + const blob = await data.blob(); + await navigator.clipboard.write([ + new ClipboardItem({ + [blob.type]: blob, + }), + ]); + console.log("Fetched image copied."); + } else { + console.log("SVG images are not supported by the clipboard."); + } } catch (err) { console.error(err.name, err.message); } diff --git a/files/en-us/web/api/clipboarditem/supports_static/index.md b/files/en-us/web/api/clipboarditem/supports_static/index.md new file mode 100644 index 000000000000000..c11ee175c2027b5 --- /dev/null +++ b/files/en-us/web/api/clipboarditem/supports_static/index.md @@ -0,0 +1,86 @@ +--- +title: "ClipboardItem: supports() static method" +short-title: supports() +slug: Web/API/ClipboardItem/supports_static +page-type: web-api-static-method +browser-compat: api.ClipboardItem.supports_static +--- + +{{APIRef("Clipboard API")}} {{securecontext_header}} + +The **`supports()`** static method of the {{domxref("ClipboardItem")}} interface returns `true` if the given {{Glossary("MIME type")}} is supported by the clipboard, and `false` otherwise. + +Note that the [Clipboard API](/en-US/docs/Web/API/Clipboard_API) mandates support for plain text, HTML and PNG files. +The `supports()` method will always return `true` for these MIME types, so testing them is unnecessary . + +## Syntax + +```js-nolint +supports(type) +``` + +### Parameters + +- `type` + + - : A string, indicating the {{Glossary("MIME type")}} to test. + + These MIME types are always supported: + + - `text/plain` + - `text/html` + - `image/png` + + These MIME types may be supported: + + - `image/svg+xml` + - Custom MIME-type formats starting with `"web "`. + The custom type (without the `"web "` prefix), must have the correct formatting for a MIME type. + +### Return value + +`true` if the given {{Glossary("MIME type")}} is supported by the clipboard, `false` otherwise. + +## Examples + +### Writing an image to the clipboard + +The following example fetches an SVG image to a blob, and then writes it to the clipboard. + +We use `supports()` to check whether the `"image/svg+xml"` MIME type is supported by the clipboard before fetching the image and writing it using {{domxref("clipboard.write()")}}. +We also wrap the whole function body in [`try..catch`](/en-US/docs/Web/JavaScript/Reference/Statements/try...catch) statement to catch any other errors, such as `ClipboardItem` itself not being supported. + +```js +async function writeClipImg() { + try { + if (ClipboardItem.supports("image/svg+xml")) { + const imgURL = "/myimage.svg"; + const data = await fetch(imgURL); + const blob = await data.blob(); + await navigator.clipboard.write([ + new ClipboardItem({ + [blob.type]: blob, + }), + ]); + console.log("Fetched image copied to clipboard."); + } else { + console.log("SVG image not supported by clipboard"); + } + } catch (err) { + console.error(err.name, err.message); + } +} +``` + +## Specifications + +{{Specifications}} + +## Browser compatibility + +{{Compat}} + +## See also + +- [Clipboard API](/en-US/docs/Web/API/Clipboard_API) +- [Image support for Async Clipboard article](https://web.dev/articles/async-clipboard)