the home site for me: also iteration 3 or 4 of my site
at main 2.6 kB view raw
1// Based on https://www.roboleary.net/2022/01/13/copy-code-to-clipboard-blog.html 2 3function initCopyButtons() { 4 const blocks = document.querySelectorAll("pre[class^='language-']"); 5 6 for (const block of blocks) { 7 // Code block header title 8 const title = document.createElement("span"); 9 title.style.color = "var(--accent-text)"; 10 const lang = block.getAttribute("data-lang"); 11 const comment = 12 block.previousElementSibling && 13 (block.previousElementSibling.tagName === "blockquote" || 14 block.previousElementSibling.nodeName === "BLOCKQUOTE") 15 ? block.previousElementSibling 16 : null; 17 if (comment) block.previousElementSibling.remove(); 18 title.innerHTML = 19 lang + (comment ? ` (${comment.textContent.trim()})` : ""); 20 21 // Copy button icon 22 const icon = document.createElement("i"); 23 icon.classList.add("icon"); 24 25 // Copy button 26 const button = document.createElement("button"); 27 const copyCodeText = "Copy code"; 28 button.setAttribute("title", copyCodeText); 29 button.appendChild(icon); 30 31 // Code block header 32 const header = document.createElement("div"); 33 header.classList.add("header"); 34 header.appendChild(title); 35 header.appendChild(button); 36 37 // Container that holds header and the code block itself 38 const container = document.createElement("div"); 39 container.classList.add("pre-container"); 40 container.appendChild(header); 41 42 // Move code block into the container 43 block.parentNode.insertBefore(container, block); 44 container.appendChild(block); 45 46 button.addEventListener("click", async () => { 47 await copyCode(block, header, button); 48 }); 49 } 50 51 async function copyCode(block, header, button) { 52 const code = block.querySelector("code"); 53 const text = code.innerText; 54 55 // Only try to copy if clipboard API is available 56 if (navigator.clipboard) { 57 try { 58 await navigator.clipboard.writeText(text); 59 header.classList.add("active"); 60 button.setAttribute("disabled", true); 61 62 header.addEventListener( 63 "animationend", 64 () => { 65 header.classList.remove("active"); 66 button.removeAttribute("disabled"); 67 }, 68 { once: true }, 69 ); 70 } catch (err) { 71 console.error("Failed to copy:", err); 72 } 73 } 74 } 75} 76 77// Since the script has defer attribute, the DOM is already loaded when this runs 78if (document.readyState === 'loading') { 79 document.addEventListener('DOMContentLoaded', initCopyButtons); 80} else { 81 initCopyButtons(); 82}