Skip to content

Commit

Permalink
copy button (#177)
Browse files Browse the repository at this point in the history
- client.js only
- visual feedback with css
- uses navigator.clipboard.writeText
- adds the copy button on all PRE > CODE (or even PRE > SPAN) elements
- pass data-copy=off to disable

supersedes #138
  • Loading branch information
Fil authored Nov 15, 2023
1 parent bdc138f commit aca0666
Show file tree
Hide file tree
Showing 2 changed files with 48 additions and 14 deletions.
36 changes: 36 additions & 0 deletions public/client.js
Original file line number Diff line number Diff line change
Expand Up @@ -334,3 +334,39 @@ function preventDoubleClick(event) {
for (const summary of document.querySelectorAll("#observablehq-sidebar summary")) {
summary.onmousedown = preventDoubleClick;
}

// copy code cells
document.addEventListener("pointerover", ({target}) => {
if (typeof navigator?.clipboard?.writeText !== "function") return;
if (target.nodeName === "PRE" && !target.getAttribute("data-copy")) {
target.addEventListener("pointermove", move);
target.addEventListener("pointerleave", out);
}
function out() {
target.removeEventListener("pointermove", move);
target.removeEventListener("pointerleave", out);
target.removeEventListener("click", copy);
target.removeAttribute("data-copy");
}
function move({offsetX: x}) {
if (30 + x > parseInt(getComputedStyle(target).width)) {
if (!target.getAttribute("data-copy")) {
target.setAttribute("data-copy", "copy");
target.addEventListener("click", copy);
}
} else {
if (target.getAttribute("data-copy")) {
target.removeAttribute("data-copy");
target.removeEventListener("click", copy);
}
}
}
async function copy() {
try {
await navigator.clipboard.writeText(target.textContent);
target.setAttribute("data-copy", "copied");
} catch {
target.setAttribute("data-copy", "error");
}
}
});
26 changes: 12 additions & 14 deletions public/style.css
Original file line number Diff line number Diff line change
Expand Up @@ -360,13 +360,7 @@ pre {
overflow-x: auto;
}

pre .language-md::after,
pre .language-tex::after,
pre .language-dot::after,
pre .language-mermaid::after,
pre .language-js::after,
pre .language-sh::after,
pre .language-sql::after {
pre code::after {
position: absolute;
right: 0;
top: 0;
Expand All @@ -377,13 +371,17 @@ pre .language-sql::after {
padding: 0.5rem 0.5rem 0.5rem 1rem;
}

pre .language-md::after { content: "md"; }
pre .language-js::after { content: "js"; }
pre .language-sh::after { content: "sh"; }
pre .language-sql::after { content: "sql"; }
pre .language-tex::after { content: "tex"; }
pre .language-dot::after { content: "dot"; }
pre .language-mermaid::after { content: "mermaid"; }
pre code.language-md::after { content: "md"; }
pre code.language-js::after { content: "js"; }
pre code.language-sh::after { content: "sh"; }
pre code.language-sql::after { content: "sql"; }
pre code.language-tex::after { content: "tex"; }
pre code.language-dot::after { content: "dot"; }
pre code.language-mermaid::after { content: "mermaid"; }
pre[data-copy="copy"] code::after { content: "copy"; }
pre[data-copy="copied"] code::after { content: "copied"; }
pre[data-copy="error"] code::after { content: "error"; }
pre code::after { pointer-events: none; }

input:not([type]),
input[type="email"],
Expand Down

0 comments on commit aca0666

Please sign in to comment.