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:
+46
-5
@@ -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");
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -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;
|
||||||
|
|||||||
@@ -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">
|
||||||
|
|||||||
Reference in New Issue
Block a user