UNPKG

purecss-ui-menu

Version:

Responsive menu system with submenus and dropdowns built on purecss-ui.

154 lines (141 loc) 7.73 kB
(function(root, factory) { if (typeof define === 'function' && define.amd) { // AMD. Register as an anonymous module. define(factory(root)); } else if (typeof exports === 'object' && typeof exports.nodeName !== 'string') { // CommonJS module.exports = factory(root); } else { // Browser globals root.pu = root.pu || {}; root.pu.menu = factory(root); } }(typeof window !== "undefined" ? window : this, function(root) { let addEventListener = window.addEventListener; if (!addEventListener) console.error('purecss-ui-dialog requires a window with events'); let document = root.document; if (!document) console.error('purecss-ui-dialog requires a window with a document'); // verify that Element.matches is defined let Element = root.Element; if (!Element.prototype.matches) Element.prototype.matches = Element.prototype.msMatchesSelector || Element.prototype.webkitMatchesSelector; function init() { window.addEventListener('click', menuHandler); window.addEventListener('resize', resetMenu); } function resetMenu(e) { let openDropdownNodes = Array.apply(null, document.querySelectorAll('.pure-menu .open, .pure-menu.collapse-open')); openDropdownNodes.forEach(n => { n.classList.remove('open', 'open-right', 'open-left', 'collapse-open'); }); let subMenuNodes = Array.apply(null, document.querySelectorAll('.sub-menu-content')); subMenuNodes.forEach(n => { n.style.marginLeft = ""; }); } function menuHandler(e) { let target = e.target; if (target.classList.contains('menu-toggle-button')) { let parentMenu = getMenuParent(target); if (parentMenu) { if (parentMenu.classList.contains('collapse-open')) parentMenu.classList.remove('collapse-open'); else parentMenu.classList.add('collapse-open'); // hack to postion css grid elements in IE11 if (!!navigator.userAgent.match(/Trident.*rv[ :]*11\./)) { let gridNodes = Array.apply(null, parentMenu.querySelectorAll('.pure-g, .menu-collapse')); gridNodes.forEach(gridNode => { let gridItemNodes = Array.apply(null, gridNode.childNodes); gridItemNodes.forEach((gridItemNode, i) => { if (gridItemNode.style) gridItemNode.style.msGridRow = (i + 1).toString(); }); }); } } } else { let targetParent = e.target.parentNode; let targetSubMenuAncestors = getSubMenuParents(target); let openDropdownNodes = Array.apply(null, document.querySelectorAll('.pure-menu-item.sub-menu.open')); if (targetSubMenuAncestors.length == 0) { // click on non dropdown element so close all openDropdownNodes.forEach(n => { n.classList.remove('open', 'open-right', 'open-left'); }); } else if (targetSubMenuAncestors.length == 1) { // click on top level dropdown so open if closed if (targetParent === targetSubMenuAncestors[0]) { targetParent.classList.add('open'); // detect right bound let subMenuContent = targetParent.getElementsByClassName('sub-menu-content')[0]; if (subMenuContent) { let rightBound = getRightBound(subMenuContent.dataset.rightBound); let targetParentDims = targetParent.getBoundingClientRect(); let subMenuContentDims = subMenuContent.getBoundingClientRect(); let contentRight = subMenuContentDims.right; if (contentRight > rightBound) { let shiftLeft = Math.ceil(contentRight - rightBound); subMenuContent.style.marginLeft = '-' + shiftLeft + 'px'; } if (subMenuContentDims.width < targetParentDims.width) { subMenuContent.style.width = Math.ceil(targetParentDims.width).toString() + 'px'; } } } // else close all dropdowns openDropdownNodes.forEach(n => { n.classList.remove('open', 'open-right', 'open-left'); }); } else { if (targetParent === targetSubMenuAncestors[0]) { // click on child level dropdown so toggle if (targetParent.classList.contains('open')) { targetParent.classList.remove('open', 'open-right', 'open-left'); } else { targetParent.classList.add('open'); // detect edge and place left or right of parent let subMenuContent = targetParent.getElementsByClassName('sub-menu-content')[0]; if (subMenuContent) { let rightBound = getRightBound(subMenuContent.dataset.rightBound); let targetParentDims = targetParent.getBoundingClientRect(); let subMenuContentDims = subMenuContent.getBoundingClientRect(); if ((targetParentDims.right + subMenuContentDims.width) > rightBound) { targetParent.classList.add('open-left'); } else { targetParent.classList.add('open-right'); } } } // close any dropdowns not in the ancestors of this dropdown openDropdownNodes.forEach(n => { if (targetSubMenuAncestors.indexOf(n) == -1) n.classList.remove('open', 'open-right', 'open-left'); }); } else { // click is on link so close all openDropdownNodes.forEach(n => { n.classList.remove('open', 'open-right', 'open-left'); }); } } if (target.classList.contains('sub-menu') || targetParent.classList.contains('sub-menu')) { e.stopPropagation(); e.preventDefault(); } } function getMenuParent(node) { let parent = null; for (; node && node !== document; node = node.parentNode) { if (node.matches('.pure-menu.pure-menu-horizontal')) parent = node; } return parent; } function getSubMenuParents(node) { let nodes = []; for (; node && node !== document; node = node.parentNode) { if (node.matches('.pure-menu-item.sub-menu')) nodes.push(node); } return nodes; } function getRightBound(rightBoundId) { let bodyDims = document.body.getBoundingClientRect(); let rightBound = bodyDims.right; if (rightBoundId) { let specifiedRightBound = document.getElementById(rightBoundId); if (specifiedRightBound) { let specifiedRightBoundDims = specifiedRightBound.getBoundingClientRect(); rightBound = specifiedRightBoundDims.right; } } return rightBound; } } let menu = { init: init }; return menu; }));