// retoor <retoor@molodetz.nl>
export class CodeBlock {
static highlight(code) {
if (typeof hljs === "undefined" || !code) return;
code.removeAttribute("data-highlighted");
code.classList.remove("hljs");
try {
hljs.highlightElement(code);
} catch {
// leave plain text on failure
}
}
static lineNumbers(pre, code) {
pre.classList.add("code-pre", "has-line-numbers");
let gutter = pre.querySelector(":scope > .code-gutter");
if (!gutter) {
gutter = document.createElement("span");
gutter.className = "code-gutter";
gutter.setAttribute("aria-hidden", "true");
pre.insertBefore(gutter, code);
}
const text = code.textContent.replace(/\n+$/, "");
const count = text.length ? text.split("\n").length : 1;
gutter.textContent = Array.from({ length: count }, (_, i) => i + 1).join("\n");
}
static copyButton(pre, code) {
if (pre.querySelector(":scope > .code-copy-btn")) return;
const btn = document.createElement("button");
btn.type = "button";
btn.className = "code-copy-btn";
btn.textContent = "Copy";
btn.addEventListener("click", async () => {
try {
await navigator.clipboard.writeText(code.textContent);
btn.textContent = "Copied";
} catch {
btn.textContent = "Failed";
}
setTimeout(() => { btn.textContent = "Copy"; }, 1500);
});
pre.appendChild(btn);
}
static enhance(pre, { highlight = true, lineNumbers = true } = {}) {
if (!pre) return;
const code = pre.querySelector("code");
if (!code) return;
if (highlight && !code.classList.contains("hljs")) this.highlight(code);
pre.classList.add("code-has-copy");
if (lineNumbers) this.lineNumbers(pre, code);
this.copyButton(pre, code);
}
static refresh(pre) {
if (!pre) return;
const code = pre.querySelector("code");
if (!code) return;
this.highlight(code);
pre.classList.add("code-has-copy");
this.lineNumbers(pre, code);
this.copyButton(pre, code);
}
}
window.CodeBlock = CodeBlock;