DEV: Make clipboardCopy util available for import (#15874)

We need this in other places, this commit moves clipboardCopy
to the utilities.js lib. Had to remove use of Promise as well because
lib/utilities cannot import it, otherwise it will cause a mini racer error.
This commit is contained in:
Martin Brennan 2022-02-09 16:11:41 +10:00 committed by GitHub
parent 7850ee318f
commit c1ad9c3276
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 77 additions and 76 deletions

View File

@ -5,6 +5,7 @@ import Permalink from "admin/models/permalink";
import bootbox from "bootbox"; import bootbox from "bootbox";
import discourseDebounce from "discourse-common/lib/debounce"; import discourseDebounce from "discourse-common/lib/debounce";
import { observes } from "discourse-common/utils/decorators"; import { observes } from "discourse-common/utils/decorators";
import { clipboardCopy } from "discourse/lib/utilities";
export default Controller.extend({ export default Controller.extend({
loading: false, loading: false,
@ -29,12 +30,7 @@ export default Controller.extend({
copyUrl(pl) { copyUrl(pl) {
let linkElement = document.querySelector(`#admin-permalink-${pl.id}`); let linkElement = document.querySelector(`#admin-permalink-${pl.id}`);
let textArea = document.createElement("textarea"); clipboardCopy(linkElement.textContent);
textArea.value = linkElement.textContent;
document.body.appendChild(textArea);
textArea.select();
document.execCommand("Copy");
textArea.remove();
}, },
destroy(record) { destroy(record) {

View File

@ -1,61 +1,10 @@
import { cancel, later } from "@ember/runloop"; import { cancel, later } from "@ember/runloop";
import I18n from "I18n"; import I18n from "I18n";
import { Promise } from "rsvp";
import { guidFor } from "@ember/object/internals"; import { guidFor } from "@ember/object/internals";
import { clipboardCopy } from "discourse/lib/utilities";
import { iconHTML } from "discourse-common/lib/icon-library"; import { iconHTML } from "discourse-common/lib/icon-library";
import { withPluginApi } from "discourse/lib/plugin-api"; import { withPluginApi } from "discourse/lib/plugin-api";
// http://github.com/feross/clipboard-copy
function clipboardCopy(text) {
// Use the Async Clipboard API when available.
// Requires a secure browsing context (i.e. HTTPS)
if (navigator.clipboard) {
return navigator.clipboard.writeText(text).catch(function (err) {
throw err !== undefined
? err
: new DOMException("The request is not allowed", "NotAllowedError");
});
}
// ...Otherwise, use document.execCommand() fallback
// Put the text to copy into a <span>
const span = document.createElement("span");
span.textContent = text;
// Preserve consecutive spaces and newlines
span.style.whiteSpace = "pre";
// Add the <span> to the page
document.body.appendChild(span);
// Make a selection object representing the range of text selected by the user
const selection = window.getSelection();
const range = window.document.createRange();
selection.removeAllRanges();
range.selectNode(span);
selection.addRange(range);
// Copy text to the clipboard
let success = false;
try {
success = window.document.execCommand("copy");
} catch (err) {
// eslint-disable-next-line no-console
console.log("error", err);
}
// Cleanup
selection.removeAllRanges();
window.document.body.removeChild(span);
return success
? Promise.resolve()
: Promise.reject(
new DOMException("The request is not allowed", "NotAllowedError")
);
}
let _copyCodeblocksClickHandlers = {}; let _copyCodeblocksClickHandlers = {};
let _fadeCopyCodeblocksRunners = {}; let _fadeCopyCodeblocksRunners = {};
@ -79,6 +28,25 @@ export default {
_fadeCopyCodeblocksRunners = {}; _fadeCopyCodeblocksRunners = {};
} }
function _copyComplete(button) {
button.classList.add("copied");
const state = button.innerHTML;
button.innerHTML = I18n.t("copy_codeblock.copied");
const commandId = guidFor(button);
if (_fadeCopyCodeblocksRunners[commandId]) {
cancel(_fadeCopyCodeblocksRunners[commandId]);
delete _fadeCopyCodeblocksRunners[commandId];
}
_fadeCopyCodeblocksRunners[commandId] = later(() => {
button.classList.remove("copied");
button.innerHTML = state;
delete _fadeCopyCodeblocksRunners[commandId];
}, 3000);
}
function _handleClick(event) { function _handleClick(event) {
if (!event.target.classList.contains("copy-cmd")) { if (!event.target.classList.contains("copy-cmd")) {
return; return;
@ -96,24 +64,14 @@ export default {
) )
.trim(); .trim();
clipboardCopy(text).then(() => { const result = clipboardCopy(text);
button.classList.add("copied"); if (result.then) {
const state = button.innerHTML; result.then(() => {
button.innerHTML = I18n.t("copy_codeblock.copied"); _copyComplete(button);
});
const commandId = guidFor(button); } else if (result) {
_copyComplete(button);
if (_fadeCopyCodeblocksRunners[commandId]) { }
cancel(_fadeCopyCodeblocksRunners[commandId]);
delete _fadeCopyCodeblocksRunners[commandId];
}
_fadeCopyCodeblocksRunners[commandId] = later(() => {
button.classList.remove("copied");
button.innerHTML = state;
delete _fadeCopyCodeblocksRunners[commandId];
}, 3000);
});
} }
} }

View File

@ -503,5 +503,52 @@ export function translateModKey(string) {
return string; return string;
} }
// http://github.com/feross/clipboard-copy
export function clipboardCopy(text) {
// Use the Async Clipboard API when available.
// Requires a secure browsing context (i.e. HTTPS)
if (navigator.clipboard) {
return navigator.clipboard.writeText(text).catch(function (err) {
throw err !== undefined
? err
: new DOMException("The request is not allowed", "NotAllowedError");
});
}
// ...Otherwise, use document.execCommand() fallback
// Put the text to copy into a <span>
const span = document.createElement("span");
span.textContent = text;
// Preserve consecutive spaces and newlines
span.style.whiteSpace = "pre";
// Add the <span> to the page
document.body.appendChild(span);
// Make a selection object representing the range of text selected by the user
const selection = window.getSelection();
const range = window.document.createRange();
selection.removeAllRanges();
range.selectNode(span);
selection.addRange(range);
// Copy text to the clipboard
let success = false;
try {
success = window.document.execCommand("copy");
} catch (err) {
// eslint-disable-next-line no-console
console.log("error", err);
}
// Cleanup
selection.removeAllRanges();
window.document.body.removeChild(span);
return success;
}
// This prevents a mini racer crash // This prevents a mini racer crash
export default {}; export default {};