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, originalId } from '../../_modules/helpers'; // Add the options and configs. Mmenu.options.dropdown = options; Mmenu.configs.dropdown = configs; export default function () { var _this = this; if (!this.opts.offCanvas) { return; } var options = extendShorthandOptions(this.opts.dropdown); this.opts.dropdown = extend(options, Mmenu.options.dropdown); var configs = this.conf.dropdown; if (!options.drop) { return; } var button; this.bind('initMenu:after', function () { _this.node.menu.classList.add('mm-menu_dropdown'); if (typeof options.position.of != 'string') { var id = originalId(_this.node.menu.id); if (id) { options.position.of = '[href="#' + id + '"]'; } } if (typeof options.position.of != 'string') { return; } // Get the button to put the menu next to button = DOM.find(document.body, options.position.of)[0]; // Emulate hover effect var events = options.event.split(' '); if (events.length == 1) { events[1] = events[0]; } if (events[0] == 'hover') { button.addEventListener('mouseenter', function () { _this.open(); }, { passive: true }); } if (events[1] == 'hover') { _this.node.menu.addEventListener('mouseleave', function () { _this.close(); }, { passive: true }); } }); // Add/remove classname and style when opening/closing the menu this.bind('open:start', function () { _this.node.menu['mmStyle'] = _this.node.menu.getAttribute('style'); _this.node.wrpr.classList.add('mm-wrapper_dropdown'); }); this.bind('close:finish', function () { _this.node.menu.setAttribute('style', _this.node.menu['mmStyle']); _this.node.wrpr.classList.remove('mm-wrapper_dropdown'); }); /** * Find the position (x, y) and sizes (width, height) for the menu. * * @param {string} dir The direction to measure ("x" for horizontal, "y" for vertical) * @param {object} obj The object where (previously) measured values are stored. * @return {object} The object where measered values are stored. */ var getPosition = function (dir, obj) { var css = obj[0], cls = obj[1]; var _outerSize = dir == 'x' ? 'offsetWidth' : 'offsetHeight', _startPos = dir == 'x' ? 'left' : 'top', _stopPos = dir == 'x' ? 'right' : 'bottom', _size = dir == 'x' ? 'width' : 'height', _winSize = dir == 'x' ? 'innerWidth' : 'innerHeight', _maxSize = dir == 'x' ? 'maxWidth' : 'maxHeight', _position = null; var startPos = DOM.offset(button, _startPos), stopPos = startPos + button[_outerSize], windowSize = window[_winSize]; /** Offset for the menu relative to the button. */ var offs = configs.offset.button[dir] + configs.offset.viewport[dir]; // Position set in option if (options.position[dir]) { switch (options.position[dir]) { case 'left': case 'bottom': _position = 'after'; break; case 'right': case 'top': _position = 'before'; break; } } // Position not set in option, find most space if (_position === null) { _position = startPos + (stopPos - startPos) / 2 < windowSize / 2 ? 'after' : 'before'; } // Set position and max var val, max; if (_position == 'after') { val = dir == 'x' ? startPos : stopPos; max = windowSize - (val + offs); css[_startPos] = val + configs.offset.button[dir] + 'px'; css[_stopPos] = 'auto'; if (options.tip) { cls.push('mm-menu_tip-' + (dir == 'x' ? 'left' : 'top')); } } else { val = dir == 'x' ? stopPos : startPos; max = val - offs; css[_stopPos] = 'calc( 100% - ' + (val - configs.offset.button[dir]) + 'px )'; css[_startPos] = 'auto'; if (options.tip) { cls.push('mm-menu_tip-' + (dir == 'x' ? 'right' : 'bottom')); } } if (options.fitViewport) { css[_maxSize] = Math.min(configs[_size].max, max) + 'px'; } return [css, cls]; }; function position() { var _this = this; if (!this.vars.opened) { return; } this.node.menu.setAttribute('style', this.node.menu['mmStyle']); var obj = [{}, []]; obj = getPosition.call(this, 'y', obj); obj = getPosition.call(this, 'x', obj); for (var s in obj[0]) { this.node.menu.style[s] = obj[0][s]; } if (options.tip) { var classnames = [ 'mm-menu_tip-left', 'mm-menu_tip-right', 'mm-menu_tip-top', 'mm-menu_tip-bottom' ]; // IE11: classnames.forEach(function (classname) { _this.node.menu.classList.remove(classname); }); obj[1].forEach(function (classname) { _this.node.menu.classList.add(classname); }); // Better browsers: // this.node.menu.classList.remove(...classnames); // this.node.menu.classList.add(...obj[1]); } } this.bind('open:start', position); window.addEventListener('resize', function (evnt) { position.call(_this); }, { passive: true }); if (!this.opts.offCanvas.blockUI) { window.addEventListener('scroll', function (evnt) { position.call(_this); }, { passive: true }); } }