blob: 6e741c71a9a5dbf5537453955ea5dbb268e822e5 [file] [log] [blame]
export default class ScrollSpy {
constructor(args) {
this.doc = document;
this.nav = this.doc.querySelectorAll(args.navSelector);
if(!this.nav.length === 0) { return }
this.win = window;
this.winHeight = this.win.innerHeight;
this.scrollElement = this.doc.querySelector(args.scrollSelector);
this.className = args.className;
this.offsetTop = args.offsetTop || 0;
this.contents = [];
this.contents = this.getContents(args.contentSelector);
this.attachEvent();
}
attachEvent() {
let scrollTimer;
this.scrollElement.addEventListener('scroll', () => {
if (scrollTimer) {
clearTimeout(scrollTimer);
}
scrollTimer = setTimeout(() => {
this.spy();
}, 1);
});
let resizeTimer;
this.scrollElement.addEventListener('resize', () => {
if (resizeTimer) {
clearTimeout(resizeTimer);
}
resizeTimer = setTimeout(() => {
this.spy();
}, 1);
});
this.scrollElement.addEventListener("click", (e) => {
const target = e.target;
if (target.tagName !== "A") return;
window.onclickToc = true;
for (let i = 0, max = this.nav.length; i < max; i++) {
const navElement = this.nav[i];
if (navElement.href === target.href) {
navElement.classList.add(this.className);
navElement.classList.add('mdl-color-text--primary');
} else {
navElement.classList.remove(this.className);
navElement.classList.remove('mdl-color-text--primary');
}
}
});
}
getContents(contentSelector) {
const targets = [];
for (let i = 0, max = this.nav.length; i < max; i++) {
const href = this.nav[i].href;
targets.push(this.doc.getElementById(href.split('#')[1]));
}
return targets;
}
spy() {
let elements = this.getViewState();
this.toggleNavClass(elements);
}
getViewState() {
const elementListInView = [];
for (let i = 0, max = this.contents.length; i < max; i++) {
const current = this.contents[i];
if (current && this.isView(current)) {
elementListInView.push(current);
}
}
return elementListInView;
}
isView(element) {
const scrollTop = this.scrollElement.scrollTop;
const subHeaderRect = document.querySelector(".mdl-layout__header-row").getBoundingClientRect();
const headerHeight = subHeaderRect.top + subHeaderRect.height;
const scrollBottom = scrollTop + window.innerHeight - headerHeight;
const rect = element.getBoundingClientRect();
const elementTop = rect.top + scrollTop;
const elementBottom = elementTop + element.offsetHeight;
return elementTop < scrollBottom - 30 && elementBottom > scrollTop + headerHeight + 30;
}
toggleNavClass(elements) {
if (window.onclickToc) {
window.onclickToc = false;
return;
}
let maxDepth = 0;
let maxDepthElement = $();
for (let i = 0, max = elements.length; i < max; i++) {
const el = elements[i];
const tempDepth = this.getTagDepth(el);
if (maxDepth < tempDepth) {
maxDepth = tempDepth;
maxDepthElement = el;
}
}
for (let i = 0, max = this.nav.length; i < max; i++) {
const navElement = this.nav[i];
if (navElement.href.split('#')[1] === maxDepthElement.id) {
navElement.classList.add(this.className);
navElement.classList.add('mdl-color-text--primary');
} else {
navElement.classList.remove(this.className);
navElement.classList.remove('mdl-color-text--primary');
}
}
}
getTagDepth(element) {
return parseInt($(element).find('h1,h2,h3,h4,h5,h6').get(0).tagName.split('H')[1]);
}
}