feat: CopyFileButton

This commit is contained in:
EnixCoda 2019-11-09 00:50:54 +08:00
parent 6a897c0249
commit 54d7c675d7
No known key found for this signature in database
GPG key ID: 0C1A07377913A1DD
2 changed files with 71 additions and 45 deletions

View file

@ -0,0 +1,38 @@
import * as React from 'react'
import { copyElementContent, getCodeElement } from 'utils/DOMHelper'
type Props = {}
export function CopyFileButton(props: React.PropsWithChildren<Props>) {
const contents = {
success: 'Success!',
error: 'Copy failed!',
normal: 'Copy file',
}
const [content, setContent] = React.useState(contents.normal)
React.useEffect(() => {
if (content !== contents.normal) {
const timer = setTimeout(() => {
setContent(contents.normal)
}, 1000)
return () => clearTimeout(timer)
}
}, [content])
return (
<a
className="btn btn-sm BtnGroup-item copy-file-btn"
onClick={() => {
const codeElement = getCodeElement()
if (codeElement) {
if (copyElementContent(codeElement)) {
setContent(contents.success)
} else {
setContent(contents.error)
}
}
}}
>
{content}
</a>
)
}

View file

@ -1,10 +1,12 @@
/**
* this helper helps manipulating DOM
*/
import { raiseError } from 'analytics'
import { CopyFileButton } from 'components/CopyFileButton'
import * as NProgress from 'nprogress'
import * as PJAX from 'pjax'
import * as React from 'react'
import * as ReactDOM from 'react-dom'
NProgress.configure({ showSpinner: false })
@ -92,7 +94,6 @@ function getCurrentBranch() {
/**
* add the logo element into DOM
*
*/
function insertLogoMountPoint() {
const logoSelector = '.gitako .gitako-logo'
@ -178,57 +179,42 @@ function getRepoPageType() {
})
}
/**
* get text content of raw text content
*/
function getCodeElement() {
if (getCurrentPageType() === PAGE_TYPES.RAW_TEXT) {
const codeContentSelector = '.repository-content .data table'
const codeContentElement = $(codeContentSelector)
if (!codeContentElement) {
raiseError(new Error('cannot find code content element'))
}
return codeContentElement
}
}
/**
* add copy file content buttons to button groups
* click these buttons will copy file content to clipboard
*/
function attachCopyFileBtn() {
/**
* get text content of raw text content
*/
function getCodeElement() {
if (getCurrentPageType() === PAGE_TYPES.RAW_TEXT) {
const codeContentSelector = '.repository-content .data table'
const codeContentElement = $(codeContentSelector)
if (!codeContentElement) {
raiseError(new Error('cannot find code content element'))
}
return codeContentElement
}
}
/**
* change inner text of copy file button to give feedback
* @param {element} copyFileBtn
* @param {string} text
*/
function setTempCopyFileBtnText(copyFileBtn: HTMLButtonElement, text: string) {
copyFileBtn.innerText = text
window.setTimeout(() => (copyFileBtn.innerText = 'Copy file'), 1000)
}
if (getCurrentPageType() === PAGE_TYPES.RAW_TEXT) {
const btnGroupSelector = [
// the button group in file content header
'.repository-content > .Box > .Box-header .BtnGroup',
].join(', ')
const btnGroups = document.querySelectorAll(btnGroupSelector)
const buttonGroupSelector = '.repository-content > .Box > .Box-header .BtnGroup'
const buttonGroups = document.querySelectorAll(buttonGroupSelector)
btnGroups.forEach(btnGroup => {
const copyFileBtn = document.createElement('button')
copyFileBtn.classList.add('btn', 'btn-sm', 'BtnGroup-item', 'copy-file-btn')
copyFileBtn.innerText = 'Copy file'
copyFileBtn.addEventListener('click', () => {
const codeElement = getCodeElement()
if (codeElement) {
if (copyElementContent(codeElement)) {
setTempCopyFileBtnText(copyFileBtn, 'Success!')
} else {
setTempCopyFileBtnText(copyFileBtn, 'Copy failed!')
}
}
})
btnGroup.insertBefore(copyFileBtn, btnGroup.lastChild)
if (buttonGroups.length === 0) {
raiseError(new Error(`No button groups found`))
}
buttonGroups.forEach(buttonGroup => {
if (!buttonGroup.lastElementChild) return
const portal = ReactDOM.createPortal(React.createElement(CopyFileButton), buttonGroup)
// creating a element for mounting button into button group, somehow hack
const seedElementForButton = document.createElement('a')
buttonGroup.appendChild(seedElementForButton)
ReactDOM.render(portal, seedElementForButton)
buttonGroup.removeChild(seedElementForButton)
})
}
}
@ -384,9 +370,11 @@ export default {
loadWithPJAX,
attachCopyFileBtn,
attachCopySnippet,
copyElementContent,
decorateGitHubPageContent,
focusSearchInput,
focusFileExplorer,
getCodeElement,
getCurrentPageType,
getRepoPageType,
insertLogoMountPoint,