Improve legacy clipboard copy handling

Refactor ClipboardManager._legacyCopy to better handle focus and selection when copying. The textarea is now appended to the active element's parent (or body) and placed off-screen with aria-hidden and readonly attributes. The code preserves and restores the previous document selection and active element, uses focus({preventScroll: true}) to avoid scrolling, and returns the execCommand('copy') result. This makes legacy copy behavior more robust and less disruptive to the page state.
This commit is contained in:
MHSanaei 2026-05-23 14:56:04 +02:00
parent 6a6a662a2e
commit 03aa619b91
No known key found for this signature in database
GPG key ID: 7E4060F2FBE5AB7A

View file

@ -550,31 +550,45 @@ export class ClipboardManager {
} }
static _legacyCopy(text) { static _legacyCopy(text) {
try {
const textarea = document.createElement('textarea'); const textarea = document.createElement('textarea');
textarea.value = text; textarea.value = text;
textarea.setAttribute('readonly', ''); textarea.setAttribute('readonly', '');
textarea.style.position = 'fixed'; textarea.setAttribute('aria-hidden', 'true');
textarea.style.position = 'absolute';
textarea.style.left = '-9999px';
textarea.style.top = '0'; textarea.style.top = '0';
textarea.style.left = '0'; textarea.style.opacity = '1';
textarea.style.width = '1em';
textarea.style.height = '1em'; const active = document.activeElement;
textarea.style.padding = '0'; const host = (active && active !== document.body && active.parentElement)
textarea.style.border = '0'; ? active.parentElement
textarea.style.outline = 'none'; : document.body;
textarea.style.boxShadow = 'none'; host.appendChild(textarea);
textarea.style.background = 'transparent';
textarea.style.opacity = '0'; const prevSelection = document.getSelection()?.rangeCount
document.body.appendChild(textarea); ? document.getSelection().getRangeAt(0)
textarea.focus(); : null;
let ok = false;
try {
textarea.focus({ preventScroll: true });
textarea.select(); textarea.select();
textarea.setSelectionRange(0, text.length); textarea.setSelectionRange(0, text.length);
const ok = document.execCommand('copy'); ok = document.execCommand('copy');
document.body.removeChild(textarea);
return ok;
} catch { } catch {
return false; ok = false;
} }
host.removeChild(textarea);
if (active && typeof active.focus === 'function') {
try { active.focus({ preventScroll: true }); } catch { /* ignore */ }
}
if (prevSelection) {
const sel = document.getSelection();
sel?.removeAllRanges();
sel?.addRange(prevSelection);
}
return ok;
} }
} }