fix docs table of contents scrolling
This commit is contained in:
parent
94972a0c58
commit
43c06b65c6
1 changed files with 48 additions and 0 deletions
|
|
@ -107,6 +107,43 @@
|
||||||
}).join('');
|
}).join('');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// marked no longer guarantees heading ids across versions, and the docs
|
||||||
|
// reader is an internal scroll container. Add stable GitHub-style ids and
|
||||||
|
// handle same-page #toc links by scrolling the reader, not the window.
|
||||||
|
function slugHeading(text) {
|
||||||
|
return String(text || '')
|
||||||
|
.trim()
|
||||||
|
.toLowerCase()
|
||||||
|
.replace(/\s/g, '-')
|
||||||
|
.replace(/[^a-z0-9_-]/g, '');
|
||||||
|
}
|
||||||
|
|
||||||
|
function prepareDocAnchors(body) {
|
||||||
|
if (!body) return;
|
||||||
|
var seen = {};
|
||||||
|
body.querySelectorAll('h1,h2,h3,h4,h5,h6').forEach(function (h) {
|
||||||
|
var base = h.id || slugHeading(h.textContent || '');
|
||||||
|
if (!base) return;
|
||||||
|
var id = base;
|
||||||
|
var n = seen[base] || 0;
|
||||||
|
if (n) id = base + '-' + n;
|
||||||
|
seen[base] = n + 1;
|
||||||
|
h.id = id;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function scrollReaderToHash(hash) {
|
||||||
|
var body = $('docs-reader-body');
|
||||||
|
var reader = $('docs-reader');
|
||||||
|
if (!body || !reader || !hash) return false;
|
||||||
|
var id = String(hash).replace(/^#/, '');
|
||||||
|
if (!id) return false;
|
||||||
|
var target = document.getElementById(id);
|
||||||
|
if (!target || !body.contains(target)) return false;
|
||||||
|
reader.scrollTop = target.offsetTop - body.offsetTop - 8;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
function loadTree() {
|
function loadTree() {
|
||||||
if (_treeLoaded) return;
|
if (_treeLoaded) return;
|
||||||
fetch('/api/admin/docs/tree', { headers: getAuthHeaders() })
|
fetch('/api/admin/docs/tree', { headers: getAuthHeaders() })
|
||||||
|
|
@ -152,6 +189,7 @@
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
body.innerHTML = data.html || '';
|
body.innerHTML = data.html || '';
|
||||||
|
prepareDocAnchors(body);
|
||||||
if (meta) {
|
if (meta) {
|
||||||
meta.textContent = relPath + ' • ' + (data.bytes != null ? (data.bytes + ' bytes') : '');
|
meta.textContent = relPath + ' • ' + (data.bytes != null ? (data.bytes + ' bytes') : '');
|
||||||
}
|
}
|
||||||
|
|
@ -160,6 +198,7 @@
|
||||||
// Scroll content area to top so deep-link readers don't land mid-doc
|
// Scroll content area to top so deep-link readers don't land mid-doc
|
||||||
var reader = $('docs-reader');
|
var reader = $('docs-reader');
|
||||||
if (reader) reader.scrollTop = 0;
|
if (reader) reader.scrollTop = 0;
|
||||||
|
if (window.location.hash) setTimeout(function () { scrollReaderToHash(window.location.hash); }, 0);
|
||||||
})
|
})
|
||||||
.catch(function (err) {
|
.catch(function (err) {
|
||||||
body.innerHTML = '<p style="color:var(--red);">' + escHtml(err.message || String(err)) + '</p>';
|
body.innerHTML = '<p style="color:var(--red);">' + escHtml(err.message || String(err)) + '</p>';
|
||||||
|
|
@ -203,6 +242,15 @@
|
||||||
arrow.classList.toggle('fa-chevron-right', !willOpen);
|
arrow.classList.toggle('fa-chevron-right', !willOpen);
|
||||||
}
|
}
|
||||||
persistExpanded();
|
persistExpanded();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
var docLink = e.target.closest('#docs-reader-body a[href^="#"]');
|
||||||
|
if (docLink) {
|
||||||
|
var href = docLink.getAttribute('href');
|
||||||
|
if (href && scrollReaderToHash(href)) {
|
||||||
|
e.preventDefault();
|
||||||
|
try { history.replaceState(null, '', href); } catch (_) { window.location.hash = href; }
|
||||||
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue