From d84f7f07fcd37eedfa64d0e2387250218089392f Mon Sep 17 00:00:00 2001 From: EnixCoda Date: Sat, 16 Nov 2019 14:48:22 +0800 Subject: [PATCH] fix: detach button --- src/components/Clippy.tsx | 5 ++++- src/components/CopyFileButton.tsx | 6 +++++- src/utils/DOMHelper.ts | 28 ++++++++++++++-------------- 3 files changed, 23 insertions(+), 16 deletions(-) diff --git a/src/components/Clippy.tsx b/src/components/Clippy.tsx index bd397f1..86ba87f 100644 --- a/src/components/Clippy.tsx +++ b/src/components/Clippy.tsx @@ -6,6 +6,9 @@ type Props = { codeSnippetElement: Element } +const className = 'clippy-wrapper' +export const ClippyClassName = className + export function Clippy({ codeSnippetElement }: Props) { const [status, setStatus] = React.useState<'normal' | 'success' | 'fail'>('normal') React.useEffect(() => { @@ -24,7 +27,7 @@ export function Clippy({ codeSnippetElement }: Props) { }, []) return ( -
+
diff --git a/src/components/CopyFileButton.tsx b/src/components/CopyFileButton.tsx index 11bcda4..dba3066 100644 --- a/src/components/CopyFileButton.tsx +++ b/src/components/CopyFileButton.tsx @@ -1,8 +1,12 @@ import * as React from 'react' +import { cx } from 'utils/cx' import { copyElementContent, getCodeElement } from 'utils/DOMHelper' type Props = {} +const className = 'gitako-copy-file-button' +export const copyFileButtonClassName = className + export function CopyFileButton(props: React.PropsWithChildren) { const contents = { success: 'Success!', @@ -20,7 +24,7 @@ export function CopyFileButton(props: React.PropsWithChildren) { }, [content]) return ( { const codeElement = getCodeElement() if (codeElement) { diff --git a/src/utils/DOMHelper.ts b/src/utils/DOMHelper.ts index 8c5782e..613f5c4 100644 --- a/src/utils/DOMHelper.ts +++ b/src/utils/DOMHelper.ts @@ -2,8 +2,8 @@ * this helper helps manipulating DOM */ import { raiseError } from 'analytics' -import { Clippy } from 'components/Clippy' -import { CopyFileButton } from 'components/CopyFileButton' +import { Clippy, ClippyClassName } from 'components/Clippy' +import { CopyFileButton, copyFileButtonClassName } from 'components/CopyFileButton' import * as NProgress from 'nprogress' import * as PJAX from 'pjax' import * as React from 'react' @@ -130,7 +130,7 @@ const pjax = new PJAX({ }) export function loadWithPJAX(URL: string) { - NProgress.start() + mountTopProgressBar() pjax.loadUrl(URL, { scrollTo: 0 }) } @@ -208,20 +208,19 @@ export function attachCopyFileBtn() { raiseError(new Error(`No button groups found`)) } - const buttons: HTMLElement[] = [] buttonGroups.forEach(async buttonGroup => { if (!buttonGroup.lastElementChild) return const button = await renderReact(React.createElement(CopyFileButton)) if (button instanceof HTMLElement) { buttonGroup.appendChild(button) - buttons.push(button) } }) - // TODO: query from DOM again when detach - return () => + return () => { + const buttons = document.querySelectorAll(`.${copyFileButtonClassName}`) buttons.forEach(button => { button.parentElement?.removeChild(button) }) + } } } @@ -248,13 +247,12 @@ export function attachCopySnippet() { return $( readmeArticleSelector, readmeElement => { - const buttons: HTMLElement[] = [] - readmeElement.addEventListener('mouseover', async ({ target }) => { + const mouseOverCallback = async ({ target }: Event): Promise => { if (target instanceof Element && target.nodeName === 'PRE') { if ( target.previousSibling === null || !(target.previousSibling instanceof Element) || - !target.previousSibling.classList.contains('clippy-wrapper') + !target.previousSibling.classList.contains(ClippyClassName) ) { /** *
@@ -270,17 +268,19 @@ export function attachCopySnippet() { ) if (clippyElement instanceof HTMLElement) { target.parentNode.insertBefore(clippyElement, target) - buttons.push(clippyElement) } } } } - }) - // TODO: query from DOM again when detach - return () => + } + readmeElement.addEventListener('mouseover', mouseOverCallback) + return () => { + readmeElement.removeEventListener('mouseover', mouseOverCallback) + const buttons = document.querySelectorAll(`.${ClippyClassName}`) buttons.forEach(button => { button.parentElement?.removeChild(button) }) + } }, () => { const plainReadmeSelector = '.repository-content div#readme .plain'