From c36f3b7878d94723c9c2d5576a724acc36aef3dc Mon Sep 17 00:00:00 2001 From: George Cushen Date: Wed, 10 Feb 2021 08:25:28 +0000 Subject: [PATCH] feat: auto scroll active book menu and ToC links into view Also, fix ScrollSpy highlighting previous ToC link for some Book anchors. Close #1964 --- wowchemy/assets/js/wowchemy-utils.js | 30 +++++++++++++++++++++- wowchemy/assets/js/wowchemy.js | 38 +++++++++++++++++++++++----- 2 files changed, 60 insertions(+), 8 deletions(-) diff --git a/wowchemy/assets/js/wowchemy-utils.js b/wowchemy/assets/js/wowchemy-utils.js index c38d9f9d..ad28d727 100644 --- a/wowchemy/assets/js/wowchemy-utils.js +++ b/wowchemy/assets/js/wowchemy-utils.js @@ -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}; diff --git a/wowchemy/assets/js/wowchemy.js b/wowchemy/assets/js/wowchemy.js index c7621325..68c12eea 100644 --- a/wowchemy/assets/js/wowchemy.js +++ b/wowchemy/assets/js/wowchemy.js @@ -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.