smartmenus
Version:
Website/web app navbars with collapsible navs or dropdowns made easy yet highly configurable.
1,287 lines (1,254 loc) • 71.9 kB
JavaScript
/*!
* SmartMenus 2.0.0-alpha.1 - Dec 29, 2023
* https://www.smartmenus.org/
* Copyright (c) since 2001 Vasil Dinkov, Vadikom Web Ltd. https://vadikom.com
* Licensed MIT https://github.com/vadikom/smartmenus/blob/master/LICENSE-MIT
*/
(function (global, factory) {
typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory() :
typeof define === 'function' && define.amd ? define(factory) :
(global = typeof globalThis !== 'undefined' ? globalThis : global || self, global.SmartMenus = factory());
}(this, (function () { 'use strict';
function _typeof(obj) {
"@babel/helpers - typeof";
if (typeof Symbol === "function" && typeof Symbol.iterator === "symbol") {
_typeof = function (obj) {
return typeof obj;
};
} else {
_typeof = function (obj) {
return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj;
};
}
return _typeof(obj);
}
function _classCallCheck(instance, Constructor) {
if (!(instance instanceof Constructor)) {
throw new TypeError("Cannot call a class as a function");
}
}
function _defineProperties(target, props) {
for (var i = 0; i < props.length; i++) {
var descriptor = props[i];
descriptor.enumerable = descriptor.enumerable || false;
descriptor.configurable = true;
if ("value" in descriptor) descriptor.writable = true;
Object.defineProperty(target, descriptor.key, descriptor);
}
}
function _createClass(Constructor, protoProps, staticProps) {
if (protoProps) _defineProperties(Constructor.prototype, protoProps);
if (staticProps) _defineProperties(Constructor, staticProps);
return Constructor;
}
function _defineProperty(obj, key, value) {
if (key in obj) {
Object.defineProperty(obj, key, {
value: value,
enumerable: true,
configurable: true,
writable: true
});
} else {
obj[key] = value;
}
return obj;
}
function ownKeys(object, enumerableOnly) {
var keys = Object.keys(object);
if (Object.getOwnPropertySymbols) {
var symbols = Object.getOwnPropertySymbols(object);
if (enumerableOnly) symbols = symbols.filter(function (sym) {
return Object.getOwnPropertyDescriptor(object, sym).enumerable;
});
keys.push.apply(keys, symbols);
}
return keys;
}
function _objectSpread2(target) {
for (var i = 1; i < arguments.length; i++) {
var source = arguments[i] != null ? arguments[i] : {};
if (i % 2) {
ownKeys(Object(source), true).forEach(function (key) {
_defineProperty(target, key, source[key]);
});
} else if (Object.getOwnPropertyDescriptors) {
Object.defineProperties(target, Object.getOwnPropertyDescriptors(source));
} else {
ownKeys(Object(source)).forEach(function (key) {
Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key));
});
}
}
return target;
}
function _slicedToArray(arr, i) {
return _arrayWithHoles(arr) || _iterableToArrayLimit(arr, i) || _unsupportedIterableToArray(arr, i) || _nonIterableRest();
}
function _toConsumableArray(arr) {
return _arrayWithoutHoles(arr) || _iterableToArray(arr) || _unsupportedIterableToArray(arr) || _nonIterableSpread();
}
function _arrayWithoutHoles(arr) {
if (Array.isArray(arr)) return _arrayLikeToArray(arr);
}
function _arrayWithHoles(arr) {
if (Array.isArray(arr)) return arr;
}
function _iterableToArray(iter) {
if (typeof Symbol !== "undefined" && Symbol.iterator in Object(iter)) return Array.from(iter);
}
function _iterableToArrayLimit(arr, i) {
if (typeof Symbol === "undefined" || !(Symbol.iterator in Object(arr))) return;
var _arr = [];
var _n = true;
var _d = false;
var _e = undefined;
try {
for (var _i = arr[Symbol.iterator](), _s; !(_n = (_s = _i.next()).done); _n = true) {
_arr.push(_s.value);
if (i && _arr.length === i) break;
}
} catch (err) {
_d = true;
_e = err;
} finally {
try {
if (!_n && _i["return"] != null) _i["return"]();
} finally {
if (_d) throw _e;
}
}
return _arr;
}
function _unsupportedIterableToArray(o, minLen) {
if (!o) return;
if (typeof o === "string") return _arrayLikeToArray(o, minLen);
var n = Object.prototype.toString.call(o).slice(8, -1);
if (n === "Object" && o.constructor) n = o.constructor.name;
if (n === "Map" || n === "Set") return Array.from(o);
if (n === "Arguments" || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)) return _arrayLikeToArray(o, minLen);
}
function _arrayLikeToArray(arr, len) {
if (len == null || len > arr.length) len = arr.length;
for (var i = 0, arr2 = new Array(len); i < len; i++) arr2[i] = arr[i];
return arr2;
}
function _nonIterableSpread() {
throw new TypeError("Invalid attempt to spread non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.");
}
function _nonIterableRest() {
throw new TypeError("Invalid attempt to destructure non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.");
}
function _createForOfIteratorHelper(o, allowArrayLike) {
var it;
if (typeof Symbol === "undefined" || o[Symbol.iterator] == null) {
if (Array.isArray(o) || (it = _unsupportedIterableToArray(o)) || allowArrayLike && o && typeof o.length === "number") {
if (it) o = it;
var i = 0;
var F = function () {};
return {
s: F,
n: function () {
if (i >= o.length) return {
done: true
};
return {
done: false,
value: o[i++]
};
},
e: function (e) {
throw e;
},
f: F
};
}
throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.");
}
var normalCompletion = true,
didErr = false,
err;
return {
s: function () {
it = o[Symbol.iterator]();
},
n: function () {
var step = it.next();
normalCompletion = step.done;
return step;
},
e: function (e) {
didErr = true;
err = e;
},
f: function () {
try {
if (!normalCompletion && it.return != null) it.return();
} finally {
if (didErr) throw err;
}
}
};
}
/*
* SmartMenus
* http://www.smartmenus.org/
* Copyright (c) since 2001 Vasil Dinkov, Vadikom Web Ltd. http://vadikom.com
* Licensed MIT https://github.com/vadikom/smartmenus/blob/master/LICENSE-MIT
*/
var storage = new WeakMap();
var Data = {
set: function set(element, key, value) {
if (!storage.has(element)) {
storage.set(element, new Map());
}
storage.get(element).set(key, value);
},
get: function get(element, key) {
return storage.has(element) ? storage.get(element).get(key) || null : null;
},
delete: function _delete(element, key) {
if (storage.has(element)) {
return storage.get(element).delete(key);
}
return false;
}
};
var DATA_KEY = 'sm-events';
function normalizeArguments(events, selector, handler) {
if (!handler && typeof selector === 'function') {
handler = selector;
selector = '';
}
if (!events || typeof events === 'string') {
var _eventsObject = {};
_eventsObject[events || ''] = handler;
events = _eventsObject;
}
if (!selector) {
selector = '';
}
// Support space separated events
var eventsObject = {};
for (var _i = 0, _Object$keys = Object.keys(events); _i < _Object$keys.length; _i++) {
var key = _Object$keys[_i];
var _iterator = _createForOfIteratorHelper(key.split(' ')),
_step;
try {
for (_iterator.s(); !(_step = _iterator.n()).done;) {
var event = _step.value;
eventsObject[event] = events[key];
}
} catch (err) {
_iterator.e(err);
} finally {
_iterator.f();
}
}
events = eventsObject;
return [events, selector];
}
function parseEventNameAndNS(value) {
var eventNameAndNS = value.split('.');
return [eventNameAndNS[0], eventNameAndNS[1] || ''];
}
var Events = {
// Add a namespace to multiple events
getEventsNS: function getEventsNS(events) {
var ns = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : '';
var eventsNS = {};
for (var _i2 = 0, _Object$keys2 = Object.keys(events); _i2 < _Object$keys2.length; _i2++) {
var key = _Object$keys2[_i2];
eventsNS[key.split(' ').join("".concat(ns, " ")) + ns] = events[key];
}
return eventsNS;
},
off: function off(element, events, selector, handler) {
var storage = Data.get(element, DATA_KEY);
if (!storage) {
return;
}
var _normalizeArguments = normalizeArguments(events, selector, handler);
var _normalizeArguments2 = _slicedToArray(_normalizeArguments, 2);
events = _normalizeArguments2[0];
selector = _normalizeArguments2[1];
var _loop = function _loop() {
var key = _Object$keys3[_i3];
var handler = events[key];
if (handler && !storage.has(handler)) {
return {
v: void 0
};
}
var _parseEventNameAndNS = parseEventNameAndNS(key),
_parseEventNameAndNS2 = _slicedToArray(_parseEventNameAndNS, 2),
eventName = _parseEventNameAndNS2[0],
eventNS = _parseEventNameAndNS2[1];
var handlersToDelete = [];
var handlersStorage = handler ? new Map().set(handler, storage.get(handler)) : storage;
var _iterator2 = _createForOfIteratorHelper(handlersStorage),
_step2;
try {
for (_iterator2.s(); !(_step2 = _iterator2.n()).done;) {
var _step2$value = _slicedToArray(_step2.value, 2),
_handler2 = _step2$value[0],
handlerStorage = _step2$value[1];
handlerStorage.eventHandlers = handlerStorage.eventHandlers.filter(function (eventHandler) {
var keep = false;
if (eventName) {
keep = !(eventName === eventHandler.eventName && (!eventNS || eventNS === eventHandler.eventNS) && (!selector || selector === eventHandler.selector));
} else if (eventNS) {
keep = !(eventNS === eventHandler.eventNS && (!selector || selector === eventHandler.selector));
} else if (selector) {
keep = selector !== eventHandler.selector;
}
if (!keep) {
element.removeEventListener(eventHandler.eventName, eventHandler.realHandler, Boolean(eventHandler.selector));
}
return keep;
});
if (handlerStorage.eventHandlers.length === 0) {
handlersToDelete.push(_handler2);
}
}
} catch (err) {
_iterator2.e(err);
} finally {
_iterator2.f();
}
for (var _i4 = 0, _handlersToDelete = handlersToDelete; _i4 < _handlersToDelete.length; _i4++) {
var _handler = _handlersToDelete[_i4];
storage.delete(_handler);
}
};
for (var _i3 = 0, _Object$keys3 = Object.keys(events); _i3 < _Object$keys3.length; _i3++) {
var _ret = _loop();
if (_typeof(_ret) === "object") return _ret.v;
}
},
on: function on(element, events, selector, handler) {
var storage = Data.get(element, DATA_KEY);
if (!storage) {
storage = new Map();
Data.set(element, DATA_KEY, storage);
}
var _normalizeArguments3 = normalizeArguments(events, selector, handler);
var _normalizeArguments4 = _slicedToArray(_normalizeArguments3, 2);
events = _normalizeArguments4[0];
selector = _normalizeArguments4[1];
var _loop2 = function _loop2() {
var key = _Object$keys4[_i5];
var handler = events[key];
var _parseEventNameAndNS3 = parseEventNameAndNS(key),
_parseEventNameAndNS4 = _slicedToArray(_parseEventNameAndNS3, 2),
eventName = _parseEventNameAndNS4[0],
eventNS = _parseEventNameAndNS4[1];
var realHandler = selector ? /^mouse(enter|leave)$/.test(eventName) ? function (event) {
var target = event.target;
if (target && target.matches && target.matches(selector) && element.contains(target)) {
handler.call(target, event, target);
}
} : function (event) {
var target = event.target;
var closest = target && target.closest && target.closest(selector);
if (closest && element.contains(closest)) {
handler.call(closest, event, closest);
}
} : function (event) {
handler.call(element, event, element);
};
if (!storage.has(handler)) {
storage.set(handler, {
eventHandlers: []
});
}
var handlerStorage = storage.get(handler);
handlerStorage.eventHandlers.push({
eventName: eventName,
eventNS: eventNS,
selector: selector,
realHandler: realHandler
});
element.addEventListener(eventName, realHandler, Boolean(selector));
};
for (var _i5 = 0, _Object$keys4 = Object.keys(events); _i5 < _Object$keys4.length; _i5++) {
_loop2();
}
},
trigger: function trigger(element, eventName, data) {
var event = new CustomEvent(eventName, {
bubbles: true,
cancelable: true,
detail: data || null
});
element.dispatchEvent(event);
return event;
}
};
/*
* SmartMenus
* http://www.smartmenus.org/
* Copyright (c) since 2001 Vasil Dinkov, Vadikom Web Ltd. http://vadikom.com
* Licensed MIT https://github.com/vadikom/smartmenus/blob/master/LICENSE-MIT
*/
var Helpers = {
getComputedStyle: function getComputedStyle(element) {
return Helpers.getWindow(element).getComputedStyle(element);
},
getDocument: function getDocument(element) {
return element && element.ownerDocument || window.document;
},
getHeight: function getHeight(element) {
return Helpers._getDimensions(element, true);
},
getViewportHeight: function getViewportHeight(element) {
return Helpers._getViewportDimensions(element, true);
},
getViewportWidth: function getViewportWidth(element) {
return Helpers._getViewportDimensions(element);
},
getWidth: function getWidth(element) {
return Helpers._getDimensions(element);
},
getWindow: function getWindow(element) {
var ownerDocument = element && element.ownerDocument;
return ownerDocument && ownerDocument.defaultView || window;
},
_getDimensions: function _getDimensions(element, height) {
var elementStyle = element.style;
var oldStyle = null;
if (Helpers.getComputedStyle(element).display === 'none') {
oldStyle = {
position: elementStyle.position,
visibility: elementStyle.visibility,
display: elementStyle.display
};
elementStyle.position = 'absolute';
elementStyle.visibility = 'hidden';
elementStyle.display = 'block';
}
var value = element.getBoundingClientRect()[height ? 'height' : 'width'];
if (oldStyle) {
elementStyle.display = oldStyle.display;
elementStyle.position = oldStyle.position;
elementStyle.visibility = oldStyle.visibility;
}
return value;
},
_getViewportDimensions: function _getViewportDimensions(element, height) {
var _window = Helpers.getWindow(element);
var visualViewport = _window.visualViewport;
if (visualViewport) {
return visualViewport[height ? 'height' : 'width'];
}
var _document = Helpers.getDocument(element);
var name = height ? 'Height' : 'Width';
var value = _document.documentElement["client".concat(name)];
var value2 = _window["inner".concat(name)];
return value2 ? Math.min(value, value2) : value;
}
};
/*
* SmartMenus
* http://www.smartmenus.org/
* Copyright (c) since 2001 Vasil Dinkov, Vadikom Web Ltd. http://vadikom.com
* Licensed MIT https://github.com/vadikom/smartmenus/blob/master/LICENSE-MIT
*/
var Query = {
get: function get(selector) {
var element = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : document.documentElement;
return element.querySelector(selector);
},
getAll: function getAll(selector) {
var element = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : document.documentElement;
return _toConsumableArray(element.querySelectorAll(selector));
},
closest: function closest(element, matchFunction) {
var closest = null;
while (element) {
if (matchFunction(element)) {
closest = element;
break;
}
element = element.parentElement;
}
return closest;
},
parentsUntil: function parentsUntil(element, selector, filter) {
var parents = [];
var parent = element.parentElement;
while (parent && !parent.matches(selector)) {
if (!filter || parent.matches(filter)) {
parents.push(parent);
}
parent = parent.parentElement;
}
return parents;
}
};
/*
* SmartMenus
* http://www.smartmenus.org/
* Copyright (c) since 2001 Vasil Dinkov, Vadikom Web Ltd. http://vadikom.com
* Licensed MIT https://github.com/vadikom/smartmenus/blob/master/LICENSE-MIT
*/
var DATA_KEY$1 = 'sm-mouse';
var EVENTS_NS = ".".concat(DATA_KEY$1);
var supportMouseInput; // true/false when detection is enabled, undefined when detection is disabled
var supportPointerEvents = typeof window === 'undefined' ? false : Boolean(window.PointerEvent);
var MouseInputDetect = {
get supportMouseInput() {
return supportMouseInput;
},
disable: function disable() {
if (supportMouseInput !== undefined) {
Events.off(document, EVENTS_NS);
supportMouseInput = undefined;
}
},
enable: function enable(callbackOnFirstDetection) {
if (supportMouseInput === undefined) {
supportMouseInput = false;
// If we get two consecutive mousemoves within 4 pixels from each other and within 300ms, we assume a real mouse/cursor is present
// in practice, this seems like impossible to trick unintentianally with a real mouse and a pretty safe detection on touch devices (even with older browsers that do not support touch events)
var isFirstDetection = true;
var lastMove = null;
var events = {
mousemove: function mousemove(event) {
var thisMove = {
x: event.pageX,
y: event.pageY,
timeStamp: Date.now()
};
if (lastMove) {
var deltaX = Math.abs(lastMove.x - thisMove.x);
var deltaY = Math.abs(lastMove.y - thisMove.y);
if ((deltaX > 0 || deltaY > 0) && deltaX <= 4 && deltaY <= 4 && thisMove.timeStamp - lastMove.timeStamp <= 300) {
supportMouseInput = true;
if (isFirstDetection) {
if (callbackOnFirstDetection) {
callbackOnFirstDetection(event);
}
isFirstDetection = false;
}
}
}
lastMove = thisMove;
}
};
events[supportPointerEvents ? 'pointerover pointermove pointerout' : 'touchstart'] = function (event) {
if (!/^(4|mouse)$/.test(event.pointerType)) {
supportMouseInput = false;
}
};
Events.on(document, Events.getEventsNS(events, EVENTS_NS));
}
}
};
/*
* SmartMenus
* http://www.smartmenus.org/
* Copyright (c) since 2001 Vasil Dinkov, Vadikom Web Ltd. http://vadikom.com
* Licensed MIT https://github.com/vadikom/smartmenus/blob/master/LICENSE-MIT
*/
var DEFAULTS = {
collapsibleActivateSelectedLinkOnInit: false,
collapsibleBehaviorAccordion: false,
collapsibleResetSubsOnClickOn: 'toggler',
dropdownsShowTrigger: 'click',
dropdownsShowTimeout: 250,
dropdownsHideTrigger: 'click',
dropdownsHideTimeout: 500,
dropdownsDropReverseX: false,
dropdownsDropReverseY: false,
dropdownsNavSubOffsetX: 0,
dropdownsNavSubOffsetY: 0,
dropdownsSubSubOffsetX: 0,
dropdownsSubSubOffsetY: 0,
dropdownsKeepInViewport: true,
markCurrentLinkAsSelectedOnInit: false,
markCurrentLinkParentsAsSelected: false,
resetTogglerOnLinkSelect: false,
showSubOnSplitLinkSelect: false,
classNavbarVertical: 'sm-navbar--vertical',
classNavbarDropReverseY: 'sm-navbar--drop-reverse-y',
classNavbarDropReverseX: 'sm-navbar--drop-reverse-x',
classSubMega: 'sm-sub--mega',
classLinkExpanded: 'sm-expanded',
classLinkSelected: 'sm-selected',
classLinkDisabled: 'sm-disabled',
classLinkHasSub: 'sm-has-sub',
classShow: 'sm-show',
classShowing: 'sm-showing',
classHiding: 'sm-hiding',
selectorTogglerState: '.sm-toggler-state',
selectorTogglerAnchorShow: '.sm-toggler-anchor--show',
selectorTogglerAnchorHide: '.sm-toggler-anchor--hide',
selectorCollapse: '.sm-collapse',
selectorOffcanvas: '.sm-offcanvas',
selectorOffcanvasOverlay: '.sm-offcanvas-overlay',
selectorNav: '.sm-nav',
selectorSub: '.sm-sub',
selectorItem: '.sm-nav-item, .sm-sub-item',
selectorLink: '.sm-nav-link, .sm-sub-link',
selectorLinkSplit: '.sm-nav-link--split, .sm-sub-link--split'
};
var DATA_KEY$2 = 'sm';
var DATA_SUFFIX = "-".concat(DATA_KEY$2);
var DATA_ATTRIBUTE_PREFIX = "data-".concat(DATA_KEY$2, "-");
var EVENTS_NS$1 = ".".concat(DATA_KEY$2);
var API_EVENTS_SUFFIX = "-".concat(DATA_KEY$2);
var navbars = [];
var SmartMenus = /*#__PURE__*/function () {
function SmartMenus(element, options) {
_classCallCheck(this, SmartMenus);
this._navbar = element;
// Get any options defined as data- attributes
var dataOptions = {};
for (var _i = 0, _Object$keys = Object.keys(DEFAULTS); _i < _Object$keys.length; _i++) {
var key = _Object$keys[_i];
var dataValue = this._navbar.dataset["".concat(DATA_KEY$2).concat(key.charAt(0).toUpperCase()).concat(key.slice(1))];
if (dataValue !== undefined) {
switch (_typeof(DEFAULTS[key])) {
case 'number':
{
dataValue = Number.parseFloat(dataValue, 10);
break;
}
case 'boolean':
{
dataValue = dataValue === 'true';
break;
}
}
dataOptions[key] = dataValue;
}
}
this._opts = _objectSpread2(_objectSpread2(_objectSpread2({}, DEFAULTS), options), dataOptions);
this._togglerState = null;
this._togglerAnchorShow = null;
this._togglerAnchorHide = null;
this._collapse = null;
this._offcanvas = null;
this._offcanvasOverlay = null;
this._nav = null;
this._navbarId = String(Date.now() + Math.random()).replace(/\D/g, ''); // for internal use
this._accessIdPrefix = "".concat(DATA_KEY$2, "-").concat(this._navbarId, "-");
this._visibleSubs = []; // stores visible subs (might be in no particular order in collapsible non-accordion mode)
this._dropdownsShowTimeout = 0;
this._dropdownsHideTimeout = 0;
this._clickActivated = false;
this._zIndexInc = 0;
this._idInc = 0;
this._disabled = false;
this._wasCollapsible = false;
// We'll access these for some tests at runtime so we'll cache them
this._firstLink = null;
this._firstSub = null;
this._init();
}
// Getters
_createClass(SmartMenus, [{
key: "destroy",
// Public
value: function destroy(refresh) {
this.subHideAll();
if (this._nav) {
this._destroySubs();
this._destroyNav();
this._nav = null;
}
this._togglerState = null;
if (this._togglerAnchorShow) {
Data.delete(this._togglerAnchorShow, "beforefirstshow-fired".concat(DATA_SUFFIX));
this._togglerAnchorShow = null;
}
this._togglerAnchorHide = null;
this._collapse = null;
this._offcanvas = null;
this._offcanvasOverlay = null;
this._firstLink = null;
this._firstSub = null;
if (!refresh) {
this._destroyNavbar();
this._navbar = null;
}
}
}, {
key: "disable",
value: function disable() {
if (!this._disabled) {
this.subHideAll();
this._disabled = true;
}
}
}, {
key: "enable",
value: function enable() {
if (this._disabled) {
this._disabled = false;
}
}
/**
* Activate a menu link
*
* @param {HTMLElement} element Any element which matches the "selectorLink" selector
* @param {('none'|'same'|'deeper'|'self')} hideSubs Hide any visible subs from the same or deeper levels or only the self sub (if it exists)
* @param {boolean} showSub Should the link's sub be shown (if it exists)?
* @returns {void}
*/
}, {
key: "linkActivate",
value: function linkActivate(element) {
var hideSubs = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 'none';
var showSub = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : true;
var menu = element.closest("".concat(this._opts.selectorNav, ", ").concat(this._opts.selectorSub));
var level = Data.get(menu, "level".concat(DATA_SUFFIX));
var sub = Data.get(element, "sub".concat(DATA_SUFFIX));
// If for some reason the containing menu is not visible (e.g. this is an API call to activate the link), show all parent menus first
if (level > 1 && !this._subIsVisible(menu)) {
var parents = Query.parentsUntil(menu, this._opts.selectorNav, this._opts.selectorSub).reverse();
parents.push(menu);
var _iterator = _createForOfIteratorHelper(parents),
_step;
try {
for (_iterator.s(); !(_step = _iterator.n()).done;) {
var _menu = _step.value;
this.linkActivate(Data.get(_menu, "parent-link".concat(DATA_SUFFIX)), this._isCollapsible() && !this._opts.collapsibleBehaviorAccordion ? 'none' : 'same');
}
} catch (err) {
_iterator.e(err);
} finally {
_iterator.f();
}
}
// Hide any visible subs
switch (hideSubs) {
case 'same':
{
this._subHideSubs(level - 1);
break;
}
case 'deeper':
{
this._subHideSubs(level);
break;
}
case 'self':
{
if (sub) {
this._subHide(sub);
}
break;
}
}
if (Events.trigger(this._navbar, "activate".concat(API_EVENTS_SUFFIX), element).defaultPrevented || !showSub) {
return;
}
// Show the sub menu if this link has one
if (sub) {
this._subShow(sub);
}
}
}, {
key: "refresh",
value: function refresh() {
this.destroy(true);
this._init(true);
}
}, {
key: "subHideAll",
value: function subHideAll() {
this._clearTimeout(this._dropdownsShowTimeout);
this._clearTimeout(this._dropdownsHideTimeout);
var visibleCount = this._visibleSubs.length;
if (visibleCount > 0) {
var _iterator2 = _createForOfIteratorHelper(_toConsumableArray(this._visibleSubs).reverse()),
_step2;
try {
for (_iterator2.s(); !(_step2 = _iterator2.n()).done;) {
var sub = _step2.value;
this._subHide(sub);
}
} catch (err) {
_iterator2.e(err);
} finally {
_iterator2.f();
}
}
this._visibleSubs = [];
this._clickActivated = false;
this._zIndexInc = 0;
if (visibleCount > 0) {
Events.trigger(this._navbar, "hideall".concat(API_EVENTS_SUFFIX));
}
} // Private
}, {
key: "_activateSelectedLink",
value: function _activateSelectedLink() {
var selectedLink = Query.getAll(".".concat(this._opts.classLinkSelected), this._nav).pop();
if (selectedLink) {
this.linkActivate(selectedLink);
}
}
}, {
key: "_animate",
value: function _animate(element, classAnimate) {
// Reflow to make sure the animation would be restarted
void element.offsetWidth;
element.classList.add(classAnimate);
var _Helpers$getComputedS = Helpers.getComputedStyle(element),
animationDuration = _Helpers$getComputedS.animationDuration;
if (!animationDuration || animationDuration.startsWith('0s')) {
element.classList.remove(classAnimate);
return;
}
// Trigger animationend if animation needs to be stopped or just in case it isn't fired for some reason
var endTimeout = Data.get(element, "animationend-timeout".concat(DATA_SUFFIX));
if (endTimeout) {
window.clearTimeout(endTimeout);
Data.get(element, "animationend-trigger".concat(DATA_SUFFIX))();
}
var endTrigger = function endTrigger() {
Data.delete(element, "animationend-timeout".concat(DATA_SUFFIX));
Data.delete(element, "animationend-trigger".concat(DATA_SUFFIX));
if (element.classList.contains(classAnimate)) {
Events.trigger(element, 'animationend');
}
};
Data.set(element, "animationend-trigger".concat(DATA_SUFFIX), endTrigger);
Data.set(element, "animationend-timeout".concat(DATA_SUFFIX), window.setTimeout(endTrigger, Number.parseFloat(animationDuration) * 1000 + 1));
Events.on(element, "animationend".concat(EVENTS_NS$1), function (event) {
if (event.target === element) {
Events.off(element, "animationend".concat(EVENTS_NS$1));
element.classList.remove(classAnimate);
}
});
}
}, {
key: "_animateHide",
value: function _animateHide(element) {
// This property is used for the expand/collapse animation
element.style.setProperty("--".concat(DATA_KEY$2, "-height"), "".concat(Helpers.getHeight(element), "px"));
element.classList.remove(this._opts.classShow);
this._animate(element, this._opts.classHiding);
}
}, {
key: "_animateShow",
value: function _animateShow(element) {
// This property is used for the expand/collapse animation
element.style.setProperty("--".concat(DATA_KEY$2, "-height"), "".concat(Helpers.getHeight(element), "px"));
element.classList.add(this._opts.classShow);
this._animate(element, this._opts.classShowing);
}
}, {
key: "_clearTimeout",
value: function _clearTimeout(timeout) {
if (timeout) {
window.clearTimeout(timeout);
timeout = 0;
}
}
}, {
key: "_destroyLink",
value: function _destroyLink(element) {
if (element.classList.contains(this._opts.classLinkHasSub)) {
if ((element.getAttribute('id') || '').startsWith(this._accessIdPrefix)) {
element.removeAttribute('id');
}
element.classList.remove(this._opts.classLinkHasSub);
Data.delete(element, "sub".concat(DATA_SUFFIX));
Data.delete(element, "toggler".concat(DATA_SUFFIX));
Data.delete(element, "link".concat(DATA_SUFFIX));
element.removeAttribute('role');
element.removeAttribute('aria-controls');
element.removeAttribute('aria-expanded');
}
if (this._opts.markCurrentLinkAsSelectedOnInit && element.classList.contains(this._opts.classLinkSelected)) {
element.classList.remove(this._opts.classLinkSelected);
element.removeAttribute('aria-current');
}
}
}, {
key: "_destroyNav",
value: function _destroyNav() {
Data.delete(this._nav, "level".concat(DATA_SUFFIX));
Events.off(this._nav, EVENTS_NS$1);
Events.off(window.document, "".concat(EVENTS_NS$1, "-").concat(this._navbarId));
Events.off(window, "".concat(EVENTS_NS$1, "-").concat(this._navbarId));
}
}, {
key: "_destroyNavbar",
value: function _destroyNavbar() {
Data.delete(this._navbar, DATA_KEY$2);
this._navbar.removeAttribute("".concat(DATA_ATTRIBUTE_PREFIX, "id"));
Events.off(this._navbar, EVENTS_NS$1);
navbars.splice(navbars.indexOf(this), 1);
}
}, {
key: "_destroySub",
value: function _destroySub(element) {
var shownBefore = Data.get(element, "shown-before".concat(DATA_SUFFIX));
if (shownBefore) {
this._subResetPosition(element);
}
if ((element.getAttribute('id') || '').startsWith(this._accessIdPrefix)) {
element.removeAttribute('id');
}
Data.delete(element, "shown-before".concat(DATA_SUFFIX));
Data.delete(element, "parent-link".concat(DATA_SUFFIX));
Data.delete(element, "level".concat(DATA_SUFFIX));
Data.delete(element, "beforefirstshow-fired".concat(DATA_SUFFIX));
element.removeAttribute('aria-hidden');
element.removeAttribute('aria-labelledby');
}
}, {
key: "_destroySubs",
value: function _destroySubs() {
var _iterator3 = _createForOfIteratorHelper(Query.getAll(this._opts.selectorSub, this._nav)),
_step3;
try {
for (_iterator3.s(); !(_step3 = _iterator3.n()).done;) {
var sub = _step3.value;
this._destroySub(sub);
}
// Let's process the links separately from the subs (unline on init) since some link might possibly be disconnected
// from the sub it had on init (e.g. its sub might have been removed in some DOM operation)
} catch (err) {
_iterator3.e(err);
} finally {
_iterator3.f();
}
var _iterator4 = _createForOfIteratorHelper(Query.getAll(this._opts.selectorLink, this._nav)),
_step4;
try {
for (_iterator4.s(); !(_step4 = _iterator4.n()).done;) {
var link = _step4.value;
this._destroyLink(link);
}
} catch (err) {
_iterator4.e(err);
} finally {
_iterator4.f();
}
}
}, {
key: "_docClick",
value: function _docClick(event) {
// Hide on any click outside the nav
var isCollapsible = this._isCollapsible();
if ((!isCollapsible && this._opts.dropdownsHideTrigger === 'click' || isCollapsible && this._opts.collapsibleResetSubsOnClickOn === 'page') && (!event.target || !this._nav.contains(event.target))) {
this.subHideAll();
}
}
}, {
key: "_docTouchEnd",
value: function _docTouchEnd() {
var _this = this;
if (!this._lastTouch) {
return;
}
if ((this._lastTouch.x2 === undefined || this._lastTouch.x1 === this._lastTouch.x2) && (this._lastTouch.y2 === undefined || this._lastTouch.y1 === this._lastTouch.y2)) {
this._clearTimeout(this._dropdownsHideTimeout);
// Call with a delay to prevent triggering accidental unwanted click on some page element
var target = this._lastTouch.target;
this._dropdownsHideTimeout = window.setTimeout(function () {
_this._docClick({
target: target
});
}, 350);
}
this._lastTouch = null;
}
}, {
key: "_docTouchMove",
value: function _docTouchMove(event) {
if (!this._lastTouch) {
return;
}
var touchPoint = event.touches[0];
this._lastTouch.x2 = touchPoint.pageX;
this._lastTouch.y2 = touchPoint.pageY;
}
}, {
key: "_docTouchStart",
value: function _docTouchStart(event) {
var touchPoint = event.touches[0];
this._lastTouch = {
x1: touchPoint.pageX,
y1: touchPoint.pageY,
target: touchPoint.target
};
}
}, {
key: "_getRootZIndex",
value: function _getRootZIndex() {
var zIndex = Number.parseInt(Helpers.getComputedStyle(this._navbar).zIndex, 10);
return Number.isNaN(zIndex) ? 1 : zIndex;
}
}, {
key: "_handleEvents",
value: function _handleEvents() {
return !this._disabled && this._isCSSOn();
}
}, {
key: "_init",
value: function _init(refresh) {
if (this._navbar.classList.contains(this._opts.classNavbarDropReverseX)) {
this._opts.dropdownsDropReverseX = true;
}
if (this._navbar.classList.contains(this._opts.classNavbarDropReverseY)) {
this._opts.dropdownsDropReverseY = true;
}
this._togglerState = Query.get(this._opts.selectorTogglerState, this._navbar);
this._togglerAnchorShow = Query.get(this._opts.selectorTogglerAnchorShow, this._navbar);
this._togglerAnchorHide = Query.get(this._opts.selectorTogglerAnchorHide, this._navbar);
this._collapse = Query.get(this._opts.selectorCollapse, this._navbar);
this._offcanvas = Query.get(this._opts.selectorOffcanvas, this._navbar);
this._offcanvasOverlay = Query.get(this._opts.selectorOffcanvasOverlay, this._navbar);
this._nav = Query.get(this._opts.selectorNav, this._navbar);
if (!refresh) {
this._initNavbar();
}
if (this._nav) {
this._initNav();
this._initSubs();
// Save initial state
var isCollapsible = this._isCollapsible();
this._wasCollapsible = isCollapsible;
if (this._opts.markCurrentLinkAsSelectedOnInit) {
this._markCurrentLinkAsSelected();
}
if (this._opts.collapsibleActivateSelectedLinkOnInit && isCollapsible) {
this._activateSelectedLink();
}
MouseInputDetect.enable(
// On mouse input detected - check if we are not over some link by chance and call the mouseenter handler if yes
function (event) {
var target = event.target;
if (target !== null && target !== void 0 && target.closest) {
navbars.some(function (object) {
var link = target.closest(object._opts.selectorLink);
if (link && object._navbar.contains(link)) {
object._linkEnter(event, link);
return true;
}
return false;
});
}
});
}
}
}, {
key: "_initNav",
value: function _initNav() {
Data.set(this._nav, "level".concat(DATA_SUFFIX), 1);
Events.on(this._nav, Events.getEventsNS({
'mouseover focusin': this._navOver.bind(this),
'mouseout focusout': this._navOut.bind(this),
keydown: this._navKeyDown.bind(this)
}, EVENTS_NS$1));
Events.on(this._nav, Events.getEventsNS({
mouseenter: this._linkEnter.bind(this),
mouseleave: this._linkLeave.bind(this),
mousedown: this._linkDown.bind(this),
focus: this._linkFocus.bind(this),
blur: this._linkBlur.bind(this),
click: this._linkClick.bind(this)
}, EVENTS_NS$1), this._opts.selectorLink);
}
}, {
key: "_initNavbar",
value: function _initNavbar() {
navbars.push(this);
Data.set(this._navbar, DATA_KEY$2, this);
this._navbar.setAttribute("".concat(DATA_ATTRIBUTE_PREFIX, "id"), this._navbarId);
Events.on(this._navbar, "click".concat(EVENTS_NS$1), this._opts.selectorTogglerAnchorShow, this._togglerAnchorShowClick.bind(this));
Events.on(this._navbar, "click".concat(EVENTS_NS$1), this._opts.selectorTogglerAnchorHide, this._togglerAnchorHideClick.bind(this));
Events.on(this._navbar, "click".concat(EVENTS_NS$1), this._opts.selectorOffcanvasOverlay, this._offcanvasOverlayClick.bind(this));
}
}, {
key: "_initSub",
value: function _initSub(element) {
var parentLink = Query.get(this._opts.selectorLink, element.closest(this._opts.selectorItem));
parentLink.classList.add(this._opts.classLinkHasSub);
var parentLinkNextElement = parentLink.nextElementSibling;
var parentLinkToggler = parentLinkNextElement !== null && parentLinkNextElement !== void 0 && parentLinkNextElement.matches(this._opts.selectorLinkSplit) && parentLink.matches(this._opts.selectorLinkSplit) ? parentLinkNextElement : null;
if (parentLinkToggler) {
Data.set(parentLink, "toggler".concat(DATA_SUFFIX), parentLinkToggler);
Data.set(parentLinkToggler, "link".concat(DATA_SUFFIX), parentLink);
parentLinkToggler.classList.add(this._opts.classLinkHasSub);
}
Data.set(parentLink, "sub".concat(DATA_SUFFIX), element);
Data.set(element, "parent-link".concat(DATA_SUFFIX), parentLink);
Data.set(element, "level".concat(DATA_SUFFIX), Query.parentsUntil(element, this._opts.selectorNav, this._opts.selectorSub).length + 2);
this._setTogglerSubARIA(parentLinkToggler || parentLink, element);
}
}, {
key: "_initSubs",
value: function _initSubs() {
// Hide subs on tap or click outside the nav
if (this._opts.dropdownsHideTrigger === 'click' || this._opts.collapsibleResetSubsOnClickOn === 'page') {
Events.on(window.document, Events.getEventsNS({
touchstart: this._docTouchStart.bind(this),
touchmove: this._docTouchMove.bind(this),
touchend: this._docTouchEnd.bind(this),
click: this._docClick.bind(this)
}, "".concat(EVENTS_NS$1, "-").concat(this._navbarId)));
}
// Hide subs on resize
Events.on(window, Events.getEventsNS({
'resize orientationchange': this._winResize.bind(this)
}, "".concat(EVENTS_NS$1, "-").concat(this._navbarId)));
var subs = Query.getAll(this._opts.selectorSub, this._nav);
var _iterator5 = _createForOfIteratorHelper(subs),
_step5;
try {
for (_iterator5.s(); !(_step5 = _iterator5.n()).done;) {
var sub = _step5.value;
this._initSub(sub);
}
// Cache these for faster access at runtime
} catch (err) {
_iterator5.e(err);
} finally {
_iterator5.f();
}
this._firstLink = Query.get(this._opts.selectorLink, this._nav);
this._firstSub = subs[0];
}
}, {
key: "_isCollapsible",
value: function _isCollapsible() {
return this._isCSSOn() && this._firstSub && Helpers.getComputedStyle(this._firstSub).position === 'static';
}
}, {
key: "_isCSSOn",
value: function _isCSSOn() {
return this._firstLink && Helpers.getComputedStyle(this._firstLink).display !== 'inline';
}
}, {
key: "_isTouchMode",
value: function _isTouchMode() {
return !MouseInputDetect.supportMouseInput || this._isCollapsible();
}
}, {
key: "_linkBlur",
value: function _linkBlur(event, element) {
if (!this._handleEvents()) {
return;
}
// If this is a split link toggler, trigger the handler for the actual link
var link = Data.get(element, "link".concat(DATA_SUFFIX));
if (link) {
this._linkBlur(event, link);
return;
}
Events.trigger(this._navbar, "blur".concat(API_EVENTS_SUFFIX), element);
}
/* eslint-disable complexity */
// Maybe refactor this to lower complexity?
}, {
key: "_linkClick",
value: function _linkClick(event, element) {
if (!this._handleEvents()) {
return;
}
if (element.classList.contains(this._opts.classLinkDisabled)) {
event.preventDefault();
return false;
}
// If this is a split link toggler, get the actual link
var link = Data.get(element, "link".concat(DATA_SUFFIX));
var isTogglerClicked = Boolean(link);
if (!isTogglerClicked) {
link = element;
}
if (Events.trigger(this._navbar, "click".concat(API_EVENTS_SUFFIX), link).defaultPrevented) {
event.preventDefault();
return false;
}
var linkToggler = Data.get(link, "toggler".concat(DATA_SUFFIX));
var sub = Data.get(link, "sub".concat(DATA_SUFFIX));
var subIsVisible = sub && this._subIsVisible(sub);
var level = Data.get(sub, "level".concat(DATA_SUFFIX)) - 1;
var isCollapsible = this._isCollapsible();
var selectLink = !sub || linkToggler && !isTogglerClicked;
if (selectLink && Events.trigger(this._navbar, "select".concat(API_EVENTS_SUFFIX), link).defaultPrevented) {
event.preventDefault();
return false;
}
if (sub && (!selectLink || this._opts.showSubOnSplitLinkSelect)) {
this._clickActivated = this._clickActivated || Boolean(!isCollapsible && !subIsVisible && this._opts.dropdownsShowTrigger === 'click-then-mouseover' && level === 1);
}
// Activate link
var hideSubs = 'none';
if (subIsVisible && isCollapsible && !this._opts.collapsibleBehaviorAccordion && (!selectLink || !this._opts.showSubOnSplitLinkSelect)) {
hideSubs = 'self';
} else if (sub && (subIsVisible && (!isCollapsible || this._opts.collapsibleBehaviorAccordion) && (!selectLink || !this._opts.showSubOnSplitLinkSelect) || !subIsVisible && (!isCollapsible || this._opts.collapsibleBehaviorAccordion && (!selectLink || this._opts.showSubOnSplitLinkSelect))) || !sub && !isCollapsible) {
hideSubs = 'same';
}
var showSub = selectLink ? this._opts.showSubOnSplitLinkSelect : !subIsVisible;
this.linkActivate(link, hideSubs, showSub);
// Select link
if (selectLink) {
if (this._opts.resetTogglerOnLinkSelect && this._togglerAnchorHide && Helpers.getComputedStyle(this._togglerAnchorHide).display !== 'none' && this._togglerAnchorHide.offsetWidth > 0) {
this._togglerAnchorHide.click();
}
if (!isCollapsible && (!sub || subIsVisible || !this._opts.showSubOnSplitLinkSelect)) {
this.subHideAll();
}
return true;
}
// Toggle sub
if (sub) {
if (!isCollapsible && level === 1 && subIsVisible) {
this.subHideAll();
}
event.preventDefault();
return false;
}
} /* eslint-enable complexity */
}, {
key: "_linkDown",
value: function _linkDown(event, element) {
if (!this._handleEvents()) {
return;
}
// If this is a split link toggler, trigger the handler for the actual link
var link = Data.get(element, "link".concat(DATA_SUFFIX));
if (link) {
this._linkDown(event, link);
return;
}
Data.set(element, "mousedown".concat(DATA_SUFFIX), true);
}
}, {
key: "_linkEnter",
value: function _linkEnter(event, element) {
var _this2 = this;
if (!this._handleEvents()) {
return;
}
// If this is a split link toggler, trigger the handler for the actual link
var link = Data.get(element, "link".concat(DATA_SUFFIX));
if (link) {
this._linkEnter(event, link);
return;
}
if (!this._isTouchMode() && (this._opts.dropdownsShowTrigger === 'mouseover' || this._opts.dropdownsShowTrigger === 'click-then-mouseover' && this._clickActivated || this._opts.dropdownsHideTrigger !== 'click')) {
this._clearTimeout(this._dropdownsShowTimeout);
var level = Data.get(element.closest("".concat(this._opts.selectorNav, ", ").concat(this._opts.selectorSub)), "level".concat(DATA_SUFFIX));
var sub = Data.get(element, "sub".concat(DATA_SUFFIX));
var hideSubs = !sub || !this._subIsVisible(sub) ? 'same' : 'deeper';
var showSub = this._opts.dropdownsShowTrigger === 'mouseover' || this._opts.dropdownsShowTrigger === 'click-then-mouseover' && this._clickActivated;
var timeout = this._opts.dropdownsShowTrigger === 'click-then-mouseover' && level === 1 ? 1 : this._opts.dropdownsShowTimeout;
this._dropdownsShowTimeout = window.setTimeout(function () {
_this2.linkActivate(element, hideSubs, showSub);
}, timeout);
}
Events.trigger(this._navbar, "mouseenter".concat(API_EVENTS_SUFFIX), element);
}
}, {
key: "_linkFocus",
value: func