fix: make copy buttons work on HTTP panel pages

Read share links from input fields and fall back to execCommand when
Clipboard API is unavailable outside secure contexts.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
dekun
2026-06-16 10:17:04 +08:00
parent d339fbd917
commit 9ebab211dd
3 changed files with 57 additions and 10 deletions
+46 -5
View File
@@ -10,14 +10,55 @@ function apiUrl(path) {
return `${base}${path}`; return `${base}${path}`;
} }
document.querySelectorAll("[data-copy]").forEach((btn) => { function copyText(text) {
btn.addEventListener("click", async () => { if (navigator.clipboard && window.isSecureContext) {
const text = btn.dataset.copy; return navigator.clipboard.writeText(text);
}
return new Promise((resolve, reject) => {
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();
try { try {
await navigator.clipboard.writeText(text); if (document.execCommand("copy")) {
resolve();
} else {
reject(new Error("execCommand failed"));
}
} catch (err) {
reject(err);
} finally {
document.body.removeChild(ta);
}
});
}
document.querySelectorAll(".copy-row").forEach((row) => {
const input = row.querySelector(".copy-input");
const btn = row.querySelector(".copy-btn");
if (!input || !btn) return;
input.addEventListener("click", () => {
input.select();
input.setSelectionRange(0, input.value.length);
});
btn.addEventListener("click", async () => {
const text = input.value;
if (!text) {
toast("没有可复制的内容");
return;
}
try {
input.select();
input.setSelectionRange(0, text.length);
await copyText(text);
toast("已复制到剪贴板"); toast("已复制到剪贴板");
} catch { } catch {
toast("复制失败,请手动选择文本"); toast("复制失败,请选中上方链接后 Ctrl+C");
} }
}); });
}); });
+7 -1
View File
@@ -70,7 +70,8 @@ body {
input[type="text"], input[type="text"],
input[type="password"], input[type="password"],
input[readonly] { input[readonly],
input.copy-input {
width: 100%; width: 100%;
padding: 10px 12px; padding: 10px 12px;
border-radius: 8px; border-radius: 8px;
@@ -79,6 +80,11 @@ input[readonly] {
color: var(--text); color: var(--text);
} }
input.copy-input {
cursor: pointer;
font-size: 0.82rem;
}
.btn { .btn {
border: 1px solid var(--border); border: 1px solid var(--border);
background: #111827; background: #111827;
+4 -4
View File
@@ -75,15 +75,15 @@
<div class="field"> <div class="field">
<label>VLESS + Reality</label> <label>VLESS + Reality</label>
<div class="copy-row"> <div class="copy-row">
<input readonly value="{{ node.links.vless }}"> <input class="copy-input" readonly value="{{ node.links.vless }}">
<button class="btn" data-copy="{{ node.links.vless }}">复制</button> <button type="button" class="btn copy-btn">复制</button>
</div> </div>
</div> </div>
<div class="field"> <div class="field">
<label>Hysteria2</label> <label>Hysteria2</label>
<div class="copy-row"> <div class="copy-row">
<input readonly value="{{ node.links.hy2 }}"> <input class="copy-input" readonly value="{{ node.links.hy2 }}">
<button class="btn" data-copy="{{ node.links.hy2 }}">复制</button> <button type="button" class="btn copy-btn">复制</button>
</div> </div>
</div> </div>
<div class="node-actions"> <div class="node-actions">