fix copy btn and copy page btn

This commit is contained in:
iqubik
2026-04-04 22:25:40 +03:00
parent 38e6ae6f3d
commit f04fa01fe1
3 changed files with 50 additions and 12 deletions
+3 -2
View File
@@ -13,6 +13,7 @@ import {
} from '@mui/material';
import { Delete, Add, Link as LinkIcon, OpenInNew, ContentCopy, Dns, Router, Edit, MoreVert, Remove, Refresh } from '@mui/icons-material';
import api from '../api';
import { copyToClipboard } from '../utils/copyToClipboard';
import { Logger } from '../utils/logger';
interface Subscription {
@@ -345,7 +346,7 @@ export default function SubscriptionsPage() {
};
const handleCopyLink = async (uuid: string, tunnelId: string | number) => {
await navigator.clipboard.writeText(getSubscriptionUrl(uuid, tunnelId));
await copyToClipboard(getSubscriptionUrl(uuid, tunnelId));
setSnackbar({ open: true, type: 'success', message: 'Ссылка на подписку скопирована' });
};
@@ -602,7 +603,7 @@ export default function SubscriptionsPage() {
/>
</DialogContent>
<DialogActions>
<Button onClick={() => navigator.clipboard.writeText(currentLinks.join('\n'))}>Копировать все</Button>
<Button onClick={() => copyToClipboard(currentLinks.join('\n'))}>Копировать все</Button>
<Button onClick={() => setLinksOpen(false)}>Закрыть</Button>
</DialogActions>
</Dialog>
+25
View File
@@ -0,0 +1,25 @@
/**
* Универсальная функция копирования текста в буфер обмена.
* Работает и в secure (HTTPS/localhost), и в insecure (HTTP по IP) контекстах.
* navigator.clipboard недоступен при не-HTTPS/не-localhost соединениях.
*/
export async function copyToClipboard(text: string): Promise<void> {
if (navigator.clipboard && navigator.clipboard.writeText) {
await navigator.clipboard.writeText(text);
} else {
// Fallback для HTTP (не-localhost) — использует execCommand
const textarea = document.createElement('textarea');
textarea.value = text;
textarea.style.position = 'fixed';
textarea.style.left = '-9999px';
textarea.style.top = '-9999px';
document.body.appendChild(textarea);
textarea.focus();
textarea.select();
try {
document.execCommand('copy');
} finally {
document.body.removeChild(textarea);
}
}
}
@@ -259,16 +259,28 @@ export function generateSubscriptionHtmlWithQr(
function copyLink() {
const link = document.getElementById('link-text').innerText;
navigator.clipboard.writeText(link).then(() => {
const btn = document.querySelector('.action-btn');
const originalText = btn.innerHTML;
btn.innerHTML = 'Скопировано!';
btn.style.backgroundColor = 'var(--button-success)';
setTimeout(() => {
btn.innerHTML = originalText;
btn.style.backgroundColor = 'var(--button-bg)';
}, 2000);
});
let copied = false;
if (navigator.clipboard && navigator.clipboard.writeText) {
navigator.clipboard.writeText(link).then(() => { copied = true; });
}
if (!copied) {
const ta = document.createElement('textarea');
ta.value = link;
ta.style.position = 'fixed';
ta.style.left = '-9999px';
document.body.appendChild(ta);
ta.select();
document.execCommand('copy');
document.body.removeChild(ta);
}
const btn = document.querySelector('.action-btn');
const originalText = btn.innerHTML;
btn.innerHTML = 'Скопировано!';
btn.style.backgroundColor = 'var(--button-success)';
setTimeout(() => {
btn.innerHTML = originalText;
btn.style.backgroundColor = 'var(--button-bg)';
}, 2000);
}
</script>
</body>