mmenu-js
Version:
The best javascript plugin for app look-alike on- and off-canvas menus with sliding submenus for your website and webapp.
137 lines (114 loc) • 4.26 kB
text/typescript
import Mmenu from '../../core/oncanvas/mmenu.oncanvas';
import options from './_options';
import configs from './_configs';
import { extendShorthandOptions } from './_options';
import * as DOM from '../../_modules/dom';
import { extend } from '../../_modules/helpers';
// Add the options and configs.
Mmenu.options.pageScroll = options;
Mmenu.configs.pageScroll = configs;
export default function(this: Mmenu) {
var options = extendShorthandOptions(this.opts.pageScroll);
this.opts.pageScroll = extend(options, Mmenu.options.pageScroll);
var configs = this.conf.pageScroll;
/** The currently "active" section */
var section: HTMLElement;
function scrollTo() {
if (section) {
// section.scrollIntoView({ behavior: 'smooth' });
window.scrollTo({
top:
section.getBoundingClientRect().top +
document.scrollingElement.scrollTop -
configs.scrollOffset,
behavior: 'smooth'
});
}
section = null;
}
function anchorInPage(href: string) {
try {
if (href != '#' && href.slice(0, 1) == '#') {
return Mmenu.node.page.querySelector(href) as HTMLElement;
}
return null;
} catch (err) {
return null;
}
}
// Scroll to section after clicking menu item.
if (options.scroll) {
this.bind('close:finish', () => {
scrollTo();
});
}
// Add click behavior.
// Prevents default behavior when clicking an anchor.
if (this.opts.offCanvas && options.scroll) {
this.clck.push((anchor: HTMLElement, args: mmClickArguments) => {
section = null;
// Don't continue if the clicked anchor is not in the menu.
if (!args.inMenu) {
return;
}
// Don't continue if the targeted section is not on the page.
var href = anchor.getAttribute('href');
section = anchorInPage(href);
if (!section) {
return;
}
// If the sidebar add-on is "expanded"...
if (
this.node.menu.matches('.mm-menu_sidebar-expanded') &&
this.node.wrpr.matches('.mm-wrapper_sidebar-expanded')
) {
// ... scroll the page to the section.
scrollTo();
// ... otherwise...
} else {
// ... close the menu.
return {
close: true
};
}
});
}
// Update selected menu item after scrolling.
if (options.update) {
let scts: HTMLElement[] = [];
this.bind('initListview:after', (listview: HTMLElement) => {
let listitems = DOM.children(listview, '.mm-listitem');
DOM.filterLIA(listitems).forEach(anchor => {
var href = anchor.getAttribute('href');
var section = anchorInPage(href);
if (section) {
scts.unshift(section);
}
});
});
let _selected = -1;
window.addEventListener('scroll', evnt => {
var scrollTop = window.scrollY;
for (var s = 0; s < scts.length; s++) {
if (scts[s].offsetTop < scrollTop + configs.updateOffset) {
if (_selected !== s) {
_selected = s;
let panel = DOM.children(
this.node.pnls,
'.mm-panel_opened'
)[0];
let listitems = DOM.find(panel, '.mm-listitem');
let anchors = DOM.filterLIA(listitems);
anchors = anchors.filter(anchor =>
anchor.matches('[href="#' + scts[s].id + '"]')
);
if (anchors.length) {
this.setSelected(anchors[0].parentElement);
}
}
break;
}
}
});
}
}