Skip to content

Update code-block-buttons.js #581

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
83 changes: 57 additions & 26 deletions static/js/code-block-buttons.js
Original file line number Diff line number Diff line change
@@ -1,47 +1,78 @@
// Turn off ESLint for this file because it's sent down to users as-is.
/* eslint-disable */
window.addEventListener("load", function () {
function button(label, ariaLabel, icon, className) {
window.addEventListener("DOMContentLoaded", function () {
function createButton(label, ariaLabel, icon, className) {
const btn = document.createElement("button");
btn.classList.add("btnIcon", className);
btn.setAttribute("type", "button");
btn.setAttribute("aria-label", ariaLabel);
btn.innerHTML =
'<div class="btnIcon__body">' +
icon +
'<strong class="btnIcon__label">' +
label +
"</strong>" +
"</div>";
btn.innerHTML = `
<div class="btnIcon__body">
${icon}
<strong class="btnIcon__label">${label}</strong>
</div>
`;
return btn;
}

function addButtons(codeBlockSelector, btn) {
document.querySelectorAll(codeBlockSelector).forEach(function (code) {
code.parentNode.appendChild(btn.cloneNode(true));
function addButtons(codeBlockSelector, btnTemplate) {
document.querySelectorAll(codeBlockSelector).forEach((codeBlock) => {
// Ensure we don't duplicate buttons
if (!codeBlock.parentNode.querySelector(".btnClipboard")) {
const btn = btnTemplate.cloneNode(true);
codeBlock.parentNode.appendChild(btn);
}
});
}

const copyIcon =
'<svg width="12" height="12" viewBox="340 364 14 15" xmlns="http://www.w3.org/2000/svg"><path fill="currentColor" d="M342 375.974h4v.998h-4v-.998zm5-5.987h-5v.998h5v-.998zm2 2.994v-1.995l-3 2.993 3 2.994v-1.996h5v-1.995h-5zm-4.5-.997H342v.998h2.5v-.997zm-2.5 2.993h2.5v-.998H342v.998zm9 .998h1v1.996c-.016.28-.11.514-.297.702-.187.187-.422.28-.703.296h-10c-.547 0-1-.452-1-.998v-10.976c0-.546.453-.998 1-.998h3c0-1.107.89-1.996 2-1.996 1.11 0 2 .89 2 1.996h3c.547 0 1 .452 1 .998v4.99h-1v-2.995h-10v8.98h10v-1.996zm-9-7.983h8c0-.544-.453-.996-1-.996h-1c-.547 0-1-.453-1-.998 0-.546-.453-.998-1-.998-.547 0-1 .452-1 .998 0 .545-.453.998-1 .998h-1c-.547 0-1 .452-1 .997z" fill-rule="evenodd"/></svg>';
const copyIcon = `<svg width="12" height="12" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<path fill="currentColor" d="M19 21H8V7h11m0-2H8a2 2 0 0 0-2 2v14a2 2 0 0 0 2 2h11a2 2 0 0 0 2-2V7a2 2 0 0 0-2-2m-3-4H4a2 2 0 0 0-2 2v14h2V3h12V1z"/>
</svg>`;

addButtons(
".hljs",
button("Copy", "Copy code to clipboard", copyIcon, "btnClipboard")
const copyButton = createButton(
"Copy",
"Copy code to clipboard",
copyIcon,
"btnClipboard"
);

addButtons(".hljs", copyButton);

const clipboard = new ClipboardJS(".btnClipboard", {
target: function (trigger) {
return trigger.parentNode.querySelector("code");
},
text: (trigger) => {
const codeBlock = trigger.parentNode.querySelector("code");
return codeBlock ? codeBlock.innerText : "";
}
});

clipboard.on("success", function (event) {
// Track timeouts per button
const buttonTimeouts = new WeakMap();

clipboard.on("success", (event) => {
event.clearSelection();
const textEl = event.trigger.querySelector(".btnIcon__label");
textEl.textContent = "Copied";
setTimeout(function () {
textEl.textContent = "Copy";
const button = event.trigger;
const label = button.querySelector(".btnIcon__label");

// Clear existing timeout if any
if (buttonTimeouts.has(button)) {
clearTimeout(buttonTimeouts.get(button));
}

label.textContent = "Copied!";

// Set new timeout
const timeoutId = setTimeout(() => {
label.textContent = "Copy";
buttonTimeouts.delete(button);
}, 2000);

buttonTimeouts.set(button, timeoutId);
});

clipboard.on("error", (event) => {
const label = event.trigger.querySelector(".btnIcon__label");
label.textContent = "Failed";
setTimeout(() => {
label.textContent = "Copy";
}, 2000);
});
});