hugo-theme/assets/js/code-copy.js
2024-10-21 13:47:30 +02:00

73 lines
2.6 KiB
JavaScript

(function () {
const copyIcon = document.getElementById("code-copy").innerHTML;
const copyIconDone = document.getElementById("code-copy-done").innerHTML;
/**
* code inspired by https://digitaldrummerj.me/hugo-add-copy-code-snippet-button/
* and https://www.dannyguo.com/blog/how-to-add-copy-to-clipboard-buttons-to-code-blocks-in-hugo
*/
function createCopyButton(highlightDiv) {
const button = document.createElement("button");
button.className = "right-1 top-1 absolute";
button.type = "button";
button.innerHTML = copyIcon;
button.addEventListener("click", () => copyCodeToClipboard(button, highlightDiv));
highlightDiv.insertBefore(button, highlightDiv.firstChild);
}
document.querySelectorAll(".highlight").forEach((highlightDiv) => createCopyButton(highlightDiv));
async function copyCodeToClipboard(button, highlightDiv) {
let codeToCopy = highlightDiv.querySelector("code").textContent;
if (highlightDiv.querySelector("table")) { // code with line number
codeToCopy = highlightDiv.querySelector("td:last-child code").textContent;
}
let permissionGranted = true;
try {
var result = await navigator.permissions.query({ name: "clipboard-write" });
if (result.state != "granted" && result.state != "prompt") {
permissionGranted = false;
}
} catch (_) {
// The clipboard-write permission name is not supported in Firefox, only Chromium browsers.
// default to true in case of error for firefox
}
try {
if (permissionGranted) {
await navigator.clipboard.writeText(codeToCopy);
} else {
copyCodeBlockExecCommand(codeToCopy, highlightDiv);
}
} catch (_) {
copyCodeBlockExecCommand(codeToCopy, highlightDiv);
} finally {
/* Chrome doesn't seem to blur automatically,
leaving the button in a focused state. */
button.blur();
button.innerHTML = copyIconDone;
setTimeout(function () {
button.innerHTML = copyIcon;
}, 2000);
}
}
function copyCodeBlockExecCommand(codeToCopy, highlightDiv) {
const textArea = document.createElement("textArea");
textArea.contentEditable = "true";
textArea.readOnly = "false";
textArea.className = "copyable-text-area";
textArea.value = codeToCopy;
highlightDiv.insertBefore(textArea, highlightDiv.firstChild);
const range = document.createRange();
range.selectNodeContents(textArea);
const sel = window.getSelection();
sel.removeAllRanges();
sel.addRange(range);
textArea.setSelectionRange(0, 999999);
document.execCommand("copy");
highlightDiv.removeChild(textArea);
}
})();