code.gitea.io/gitea@v1.22.3/web_src/js/markup/anchors.js (about) 1 import {svg} from '../svg.js'; 2 3 const addPrefix = (str) => `user-content-${str}`; 4 const removePrefix = (str) => str.replace(/^user-content-/, ''); 5 const hasPrefix = (str) => str.startsWith('user-content-'); 6 7 // scroll to anchor while respecting the `user-content` prefix that exists on the target 8 function scrollToAnchor(encodedId) { 9 if (!encodedId) return; 10 const id = decodeURIComponent(encodedId); 11 const prefixedId = addPrefix(id); 12 let el = document.getElementById(prefixedId); 13 14 // check for matching user-generated `a[name]` 15 if (!el) { 16 const nameAnchors = document.getElementsByName(prefixedId); 17 if (nameAnchors.length) { 18 el = nameAnchors[0]; 19 } 20 } 21 22 // compat for links with old 'user-content-' prefixed hashes 23 if (!el && hasPrefix(id)) { 24 return document.getElementById(id)?.scrollIntoView(); 25 } 26 27 el?.scrollIntoView(); 28 } 29 30 export function initMarkupAnchors() { 31 const markupEls = document.querySelectorAll('.markup'); 32 if (!markupEls.length) return; 33 34 for (const markupEl of markupEls) { 35 // create link icons for markup headings, the resulting link href will remove `user-content-` 36 for (const heading of markupEl.querySelectorAll('h1, h2, h3, h4, h5, h6')) { 37 const a = document.createElement('a'); 38 a.classList.add('anchor'); 39 a.setAttribute('href', `#${encodeURIComponent(removePrefix(heading.id))}`); 40 a.innerHTML = svg('octicon-link'); 41 heading.prepend(a); 42 } 43 44 // remove `user-content-` prefix from links so they don't show in url bar when clicked 45 for (const a of markupEl.querySelectorAll('a[href^="#"]')) { 46 const href = a.getAttribute('href'); 47 if (!href.startsWith('#user-content-')) continue; 48 a.setAttribute('href', `#${removePrefix(href.substring(1))}`); 49 } 50 51 // add `user-content-` prefix to user-generated `a[name]` link targets 52 // TODO: this prefix should be added in backend instead 53 for (const a of markupEl.querySelectorAll('a[name]')) { 54 const name = a.getAttribute('name'); 55 if (!name) continue; 56 a.setAttribute('name', addPrefix(a.name)); 57 } 58 59 for (const a of markupEl.querySelectorAll('a[href^="#"]')) { 60 a.addEventListener('click', (e) => { 61 scrollToAnchor(e.currentTarget.getAttribute('href')?.substring(1)); 62 }); 63 } 64 } 65 66 // scroll to anchor unless the browser has already scrolled somewhere during page load 67 if (!document.querySelector(':target')) { 68 scrollToAnchor(window.location.hash?.substring(1)); 69 } 70 }