mirror of
				https://github.com/go-gitea/gitea.git
				synced 2025-10-26 12:27:06 +00:00 
			
		
		
		
	Use clippie module to copy to clipboard (#23801)
Externalize clipboard copying to the [clippie](https://github.com/silverwind/clippie) module which I feel I can maintain outside this repo for shared benefit with my other projects. The module is feature-equivalent to the previous code and has one improvement where it sets `aria-hidden` on the fallback textarea, preventing screen readers from picking it up. Also it support `Array` of `content` as well to copy multiple items at once, in case it's ever needed.
This commit is contained in:
		
							
								
								
									
										6
									
								
								package-lock.json
									
									
									
										generated
									
									
									
								
							
							
						
						
									
										6
									
								
								package-lock.json
									
									
									
										generated
									
									
									
								
							| @@ -19,6 +19,7 @@ | |||||||
|         "add-asset-webpack-plugin": "2.0.1", |         "add-asset-webpack-plugin": "2.0.1", | ||||||
|         "ansi-to-html": "0.7.2", |         "ansi-to-html": "0.7.2", | ||||||
|         "asciinema-player": "3.2.0", |         "asciinema-player": "3.2.0", | ||||||
|  |         "clippie": "3.1.4", | ||||||
|         "css-loader": "6.7.3", |         "css-loader": "6.7.3", | ||||||
|         "dropzone": "6.0.0-beta.2", |         "dropzone": "6.0.0-beta.2", | ||||||
|         "easymde": "2.18.0", |         "easymde": "2.18.0", | ||||||
| @@ -2762,6 +2763,11 @@ | |||||||
|         "url": "https://github.com/chalk/strip-ansi?sponsor=1" |         "url": "https://github.com/chalk/strip-ansi?sponsor=1" | ||||||
|       } |       } | ||||||
|     }, |     }, | ||||||
|  |     "node_modules/clippie": { | ||||||
|  |       "version": "3.1.4", | ||||||
|  |       "resolved": "https://registry.npmjs.org/clippie/-/clippie-3.1.4.tgz", | ||||||
|  |       "integrity": "sha512-jrW6sG1zcTEQr5MtCXJzszNmHWV9Fkaco8sAqFeuOApNFP/lRFcUi4JABMmxBJwFZLIvbw2BY3G5E+BjBqZMdQ==" | ||||||
|  |     }, | ||||||
|     "node_modules/cliui": { |     "node_modules/cliui": { | ||||||
|       "version": "7.0.4", |       "version": "7.0.4", | ||||||
|       "resolved": "https://registry.npmjs.org/cliui/-/cliui-7.0.4.tgz", |       "resolved": "https://registry.npmjs.org/cliui/-/cliui-7.0.4.tgz", | ||||||
|   | |||||||
| @@ -19,6 +19,7 @@ | |||||||
|     "add-asset-webpack-plugin": "2.0.1", |     "add-asset-webpack-plugin": "2.0.1", | ||||||
|     "ansi-to-html": "0.7.2", |     "ansi-to-html": "0.7.2", | ||||||
|     "asciinema-player": "3.2.0", |     "asciinema-player": "3.2.0", | ||||||
|  |     "clippie": "3.1.4", | ||||||
|     "css-loader": "6.7.3", |     "css-loader": "6.7.3", | ||||||
|     "dropzone": "6.0.0-beta.2", |     "dropzone": "6.0.0-beta.2", | ||||||
|     "easymde": "2.18.0", |     "easymde": "2.18.0", | ||||||
|   | |||||||
| @@ -1,48 +1,9 @@ | |||||||
| import {showTemporaryTooltip} from '../modules/tippy.js'; | import {showTemporaryTooltip} from '../modules/tippy.js'; | ||||||
| import {toAbsoluteUrl} from '../utils.js'; | import {toAbsoluteUrl} from '../utils.js'; | ||||||
|  | import {clippie} from 'clippie'; | ||||||
|  |  | ||||||
| const {copy_success, copy_error} = window.config.i18n; | const {copy_success, copy_error} = window.config.i18n; | ||||||
|  |  | ||||||
| export async function copyToClipboard(content) { |  | ||||||
|   if (content instanceof Blob) { |  | ||||||
|     const item = new ClipboardItem({[content.type]: content}); |  | ||||||
|     await navigator.clipboard.write([item]); |  | ||||||
|   } else { // text |  | ||||||
|     try { |  | ||||||
|       await navigator.clipboard.writeText(content); |  | ||||||
|     } catch { |  | ||||||
|       return fallbackCopyToClipboard(content); |  | ||||||
|     } |  | ||||||
|   } |  | ||||||
|   return true; |  | ||||||
| } |  | ||||||
|  |  | ||||||
| // Fallback to use if navigator.clipboard doesn't exist. Achieved via creating |  | ||||||
| // a temporary textarea element, selecting the text, and using document.execCommand |  | ||||||
| function fallbackCopyToClipboard(text) { |  | ||||||
|   if (!document.execCommand) return false; |  | ||||||
|  |  | ||||||
|   const tempTextArea = document.createElement('textarea'); |  | ||||||
|   tempTextArea.value = text; |  | ||||||
|  |  | ||||||
|   // avoid scrolling |  | ||||||
|   tempTextArea.style.top = 0; |  | ||||||
|   tempTextArea.style.left = 0; |  | ||||||
|   tempTextArea.style.position = 'fixed'; |  | ||||||
|  |  | ||||||
|   document.body.appendChild(tempTextArea); |  | ||||||
|  |  | ||||||
|   tempTextArea.select(); |  | ||||||
|  |  | ||||||
|   // if unsecure (not https), there is no navigator.clipboard, but we can still |  | ||||||
|   // use document.execCommand to copy to clipboard |  | ||||||
|   const success = document.execCommand('copy'); |  | ||||||
|  |  | ||||||
|   document.body.removeChild(tempTextArea); |  | ||||||
|  |  | ||||||
|   return success; |  | ||||||
| } |  | ||||||
|  |  | ||||||
| // For all DOM elements with [data-clipboard-target] or [data-clipboard-text], | // For all DOM elements with [data-clipboard-target] or [data-clipboard-text], | ||||||
| // this copy-to-clipboard will work for them | // this copy-to-clipboard will work for them | ||||||
| export function initGlobalCopyToClipboardListener() { | export function initGlobalCopyToClipboardListener() { | ||||||
| @@ -61,7 +22,7 @@ export function initGlobalCopyToClipboardListener() { | |||||||
|         e.preventDefault(); |         e.preventDefault(); | ||||||
|  |  | ||||||
|         (async() => { |         (async() => { | ||||||
|           const success = await copyToClipboard(text); |           const success = await clippie(text); | ||||||
|           showTemporaryTooltip(target, success ? copy_success : copy_error); |           showTemporaryTooltip(target, success ? copy_success : copy_error); | ||||||
|         })(); |         })(); | ||||||
|  |  | ||||||
|   | |||||||
| @@ -1,11 +1,11 @@ | |||||||
| import {copyToClipboard} from './clipboard.js'; | import {clippie} from 'clippie'; | ||||||
| import {showTemporaryTooltip} from '../modules/tippy.js'; | import {showTemporaryTooltip} from '../modules/tippy.js'; | ||||||
| import {convertImage} from '../utils.js'; | import {convertImage} from '../utils.js'; | ||||||
|  |  | ||||||
| const {i18n} = window.config; | const {i18n} = window.config; | ||||||
|  |  | ||||||
| async function doCopy(content, btn) { | async function doCopy(content, btn) { | ||||||
|   const success = await copyToClipboard(content); |   const success = await clippie(content); | ||||||
|   showTemporaryTooltip(btn, success ? i18n.copy_success : i18n.copy_error); |   showTemporaryTooltip(btn, success ? i18n.copy_success : i18n.copy_error); | ||||||
| } | } | ||||||
|  |  | ||||||
|   | |||||||
| @@ -2,7 +2,7 @@ import $ from 'jquery'; | |||||||
| import {svg} from '../svg.js'; | import {svg} from '../svg.js'; | ||||||
| import {invertFileFolding} from './file-fold.js'; | import {invertFileFolding} from './file-fold.js'; | ||||||
| import {createTippy} from '../modules/tippy.js'; | import {createTippy} from '../modules/tippy.js'; | ||||||
| import {copyToClipboard} from './clipboard.js'; | import {clippie} from 'clippie'; | ||||||
| import {toAbsoluteUrl} from '../utils.js'; | import {toAbsoluteUrl} from '../utils.js'; | ||||||
|  |  | ||||||
| export const singleAnchorRegex = /^#(L|n)([1-9][0-9]*)$/; | export const singleAnchorRegex = /^#(L|n)([1-9][0-9]*)$/; | ||||||
| @@ -190,7 +190,7 @@ export function initRepoCodeView() { | |||||||
|     currentTarget.closest('tr').outerHTML = blob; |     currentTarget.closest('tr').outerHTML = blob; | ||||||
|   }); |   }); | ||||||
|   $(document).on('click', '.copy-line-permalink', async (e) => { |   $(document).on('click', '.copy-line-permalink', async (e) => { | ||||||
|     const success = await copyToClipboard(toAbsoluteUrl(e.currentTarget.getAttribute('data-url'))); |     const success = await clippie(toAbsoluteUrl(e.currentTarget.getAttribute('data-url'))); | ||||||
|     if (!success) return; |     if (!success) return; | ||||||
|     document.querySelector('.code-line-button')?._tippy?.hide(); |     document.querySelector('.code-line-button')?._tippy?.hide(); | ||||||
|   }); |   }); | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user
	 silverwind
					silverwind