@randstad-design/orbit-multitheme
Version:
multitheme Front-end code based on Randstad Human Forward components
175 lines (148 loc) • 4.97 kB
JavaScript
import ElementHelpers from '../helpers/element-helpers';
import scrollToElement from '../helpers/scrollToElement';
/**
* scroll.js
* scroll script that adds a gradient and handles anchors
*/
/**
* Declare constants
*/
const attributeBase = 'data-rs-scroll';
export class Scroll {
constructor(element) {
this.element = element;
this.list = ElementHelpers.getElementsByAttribute(this.attributes.list);
this.link = ElementHelpers.getElementsByAttribute(this.attributes.link);
this.addEventHandlers();
}
/**
* Declare attribute constants
*/
get attributes() {
return {
list: attributeBase + '-list',
link: attributeBase + '-link'
};
}
/**
* Add event handlers
*/
addEventHandlers() {
this.addGradientToScrollingList();
this.addAndRemoveGradientOnScroll();
this.handleScrollOnClick();
this.addAndRemoveDividerOnScroll();
this.addDividerToScrollingList();
}
/**
* Adds a gradient when it is possible to scroll, by comparing offset height with scroll height
*/
addGradientToScrollingList() {
this.element.addEventListener('click', function () {
const list = this.nextElementSibling;
const offsetHeight = list.offsetHeight;
const scrollHeight = list.scrollHeight;
const scrollTop = list.scrollTop;
const isScrollable = scrollHeight > offsetHeight;
const isScrolledToBottom = scrollHeight - offsetHeight - scrollTop < 1;
if (isScrollable && !isScrolledToBottom) {
if (list.classList.contains('scroll-gradient')) {
list.classList.remove('scroll-gradient');
} else {
list.classList.add('scroll-gradient');
}
} else {
list.classList.remove('scroll-gradient');
}
});
}
/**
* removes gradient when scrolled all the way to the bottom
* adds gradient when scrolled to the top
*/
addAndRemoveGradientOnScroll() {
this.list.forEach((item) => {
item.addEventListener('scroll', () => {
const list = item;
const scrollTop = list.scrollTop;
const scrollHeight = list.scrollHeight;
const offsetHeight = list.offsetHeight;
const isScrollable = scrollHeight > offsetHeight;
const isScrolledToBottom = scrollHeight - offsetHeight - scrollTop < 1;
if (isScrolledToBottom && isScrollable) {
list.classList.remove('scroll-gradient');
} else {
list.classList.add('scroll-gradient');
}
});
});
}
/**
* adds divider when scrolled more than 1px from top
* removes the divider when scrolled to top
*/
addAndRemoveDividerOnScroll() {
this.list.forEach((item) => {
const element = item.previousElementSibling;
item.addEventListener('scroll', () => {
const list = item;
const scrollTop = list.scrollTop;
const scrollHeight = list.scrollHeight;
const offsetHeight = list.offsetHeight;
const isScrollable = scrollHeight > offsetHeight;
if (isScrollable && scrollTop > 1) {
element.classList.add('scroll-divider');
} else {
element.classList.remove('scroll-divider');
}
});
});
}
/**
* Removes the divider when closing the element
*/
addDividerToScrollingList() {
this.element.addEventListener('click', function () {
if (this.classList.contains('scroll-divider')) {
this.classList.remove('scroll-divider');
}
});
}
/**
* scrolls the screen to the id of the content defined in the href
* uses scrolltoelement helper
* sets and removes 'is-active state'
*/
handleScrollOnClick() {
this.link.forEach((item) => {
const _this = this;
item.addEventListener('click', function () {
const link = this.querySelector('a');
const href = link.getAttribute('href').substring(1);
const elem = document.getElementById(href);
const navHeight = _this.element.offsetHeight;
let scrollExtraOffset = ElementHelpers.isDesktop() ? null : -navHeight;
const stickyClass = _this.element.parentElement.dataset.rsSticky;
const parentContainsStickyClass =
_this.element.parentElement.classList.contains(stickyClass);
const parentHeight = _this.element.parentElement.offsetHeight;
// If the parentcontainer is not sticky it needs to add an extra space to the scroll, because while scrolling down
// the navigation becomes absolute and the height will be taken out of the DOM
if (!parentContainsStickyClass) {
scrollExtraOffset = -parentHeight;
}
scrollToElement(elem, 500, scrollExtraOffset);
_this.link.forEach((item) => {
item.classList.remove('is-active');
});
this.classList.add('is-active');
});
});
}
/**
* Get selector
*/
static getSelector() {
return `[${attributeBase}]`;
}
}