mirror of
https://codeberg.org/forgejo/forgejo
synced 2024-11-28 04:36:11 +01:00
2e49c82f80
This seeks to fix the bug reported on issue #29196. Cause: ID's with custom characters (- , _ , etc.), were not linking correctly in the Markdown file when rendered in the browser because the ID in the respective destinies would be different than the one in anchor, while for IDs with only letters, the ID would be the same. Fix: It was suggested that to fix this bug, it should more or less like GitHub does it. While in gitea the anchors would be put in HTML like this: ``` <p dir="auto"><a href="#user-content-_toc152597800" rel="nofollow">Review</a></p> <p dir="auto"><a href="#user-content-_toc152597802" rel="nofollow">Staging</a></p> <p dir="auto"><a href="#user-content-_toc152597803" rel="nofollow">Development</a></p> <p dir="auto"><a href="#user-content-_toc152597828" rel="nofollow">Testing</a></p> <p dir="auto"><a href="#user-content-_toc152597829" rel="nofollow">Unit-tests</a></p> ``` In GitHub, the same anchor's href properties would be the same without "user-content-" trailing behind. So my code made sure to change those anchors, so it would not include "user-content-" and then add respective Event Listeners so it would scroll into the supposed places. Fixes: #29196 --------- Co-authored-by: silverwind <me@silverwind.io> (cherry picked from commit f219ea8d0e0eccd74c786202a4ddb2784a0175ad)
51 lines
2 KiB
JavaScript
51 lines
2 KiB
JavaScript
import {svg} from '../svg.js';
|
|
|
|
const headingSelector = '.markup h1, .markup h2, .markup h3, .markup h4, .markup h5, .markup h6';
|
|
|
|
// scroll to anchor while respecting the `user-content` prefix that exists on the target
|
|
function scrollToAnchor(hash, initial) {
|
|
// abort if the browser has already scrolled to another anchor during page load
|
|
if (initial && document.querySelector(':target')) return;
|
|
if (hash?.length <= 1) return;
|
|
const id = decodeURIComponent(hash.substring(1));
|
|
const el = document.getElementById(`user-content-${id}`);
|
|
if (el) {
|
|
el.scrollIntoView();
|
|
} else if (id.startsWith('user-content-')) { // compat for links with old 'user-content-' prefixed hashes
|
|
const el = document.getElementById(id);
|
|
if (el) el.scrollIntoView();
|
|
}
|
|
}
|
|
|
|
export function initMarkupAnchors() {
|
|
if (!document.querySelector('.markup')) return;
|
|
|
|
// create link icons for markup headings, the resulting link href will remove `user-content-`
|
|
for (const heading of document.querySelectorAll(headingSelector)) {
|
|
const originalId = heading.id.replace(/^user-content-/, '');
|
|
const a = document.createElement('a');
|
|
a.classList.add('anchor');
|
|
a.setAttribute('href', `#${encodeURIComponent(originalId)}`);
|
|
a.innerHTML = svg('octicon-link');
|
|
a.addEventListener('click', (e) => {
|
|
scrollToAnchor(e.currentTarget.getAttribute('href'), false);
|
|
});
|
|
heading.prepend(a);
|
|
}
|
|
|
|
// handle user-defined `name` anchors like `[Link](#link)` linking to `<a name="link"></a>Link`
|
|
for (const a of document.querySelectorAll('.markup a[href^="#"]')) {
|
|
const href = a.getAttribute('href');
|
|
if (!href.startsWith('#user-content-')) continue;
|
|
const originalId = href.replace(/^#user-content-/, '');
|
|
a.setAttribute('href', `#${encodeURIComponent(originalId)}`);
|
|
if (document.getElementsByName(originalId).length !== 1) {
|
|
a.addEventListener('click', (e) => {
|
|
scrollToAnchor(e.currentTarget.getAttribute('href'), false);
|
|
});
|
|
}
|
|
}
|
|
|
|
scrollToAnchor(window.location.hash, true);
|
|
}
|