scrollSpy.js 2.5 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162
  1. // Inspired by ScrollSpy as in e.g. Bootstrap
  2. (function() {
  3. const OFFSET = 10;
  4. let timer;
  5. let headingsCache;
  6. let navPageContainer;
  7. const findHeadings = () => headingsCache ? headingsCache :
  8. document.querySelectorAll('.toc-headings > li > a');
  9. const onScroll = () => {
  10. if (timer) { // throttle
  11. return;
  12. }
  13. timer = setTimeout(() => {
  14. timer = null;
  15. let found = false;
  16. const headings = findHeadings();
  17. let headingElement;
  18. for (let i = 0; i < headings.length; i++) {
  19. // if !found and i is the last element, highlight the last
  20. let current = !found;
  21. if (!found && i < headings.length - 1) {
  22. const next = headings[i + 1].href.split('#')[1];
  23. const nextHeader = document.getElementById(next);
  24. const top = nextHeader.getBoundingClientRect().top;
  25. // The following tests whether top + scrollTop
  26. // (the top of the header) is greater than scrollTop
  27. // (where scrollTop = window.pageYOffset, the top of
  28. // the window), with OFFSET pixels of slop.
  29. current = top > OFFSET;
  30. }
  31. if (current) {
  32. found = true;
  33. headings[i].className = "active";
  34. headingElement = headings[i];
  35. } else {
  36. headings[i].className = "";
  37. }
  38. }
  39. if (headingElement) {
  40. if (headingElement.offsetTop < navPageContainer.scrollTop) {
  41. navPageContainer.scrollTop = headingElement.offsetTop;
  42. } else {
  43. const offsetBottom = headingElement.offsetTop + headingElement.offsetHeight;
  44. const scrollBottom = navPageContainer.scrollTop + navPageContainer.offsetHeight;
  45. if (offsetBottom > scrollBottom) {
  46. navPageContainer.scrollTop = offsetBottom - navPageContainer.offsetHeight;
  47. }
  48. }
  49. }
  50. }, 100);
  51. };
  52. document.addEventListener('scroll', onScroll);
  53. document.addEventListener('resize', onScroll);
  54. document.addEventListener('DOMContentLoaded', () => {
  55. // Cache the headings once the page has fully loaded.
  56. navPageContainer = document.getElementsByClassName('onPageNav')[0];
  57. headingsCache = findHeadings();
  58. onScroll();
  59. });
  60. })();