| 244 | // --- Copy-to-clipboard buttons -------------------------------- |
| 245 | |
| 246 | function addCopyButtons(container) { |
| 247 | container.querySelectorAll("pre").forEach((pre) => { |
| 248 | if (pre.querySelector(".copy-btn")) return; // guard against double-adding |
| 249 | const btn = document.createElement("button"); |
| 250 | btn.className = "copy-btn"; |
| 251 | btn.setAttribute("aria-label", "Copy code to clipboard"); |
| 252 | btn.innerHTML = |
| 253 | `<svg viewBox="0 0 14 14" fill="none" width="11" height="11" xmlns="http://www.w3.org/2000/svg"> |
| 254 | <rect x="4" y="4" width="8" height="8" rx="1.2" stroke="currentColor" stroke-width="1.3"/> |
| 255 | <path d="M2.5 9.5V2.5a1 1 0 0 1 1-1h6.5" stroke="currentColor" stroke-width="1.3" stroke-linecap="round"/> |
| 256 | </svg><span>Copy</span>`; |
| 257 | |
| 258 | btn.addEventListener("click", () => { |
| 259 | const code = pre.querySelector("code"); |
| 260 | const text = (code ? code.innerText : pre.innerText).trimEnd(); |
| 261 | |
| 262 | const finish = (ok) => { |
| 263 | const span = btn.querySelector("span"); |
| 264 | span.textContent = ok ? "Copied!" : "Error"; |
| 265 | btn.classList.toggle("copied", ok); |
| 266 | btn.classList.toggle("copy-error", !ok); |
| 267 | setTimeout(() => { |
| 268 | span.textContent = "Copy"; |
| 269 | btn.classList.remove("copied", "copy-error"); |
| 270 | }, 2000); |
| 271 | }; |
| 272 | |
| 273 | if (navigator.clipboard?.writeText) { |
| 274 | navigator.clipboard.writeText(text).then(() => finish(true)).catch(() => finish(false)); |
| 275 | } else { |
| 276 | // Fallback for HTTP / older browsers |
| 277 | try { |
| 278 | const ta = Object.assign(document.createElement("textarea"), { |
| 279 | value: text, style: "position:fixed;opacity:0" |
| 280 | }); |
| 281 | document.body.appendChild(ta); |
| 282 | ta.select(); |
| 283 | document.execCommand("copy"); |
| 284 | ta.remove(); |
| 285 | finish(true); |
| 286 | } catch { finish(false); } |
| 287 | } |
| 288 | }); |
| 289 | |
| 290 | pre.appendChild(btn); |
| 291 | }); |
| 292 | } |
| 293 | |
| 294 | // --- Sidebar tree --------------------------------------------- |
| 295 | |