UNPKG

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
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; } } }); } }