diff --git a/articles/flow/advanced/clipboard-api.adoc b/articles/flow/advanced/clipboard-api.adoc index 5a6e43d0fa..6e195f3cb5 100644 --- a/articles/flow/advanced/clipboard-api.adoc +++ b/articles/flow/advanced/clipboard-api.adoc @@ -1,8 +1,8 @@ --- title: Clipboard API page-title: How to use the Clipboard API in Vaadin -description: Using the Clipboard API to copy text and HTML to the user's clipboard from the server. -meta-description: Learn how to copy text and HTML to the user's clipboard in Vaadin applications using the server-side Clipboard API. +description: Using the Clipboard API to copy text, HTML, and images to the user's clipboard from the server. +meta-description: Learn how to copy text, HTML, and images to the user's clipboard in Vaadin applications using the server-side Clipboard API. order: 113 --- @@ -10,7 +10,7 @@ order: 113 = Clipboard API :toc: -The [classname]`Clipboard` API lets server-side Java code copy text and HTML to the user's clipboard through the https://developer.mozilla.org/en-US/docs/Web/API/Clipboard_API[browser Clipboard API]. Actions are bound to a clickable component and run during the DOM event that fires the underlying click, so the browser sees a fresh user gesture and allows the write. +The [classname]`Clipboard` API lets server-side Java code copy text, HTML, and images to the user's clipboard through the https://developer.mozilla.org/en-US/docs/Web/API/Clipboard_API[browser Clipboard API]. Actions are bound to a clickable component and run during the DOM event that fires the underlying click, so the browser sees a fresh user gesture and allows the write. [NOTE] The Clipboard API requires a secure context (HTTPS), except on `localhost` during development. Browsers also require the [code]`write` call to happen inside a short-lived user gesture (click, key press, …) -- writes triggered outside of a gesture, for example from a background thread or a timer, will fail with a [code]`NotAllowedError`. @@ -72,16 +72,39 @@ Clipboard.onClick(copy).writeHtml("Hello, world!"); Most targets fall back to a plain-text representation when only [code]`text/html` is present, but the fallback is browser-dependent. To control both representations explicitly, use the multi-format form below. +== Copying Images + +Use [methodname]`writeImage()` to copy a PNG version of an [code]`` element to the clipboard: + +[source,java] +---- +Image preview = new Image("images/chart.png", "Chart preview"); +Clipboard.onClick(copy).writeImage(preview); +---- + +The source can be a same-origin image, a [code]`data:` URL, or any cross-origin image served with matching CORS headers and [code]`crossorigin="anonymous"` on the [code]``. If the image is served from the server, pass a [classname]`DownloadHandler` instead: + +[source,java] +---- +Clipboard.onClick(copy).writeImage( + DownloadHandler.forClassResource(MainView.class, "chart.png")); +---- + +To include an image together with text or HTML, use [methodname]`ClipboardContent.image()` in the multi-format form. + + == Multi-Format Content -[classname]`ClipboardContent` packs several MIME types into a single clipboard item, so the paste target can pick the representation it understands. Set the [code]`text/plain` and [code]`text/html` slots independently; at least one must be set. +[classname]`ClipboardContent` packs several MIME types into a single clipboard item, so the paste target can pick the representation it understands. Set the [code]`text/plain`, [code]`text/html`, and [code]`image/png` slots independently; at least one must be set. [source,java] ---- +Image preview = new Image("images/chart.png", "Chart preview"); Button copy = new Button("Copy"); Clipboard.onClick(copy).write(ClipboardContent.create() .text("Hello, world!") - .html("Hello, world!")); + .html("Hello, world!") + .image(preview)); ---- The [methodname]`text()` setter also accepts a component, with the same client-side read semantics as [methodname]`writeText(Component)`: @@ -97,6 +120,8 @@ Clipboard.onClick(copy).write(ClipboardContent.create() [NOTE] The HTML slot only accepts a literal string -- there is no component overload. If the HTML depends on a field value, build it on the server before binding, or use the plain-text component overload alongside a static HTML literal. +[NOTE] +The image slot only accepts a component whose root element is an [code]``. If the image source is not already on the page, use [methodname]`writeImage(DownloadHandler)` to serve it through a hidden image element. [#observing-the-outcome]