feat: use global delegation for copy code interaction

pull/1262/head
Evan You 3 years ago
parent 1e312f5792
commit b5bd73f630

@ -1,23 +1,37 @@
import { nextTick, watch } from 'vue'
import { inBrowser, useData } from 'vitepress'
import { inBrowser } from '../utils.js'
export function useCopyCode() {
const { page } = useData()
if (inBrowser)
watch(
() => page.value.relativePath,
() => {
nextTick(() => {
document
.querySelectorAll<HTMLSpanElement>(
'.vp-doc div[class*="language-"] > button.copy'
)
.forEach(handleElement)
if (inBrowser) {
window.addEventListener('click', (e) => {
const el = e.target as HTMLElement
if (el.matches('div[class*="language-"] > button.copy')) {
const parent = el.parentElement
const sibling = el.nextElementSibling
?.nextElementSibling as HTMLPreElement | null
if (!parent || !sibling) {
return
}
const isShell = /language-(shellscript|shell|bash|sh|zsh)/.test(
parent.classList.toString()
)
let { innerText: text = '' } = sibling
if (isShell) {
text = text.replace(/^ *(\$|>) /gm, '')
}
copyToClipboard(text).then(() => {
el.classList.add('copied')
setTimeout(() => {
el.classList.remove('copied')
el.blur()
}, 2000)
})
},
{ immediate: true, flush: 'post' }
)
}
})
}
}
async function copyToClipboard(text: string) {
@ -63,32 +77,3 @@ async function copyToClipboard(text: string) {
}
}
}
function handleElement(el: HTMLElement) {
el.onclick = () => {
const parent = el.parentElement
const sibling = el.nextElementSibling
?.nextElementSibling as HTMLPreElement | null
if (!parent || !sibling) {
return
}
const isShell = /language-(shellscript|shell|bash|sh|zsh)/.test(
parent.classList.toString()
)
let { innerText: text = '' } = sibling
if (isShell) {
text = text.replace(/^ *(\$|>) /gm, '')
}
copyToClipboard(text).then(() => {
el.classList.add('copied')
setTimeout(() => {
el.classList.remove('copied')
el.blur()
}, 2000)
})
}
}

@ -16,6 +16,7 @@ import { usePrefetch } from './composables/preFetch.js'
import { dataSymbol, initData } from './data.js'
import { Content } from './components/Content.js'
import { ClientOnly } from './components/ClientOnly.js'
import { useCopyCode } from './composables/copyCode.js'
const NotFound = Theme.NotFound || (() => '404 Not Found')
@ -40,6 +41,9 @@ const VitePressApp = defineComponent({
usePrefetch()
}
// setup global copy code handler
useCopyCode()
if (Theme.setup) Theme.setup()
return () => h(Theme.Layout)
}

@ -1,6 +1,5 @@
<script setup lang="ts">
import { useRoute, useData } from 'vitepress'
import { useCopyCode } from '../composables/copy-code.js'
import { useSidebar } from '../composables/sidebar.js'
import VPPage from './VPPage.vue'
import VPHome from './VPHome.vue'
@ -12,8 +11,6 @@ const { frontmatter } = useData()
const { hasSidebar } = useSidebar()
const NotFound = inject('NotFound')
useCopyCode()
</script>
<template>

Loading…
Cancel
Save