Skip to content

Commit 2935ed2

Browse files
cfmjbrc-dd
andauthored
fix: copy code in non-secure contexts (#792)
Co-authored-by: Divyansh Singh <40380293+brc-dd@users.noreply.github.com>
1 parent 48fae52 commit 2935ed2

File tree

1 file changed

+45
-1
lines changed

1 file changed

+45
-1
lines changed

src/client/theme-default/composables/copy-code.ts

+45-1
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,50 @@ export function useCopyCode() {
2020
)
2121
}
2222

23+
async function copyToClipboard(text: string) {
24+
try {
25+
return navigator.clipboard.writeText(text)
26+
} catch {
27+
const element = document.createElement('textarea')
28+
const previouslyFocusedElement = document.activeElement
29+
30+
element.value = text
31+
32+
// Prevent keyboard from showing on mobile
33+
element.setAttribute('readonly', '')
34+
35+
element.style.contain = 'strict'
36+
element.style.position = 'absolute'
37+
element.style.left = '-9999px'
38+
element.style.fontSize = '12pt' // Prevent zooming on iOS
39+
40+
const selection = document.getSelection()
41+
const originalRange = selection
42+
? selection.rangeCount > 0 && selection.getRangeAt(0)
43+
: null
44+
45+
document.body.appendChild(element)
46+
element.select()
47+
48+
// Explicit selection workaround for iOS
49+
element.selectionStart = 0
50+
element.selectionEnd = text.length
51+
52+
document.execCommand('copy')
53+
document.body.removeChild(element)
54+
55+
if (originalRange) {
56+
selection!.removeAllRanges() // originalRange can't be truthy when selection is falsy
57+
selection!.addRange(originalRange)
58+
}
59+
60+
// Get the focus back on the previously focused element, if any
61+
if (previouslyFocusedElement) {
62+
;(previouslyFocusedElement as HTMLElement).focus()
63+
}
64+
}
65+
}
66+
2367
function handleElement(el: HTMLElement) {
2468
el.onclick = () => {
2569
const parent = el.parentElement
@@ -38,7 +82,7 @@ function handleElement(el: HTMLElement) {
3882
text = text.replace(/^ *\$ /gm, '')
3983
}
4084

41-
navigator.clipboard.writeText(text).then(() => {
85+
copyToClipboard(text).then(() => {
4286
el.classList.add('copied')
4387
setTimeout(() => {
4488
el.classList.remove('copied')

0 commit comments

Comments
 (0)