From 0832cad803bb429a49595eab822a7c77dfa2088b Mon Sep 17 00:00:00 2001 From: Martin Brennan Date: Mon, 21 Mar 2022 13:34:01 +1000 Subject: [PATCH] DEV: Add clipboardCopyAsync API to utilities (#16232) In certain cases (like chat quoting) we need to be able to call the API with an async AJAX call before copying the results to the clipboard. The only way to reliably do this is by handing off the AJAX promise to a ClipboardItem. This commit introduces a new clipboardCopyAsync function to handle this, which will stand alongside the existing clipboardCopy function which can be used when no AJAX request is necessary. --- .../discourse/app/lib/utilities.js | 36 ++++++++++++++++++- 1 file changed, 35 insertions(+), 1 deletion(-) diff --git a/app/assets/javascripts/discourse/app/lib/utilities.js b/app/assets/javascripts/discourse/app/lib/utilities.js index 942b0aa17cb..8a78eb0a4bb 100644 --- a/app/assets/javascripts/discourse/app/lib/utilities.js +++ b/app/assets/javascripts/discourse/app/lib/utilities.js @@ -506,7 +506,9 @@ export function translateModKey(string) { return string; } -// http://github.com/feross/clipboard-copy +// Use this version of clipboardCopy if you already have the text to +// be copied in memory, and you do not need to make an AJAX call to +// the API to generate any text. See clipboardCopyAsync for the latter. export function clipboardCopy(text) { // Use the Async Clipboard API when available. // Requires a secure browsing context (i.e. HTTPS) @@ -519,7 +521,39 @@ export function clipboardCopy(text) { } // ...Otherwise, use document.execCommand() fallback + return clipboardCopyFallback(text); +} +// Use this verison of clipboardCopy if you must use an AJAX call +// to retrieve/generate server-side text to copy to the clipboard, +// otherwise this write function will error in certain browsers, because +// the time taken from the user event to the clipboard text being copied +// will be too long. +// +// Note that the promise passed in should return a Blob with type of +// text/plain. +export function clipboardCopyAsync(promise) { + // Use the Async Clipboard API when available. + // Requires a secure browsing context (i.e. HTTPS) + if (navigator.clipboard) { + return navigator.clipboard + .write([new window.ClipboardItem({ "text/plain": promise() })]) + .catch(function (err) { + throw err !== undefined + ? err + : new DOMException("The request is not allowed", "NotAllowedError"); + }); + } + + // ...Otherwise, use document.execCommand() fallback + return promise().then((textBlob) => { + textBlob.text().then((text) => { + return clipboardCopyFallback(text); + }); + }); +} + +function clipboardCopyFallback(text) { // Put the text to copy into a const span = document.createElement("span"); span.textContent = text;