diff --git a/src/client/theme-default/composables/copy-code.ts b/src/client/app/composables/copyCode.ts similarity index 54% rename from src/client/theme-default/composables/copy-code.ts rename to src/client/app/composables/copyCode.ts index a705433331f..58b60807cb9 100644 --- a/src/client/theme-default/composables/copy-code.ts +++ b/src/client/app/composables/copyCode.ts @@ -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( - '.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) - }) - } -} diff --git a/src/client/app/index.ts b/src/client/app/index.ts index c7d0e2e3a76..84bd1c23da8 100644 --- a/src/client/app/index.ts +++ b/src/client/app/index.ts @@ -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) } diff --git a/src/client/theme-default/components/VPContent.vue b/src/client/theme-default/components/VPContent.vue index 35a27b77d31..86aca8623de 100644 --- a/src/client/theme-default/components/VPContent.vue +++ b/src/client/theme-default/components/VPContent.vue @@ -1,6 +1,5 @@