Unverified Commit be6d68aa authored by Ken Hawkins's avatar Ken Hawkins Committed by GitHub
Browse files

Enhancement: make vf-navigation--on-this-page more dynamic, responsive (#1771)

* Make vf-navigation--on-this-page more dynamic

- allows for multiple on this page navigators
- activates the indicator only when the content is in focus
- is a breaking change! (requires a `data-vf-js-navigation-on-this-page-link` on the navigation links)

I think this is the *better* approach, but it's also disruptive as it has a breaking change.

* Update README.md

* Update vf-navigation.njk

* Update CHANGELOG.md

* Make onscreen math more reliable
parent 90607804
### 4.0.0-rc.1
* Make vf-navigation--on-this-page more dynamic and reactive with `data-vf-js-navigation-on-this-page-link`.
### 3.0.0-rc.2
* Fixed bug where the `vf-navigation` component was getting overlapped by other components.
......
......@@ -27,6 +27,7 @@ The `vfNavigationOnThisPage` JavaScript adds a quality-of-life improvement by au
- There should be only one use of `vf-navigation--on-this-page` on a page.
- Anchor targets need an element id: `id="container-1"`. This can be added to any item on the page, but would most logically be added to a `vf-grid`, `embl-grid` or `vf-section-header` element.
- Ensure `data-vf-js-navigation-on-this-page-container="true"` is present on `.vf-navigation__list`.
- Ensure each anchor link has a `data-vf-js-navigation-on-this-page-link`.
## Install
......
......@@ -6,42 +6,72 @@
* That must be executed exactly once
* @example vfNavigationOnThisPage()
*/
export function vfNavigationOnThisPage() {
var sectionList = document.querySelectorAll("[data-vf-js-navigation-on-this-page-container='true'],[data-vf-js-navigation-on-this-page-container='1']")[0];
var section = document.querySelectorAll("[id]");
var scope = document;
var sectionList = scope.querySelectorAll(
"[data-vf-js-navigation-on-this-page-link]"
);
// console.log(sectionList);
var section = scope.querySelectorAll("[id]");
var sectionPositions = {};
var sectionHeights = {};
var i = 0;
if (!sectionList || !section) {
// exit: either sections or section content not found
return;
}
if (sectionList.length == 0 || section.length == 0) {
if (sectionList.length === 0 || section.length === 0) {
// exit: either sections or section content not found
return;
}
section.forEach(e => {
sectionPositions[e.id] = e.offsetTop;
});
function activateNavigationItem() {
var scrollPosition = document.documentElement.scrollTop || document.body.scrollTop;
// althought costly, we recalculate the position of elements each time as things move or load dynamically
section.forEach((e) => {
var rect = e.getBoundingClientRect();
var scrollTop = window.pageYOffset || document.documentElement.scrollTop;
sectionPositions[e.id] = rect.top + scrollTop;
sectionHeights[e.id] = e.offsetHeight;
});
var scrollPosition =
document.documentElement.scrollTop || document.body.scrollTop;
for (i in sectionPositions) {
// this implements a scrollspy concept based on https://codepen.io/zchee/pen/ogzvZZ
if (sectionPositions[i] <= scrollPosition + 70) {
if (sectionPositions[i] <= scrollPosition + 0) {
// we activate the section 70 pixels before coming into view, as the sticky bar will cover it
// only add remove the class if there is a new section to activate
if (sectionList.querySelector("a[href*='" + i + "']") != null) {
sectionList.querySelector("[aria-selected]").removeAttribute("aria-selected");
sectionList.querySelector("a[href*='" + i + "']").setAttribute("aria-selected", "true");
}
sectionList.forEach(function (currentValue, currentIndex, listObj) {
// console.log(currentValue.href);
if (currentValue.href.includes(i)) {
currentValue.setAttribute("aria-selected", "true");
}
}, "myThisArg");
}
var isNotYetOnScreen = sectionPositions[i] > scrollPosition;
var bottomOfElement = sectionPositions[i] + sectionHeights[i];
if (scrollPosition - 70 > bottomOfElement || isNotYetOnScreen) {
// we activate the container only while it is in view
sectionList.forEach(function (currentValue, currentIndex, listObj) {
if (currentValue.href.includes(i)) {
currentValue.setAttribute("aria-selected", "false");
}
}, "myThisArg");
}
}
isCalculating = false;
}
window.onscroll = function() {
// we could introduce throttling, but as this is a fairly simple repaint, throttling is not likely required
window.requestAnimationFrame(activateNavigationItem);
var isCalculating = false;
window.onscroll = function () {
if (!isCalculating) {
isCalculating = true;
window.requestAnimationFrame(activateNavigationItem);
} else {
// console.log("throttled!");
}
};
}
......@@ -23,6 +23,8 @@
<a
href="{{ item.navigation_href }}"
class="vf-navigation__link"
{%- if classModifier == 'on-this-page' %} data-vf-js-navigation-on-this-page-link{%- endif -%}
data-vf-js-navigation-on-this-page-link
{%- if item.currentPage %} aria-current="page"{%- endif -%}
{%- if item.currentSection %} aria-selected="true"{%- endif -%}
>
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment