From 2935ed22954010fa0d48d0625e5f2b0136991e0b Mon Sep 17 00:00:00 2001 From: Linmj <33464433+cfmj@users.noreply.github.com> Date: Thu, 16 Jun 2022 20:52:15 +0800 Subject: [PATCH] fix: copy code in non-secure contexts (#792) Co-authored-by: Divyansh Singh <40380293+brc-dd@users.noreply.github.com> --- .../theme-default/composables/copy-code.ts | 46 ++++++++++++++++++- 1 file changed, 45 insertions(+), 1 deletion(-) diff --git a/src/client/theme-default/composables/copy-code.ts b/src/client/theme-default/composables/copy-code.ts index bd5d73ab8f9..35aca1c1057 100644 --- a/src/client/theme-default/composables/copy-code.ts +++ b/src/client/theme-default/composables/copy-code.ts @@ -20,6 +20,50 @@ export function useCopyCode() { ) } +async function copyToClipboard(text: string) { + try { + return navigator.clipboard.writeText(text) + } catch { + const element = document.createElement('textarea') + const previouslyFocusedElement = document.activeElement + + element.value = text + + // Prevent keyboard from showing on mobile + element.setAttribute('readonly', '') + + element.style.contain = 'strict' + element.style.position = 'absolute' + element.style.left = '-9999px' + element.style.fontSize = '12pt' // Prevent zooming on iOS + + const selection = document.getSelection() + const originalRange = selection + ? selection.rangeCount > 0 && selection.getRangeAt(0) + : null + + document.body.appendChild(element) + element.select() + + // Explicit selection workaround for iOS + element.selectionStart = 0 + element.selectionEnd = text.length + + document.execCommand('copy') + document.body.removeChild(element) + + if (originalRange) { + selection!.removeAllRanges() // originalRange can't be truthy when selection is falsy + selection!.addRange(originalRange) + } + + // Get the focus back on the previously focused element, if any + if (previouslyFocusedElement) { + ;(previouslyFocusedElement as HTMLElement).focus() + } + } +} + function handleElement(el: HTMLElement) { el.onclick = () => { const parent = el.parentElement @@ -38,7 +82,7 @@ function handleElement(el: HTMLElement) { text = text.replace(/^ *\$ /gm, '') } - navigator.clipboard.writeText(text).then(() => { + copyToClipboard(text).then(() => { el.classList.add('copied') setTimeout(() => { el.classList.remove('copied')