160 lines
6.1 KiB
JavaScript
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 });
|
|
}
|
|
}
|