copy behavior
This commit is contained in:
@@ -155,6 +155,25 @@ function escapeHtml(s) {
|
||||
return (s || "").replace(/[&<>"']/g, (c) => ({ "&": "&", "<": "<", ">": ">", '"': """, "'": "'" }[c]));
|
||||
}
|
||||
|
||||
// navigator.clipboard only exists in secure contexts (HTTPS/localhost);
|
||||
// fall back to a hidden textarea + execCommand for plain-HTTP LAN use.
|
||||
async function copyText(text) {
|
||||
if (window.isSecureContext && navigator.clipboard) {
|
||||
try { await navigator.clipboard.writeText(text); return true; } catch (e) { /* fall through */ }
|
||||
}
|
||||
const ta = document.createElement("textarea");
|
||||
ta.value = text;
|
||||
ta.setAttribute("readonly", "");
|
||||
ta.style.position = "fixed";
|
||||
ta.style.left = "-9999px";
|
||||
document.body.appendChild(ta);
|
||||
ta.select();
|
||||
let ok = false;
|
||||
try { ok = document.execCommand("copy"); } catch (e) {}
|
||||
ta.remove();
|
||||
return ok;
|
||||
}
|
||||
|
||||
async function boot() {
|
||||
try {
|
||||
const me = await api("GET", "/api/me");
|
||||
@@ -261,9 +280,22 @@ function showCli() {
|
||||
const back = backButton(showHome);
|
||||
const installCmd = "curl -fsSL " + window.location.origin + "/" + state.user + "/cli | bash";
|
||||
const cmdEl = el("code", { class: "cli-install-cmd", text: installCmd });
|
||||
const copyBtn = el("button", {
|
||||
class: "btn", text: "Copy",
|
||||
onclick: () => { navigator.clipboard?.writeText(installCmd); copyBtn.textContent = "Copied!"; setTimeout(() => { copyBtn.textContent = "Copy"; }, 2000); },
|
||||
const CLIP_ICON = '<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><rect x="8" y="2" width="8" height="4" rx="1" ry="1"></rect><path d="M16 4h2a2 2 0 0 1 2 2v14a2 2 0 0 1-2 2H6a2 2 0 0 1-2-2V6a2 2 0 0 1 2-2h2"></path></svg>';
|
||||
const CHECK_ICON = '<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><polyline points="20 6 9 17 4 12"></polyline></svg>';
|
||||
const copyBtn = el("button", { class: "btn icon-btn", title: "Copy install command", "aria-label": "Copy install command", html: CLIP_ICON });
|
||||
copyBtn.addEventListener("click", async () => {
|
||||
const ok = await copyText(installCmd);
|
||||
if (!ok) { // last resort: select the text so the user can ⌘C
|
||||
const sel = window.getSelection();
|
||||
const range = document.createRange();
|
||||
range.selectNodeContents(cmdEl);
|
||||
sel.removeAllRanges();
|
||||
sel.addRange(range);
|
||||
return;
|
||||
}
|
||||
copyBtn.innerHTML = CHECK_ICON;
|
||||
copyBtn.classList.add("ok");
|
||||
setTimeout(() => { copyBtn.innerHTML = CLIP_ICON; copyBtn.classList.remove("ok"); }, 2000);
|
||||
});
|
||||
|
||||
const card = el("div", { class: "help-card" }, [
|
||||
|
||||
Reference in New Issue
Block a user