feat: auto scroll active book menu and ToC links into view

Also, fix ScrollSpy highlighting previous ToC link for some Book anchors.

Close #1964
This commit is contained in:
George Cushen 2021-02-10 08:25:28 +00:00
commit c36f3b7878
2 changed files with 60 additions and 8 deletions

View file

@ -23,4 +23,32 @@ function fixMermaid() {
}
}
export {fixMermaid};
/**
* @param {Element} parent
* @param {Element} child
*/
function scrollParentToChild(parent, child) {
// Where is the parent on the page?
const parentRect = parent.getBoundingClientRect();
// What can the client see?
const parentViewableArea = {
height: parent.clientHeight,
width: parent.clientWidth,
};
// Where is the child?
const childRect = child.getBoundingClientRect();
// Is the child in view?
const isChildInView =
childRect.top >= parentRect.top && childRect.bottom <= parentRect.top + parentViewableArea.height;
// If the child isn't in view, attempt to scroll the parent to it.
if (!isChildInView) {
// Scroll by offset relative to parent.
parent.scrollTop = childRect.top + parent.scrollTop - parentRect.top;
}
}
export {fixMermaid, scrollParentToChild};

View file

@ -7,7 +7,7 @@
import {hugoEnvironment, codeHighlighting, searchEnabled} from '@params';
import {fixMermaid} from './wowchemy-utils';
import {fixMermaid, scrollParentToChild} from './wowchemy-utils';
import {
changeThemeModeClick,
@ -33,10 +33,11 @@ function getNavBarHeight() {
/**
* Responsive hash scrolling.
* Check for a URL hash as an anchor.
* If it exists on current page, scroll to it responsively.
* If page anchor matches hash, scroll to it responsively considering dynamic height elements.
* If `target` argument omitted (e.g. after event), assume it's the window's hash.
* Default to 0ms animation duration as don't want animation for fixing scrollspy Book page ToC highlighting.
*/
function scrollToAnchor(target, duration = 600) {
function scrollToAnchor(target, duration = 0) {
// If `target` is undefined or HashChangeEvent object, set it to window's hash.
// Decode the hash as browsers can encode non-ASCII characters (e.g. Chinese symbols).
target =
@ -434,6 +435,13 @@ $(document).ready(function () {
// Render theme variation, including any HLJS and Mermaid themes.
let {isDarkTheme, themeMode} = initThemeVariation();
renderThemeVariation(isDarkTheme, themeMode, true);
// Scroll Book page's active menu sidebar link into view.
let child = document.querySelector('.docs-links .active');
let parent = document.querySelector('.docs-links');
if (child && parent) {
scrollParentToChild(parent, child);
}
});
/* ---------------------------------------------------------------------------
@ -441,9 +449,28 @@ $(document).ready(function () {
* --------------------------------------------------------------------------- */
$(window).on('load', function () {
// Init Isotope Layout Engine for instances of the Portfolio widget.
// Re-initialize Scrollspy with dynamic navbar height offset.
fixScrollspy();
// Detect instances of the Portfolio widget.
let isotopeInstances = document.querySelectorAll('.projects-container');
let isotopeInstancesCount = isotopeInstances.length;
// Fix ScrollSpy highlighting previous Book page ToC link for some anchors.
// Check if isotopeInstancesCount>0 as that case performs its own scrollToAnchor.
if (window.location.hash && isotopeInstancesCount === 0) {
scrollToAnchor(decodeURIComponent(window.location.hash), 0);
}
// Scroll Book page's active ToC sidebar link into view.
// Action after calling scrollToAnchor to fix Scrollspy highlighting otherwise wrong link may have active class.
let child = document.querySelector('.docs-toc .nav-link.active');
let parent = document.querySelector('.docs-toc');
if (child && parent) {
scrollParentToChild(parent, child);
}
// Init Isotope Layout Engine for instances of the Portfolio widget.
let isotopeCounter = 0;
isotopeInstances.forEach(function (isotopeInstance, index) {
console.debug(`Loading Isotope instance ${index}`);
@ -610,9 +637,6 @@ $(window).on('load', function () {
// Init. author notes (tooltips).
$('[data-toggle="tooltip"]').tooltip();
// Re-initialize Scrollspy with dynamic navbar height offset.
fixScrollspy();
});
// Theme chooser events.