code.gitea.io/gitea@v1.21.7/web_src/js/features/copycontent.js (about) 1 import {clippie} from 'clippie'; 2 import {showTemporaryTooltip} from '../modules/tippy.js'; 3 import {convertImage} from '../utils.js'; 4 import {GET} from '../modules/fetch.js'; 5 6 const {i18n} = window.config; 7 8 export function initCopyContent() { 9 const btn = document.getElementById('copy-content'); 10 if (!btn || btn.classList.contains('disabled')) return; 11 12 btn.addEventListener('click', async () => { 13 if (btn.classList.contains('is-loading')) return; 14 let content; 15 let isRasterImage = false; 16 const link = btn.getAttribute('data-link'); 17 18 // when data-link is present, we perform a fetch. this is either because 19 // the text to copy is not in the DOM or it is an image which should be 20 // fetched to copy in full resolution 21 if (link) { 22 btn.classList.add('is-loading', 'small-loading-icon'); 23 try { 24 const res = await GET(link, {credentials: 'include', redirect: 'follow'}); 25 const contentType = res.headers.get('content-type'); 26 27 if (contentType.startsWith('image/') && !contentType.startsWith('image/svg')) { 28 isRasterImage = true; 29 content = await res.blob(); 30 } else { 31 content = await res.text(); 32 } 33 } catch { 34 return showTemporaryTooltip(btn, i18n.copy_error); 35 } finally { 36 btn.classList.remove('is-loading', 'small-loading-icon'); 37 } 38 } else { // text, read from DOM 39 const lineEls = document.querySelectorAll('.file-view .lines-code'); 40 content = Array.from(lineEls, (el) => el.textContent).join(''); 41 } 42 43 // try copy original first, if that fails and it's an image, convert it to png 44 const success = await clippie(content); 45 if (success) { 46 showTemporaryTooltip(btn, i18n.copy_success); 47 } else { 48 if (isRasterImage) { 49 const success = await clippie(await convertImage(content, 'image/png')); 50 showTemporaryTooltip(btn, success ? i18n.copy_success : i18n.copy_error); 51 } else { 52 showTemporaryTooltip(btn, i18n.copy_error); 53 } 54 } 55 }); 56 }