@ulu/frontend
Version:
A versatile SCSS and JavaScript component library offering configurable, accessible components and flexible integration into any project, with SCSS modules suitable for modern JS frameworks.
107 lines (95 loc) • 3.09 kB
Markdown
Example of anchor menu setup
```js
/**
* @todo This needs to be converted for reuse!
*/
// Creates anchor menu and attaches waypoints
import ElementWaypoint from "../waypoints/element-waypoint.js";
import Tooltip from "../ui/tooltip.js";
window.addEventListener("load", init);
function init() {
const anchors = [];
let idCount = 0;
const activeClass = 'header__page-link--active';
const ignoreSelector = '[data-page-link-search-ignore]';
const searchSelector = `h1:not(${ ignoreSelector }), h2:not(${ ignoreSelector })`;
const container = document.querySelector('.header__page-links');
const context = document.querySelector('[data-page-link-search]');
if (!container || !context) return;
const headlineNodes = [ ...context.querySelectorAll(searchSelector) ];
// Filter out parents too
const headlines = headlineNodes.filter(n => n.closest(ignoreSelector) === null);
headlines.forEach(element => {
const id = getId(element);
const anchor = document.createElement('a');
const span = document.createElement('span');
anchor.classList.add('header__page-link');
anchor.href = "#" + id;
span.classList.add('hidden-visually');
span.textContent = element.textContent;
anchor.appendChild(span);
container.append(anchor);
anchors.push(anchor);
anchor.addEventListener("focusin", onHover);
anchor.addEventListener("mouseenter", onHover);
anchor.addEventListener("focusout", onHoverOut);
anchor.addEventListener("mouseleave", onHoverOut);
// Attach watcher
(new ElementWaypoint({
offsetTop: '20%',
handler: waypointHandler,
element
}));
});
function waypointHandler(entering, direction) {
const { element } = this.options;
const anchor = anchors[ headlines.indexOf(element) ];
const index = anchors.indexOf(anchor);
if (entering) {
removeActiveAll();
activateAnchor(anchor);
// Above the first
} else if (index === 0 && direction === "up") {
removeActiveAll();
// Since we are using headlines instaed of containers we need to
// activate when user is scrolling up. By finding the index of the anchor
// above the recently deactivated headline target
} else if (direction === "up") {
removeActiveAll();
activateAnchor(anchors[index - 1]);
}
}
function removeActiveAll() {
anchors.forEach(anchor => anchor.classList.remove(activeClass));
}
function activateAnchor(anchor) {
anchor.classList.add(activeClass);
}
function getId(element) {
if (!element.id) element.id = `page-link--${ ++idCount }`;
return element.id;
}
}
// Tooltip Related
// =============================================================================
let tooltip;
function onHover(event) {
const { target } = event;
destroy();
tooltip = new Tooltip(target, target.textContent, {
classes: [
"site-tooltip",
"page-link-tooltip"
]
});
}
function onHoverOut() {
destroy();
}
function destroy() {
if (tooltip) {
tooltip.destroy();
tooltip = null;
}
}
```