DEV: Make clipboardCopy util available for import ()

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
app/assets/javascripts
admin/addon/controllers
discourse/app

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

@ -1,61 +1,10 @@
import { cancel, later } from "@ember/runloop";
import I18n from "I18n";
import { Promise } from "rsvp";
import { guidFor } from "@ember/object/internals";
import { clipboardCopy } from "discourse/lib/utilities";
import { iconHTML } from "discourse-common/lib/icon-library";
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 _fadeCopyCodeblocksRunners = {};
@ -79,6 +28,25 @@ export default {
_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) {
if (!event.target.classList.contains("copy-cmd")) {
return;
@ -96,24 +64,14 @@ export default {
)
.trim();
clipboardCopy(text).then(() => {
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);
const result = clipboardCopy(text);
if (result.then) {
result.then(() => {
_copyComplete(button);
});
} else if (result) {
_copyComplete(button);
}
}
}

@ -503,5 +503,52 @@ export function translateModKey(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
export default {};