frdh-mmenu-js/dist/addons/dropdown/mmenu.dropdown.js
2022-11-18 21:38:41 +01:00

160 lines
6.1 KiB
JavaScript

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