mirror of
https://github.com/coollabsio/coolify.git
synced 2026-11-06 13:10:37 -04:00
fix(ui): copy DNS record values on plain http instances
On non-secure origins the copy button falls back to execCommand('copy')
with a temporary textarea. The textarea was appended to <body>, outside
the x-trap focus trap of the DNS entries modal, so the trap pulled focus
back and the selection was lost before the copy. The button showed
success, but nothing was copied.
Append the textarea next to the button, select it explicitly, and
restore focus afterwards. "Copy all" now uses the shared copyButton
handler instead of its own duplicate fallback that ignored failures.
Closes #12075
This commit is contained in:
@@ -12,15 +12,22 @@ export function initializeCopyButtonComponent() {
|
||||
await navigator.clipboard.writeText(value);
|
||||
} else {
|
||||
// Deprecated, but the only copy path on plain http (non-secure contexts).
|
||||
// The textarea goes next to the button, not into <body>: a modal's x-trap
|
||||
// pulls focus back from nodes outside it, which clears the selection.
|
||||
const previousFocus = document.activeElement;
|
||||
const textarea = document.createElement('textarea');
|
||||
textarea.value = value;
|
||||
textarea.setAttribute('readonly', '');
|
||||
textarea.setAttribute('tabindex', '-1');
|
||||
textarea.style.position = 'fixed';
|
||||
textarea.style.left = '-9999px';
|
||||
document.body.appendChild(textarea);
|
||||
this.$el.after(textarea);
|
||||
textarea.focus({ preventScroll: true });
|
||||
textarea.select();
|
||||
textarea.setSelectionRange(0, textarea.value.length);
|
||||
const ok = document.execCommand('copy');
|
||||
document.body.removeChild(textarea);
|
||||
textarea.remove();
|
||||
previousFocus?.focus?.({ preventScroll: true });
|
||||
if (!ok) {
|
||||
throw new Error('Copy command was rejected.');
|
||||
}
|
||||
|
||||
@@ -223,39 +223,15 @@
|
||||
</div>
|
||||
|
||||
@if (filled($dnsCopyText))
|
||||
<div class="flex flex-wrap items-center justify-between gap-2"
|
||||
x-data="{
|
||||
copied: false,
|
||||
async copyAll(text) {
|
||||
try {
|
||||
if (navigator.clipboard?.writeText) {
|
||||
await navigator.clipboard.writeText(text);
|
||||
} else {
|
||||
const el = document.createElement('textarea');
|
||||
el.value = text;
|
||||
el.setAttribute('readonly', '');
|
||||
el.style.position = 'fixed';
|
||||
el.style.left = '-9999px';
|
||||
document.body.appendChild(el);
|
||||
el.select();
|
||||
document.execCommand('copy');
|
||||
document.body.removeChild(el);
|
||||
}
|
||||
this.copied = true;
|
||||
setTimeout(() => this.copied = false, 1000);
|
||||
} catch (e) {
|
||||
console.error('Copy failed', e);
|
||||
}
|
||||
}
|
||||
}">
|
||||
<div class="flex flex-wrap items-center justify-between gap-2">
|
||||
<p class="text-[12px] text-neutral-500 dark:text-fg-dim">
|
||||
{{ count($dnsHints) }}
|
||||
{{ count($dnsHints) === 1 ? 'entry' : 'entries' }}
|
||||
· BIND zone format
|
||||
</p>
|
||||
<button type="button" class="button shrink-0"
|
||||
title="Copy as BIND-compatible zone file"
|
||||
@click.prevent="copyAll(@js($dnsCopyText))">
|
||||
title="Copy as BIND-compatible zone file" x-data="copyButton"
|
||||
@click.prevent="copy(@js($dnsCopyText))">
|
||||
<span x-text="copied ? 'Copied' : 'Copy all'"></span>
|
||||
</button>
|
||||
</div>
|
||||
|
||||
Reference in New Issue
Block a user