UNPKG

devextreme

Version:

HTML5 JavaScript Component Suite for Responsive Web Development

923 lines (921 loc) • 42.2 kB
/** * DevExtreme (cjs/__internal/ui/menu/menu.js) * Version: 25.2.3 * Build date: Fri Dec 12 2025 * * Copyright (c) 2012 - 2025 Developer Express Inc. ALL RIGHTS RESERVED * Read about DevExtreme licensing here: https://js.devexpress.com/Licensing/ */ "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.default = exports.DX_MENU_ITEM_CLASS = void 0; var _events_engine = _interopRequireDefault(require("../../../common/core/events/core/events_engine")); var _hover = require("../../../common/core/events/hover"); var _pointer = _interopRequireDefault(require("../../../common/core/events/pointer")); var _utils = require("../../../common/core/events/utils"); var _component_registrator = _interopRequireDefault(require("../../../core/component_registrator")); var _element = require("../../../core/element"); var _renderer = _interopRequireDefault(require("../../../core/renderer")); var _common = require("../../../core/utils/common"); var _extend = require("../../../core/utils/extend"); var _iterator = require("../../../core/utils/iterator"); var _size = require("../../../core/utils/size"); var _type = require("../../../core/utils/type"); var _button = _interopRequireDefault(require("../../../ui/button")); var _ui = _interopRequireDefault(require("../../../ui/overlay/ui.overlay")); var _tree_view = _interopRequireDefault(require("../../../ui/tree_view")); var _menu_base = _interopRequireDefault(require("../../ui/context_menu/menu_base")); var _utils2 = require("../../ui/overlay/utils"); var _submenu = _interopRequireDefault(require("./submenu")); function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e } } const DX_MENU_CLASS = "dx-menu"; const DX_MENU_VERTICAL_CLASS = "dx-menu-vertical"; const DX_MENU_HORIZONTAL_CLASS = "dx-menu-horizontal"; const DX_MENU_ITEM_CLASS = exports.DX_MENU_ITEM_CLASS = "dx-menu-item"; const DX_MENU_ITEMS_CONTAINER_CLASS = "dx-menu-items-container"; const DX_MENU_ITEM_EXPANDED_CLASS = `${DX_MENU_ITEM_CLASS}-expanded`; const DX_CONTEXT_MENU_CLASS = "dx-context-menu"; const DX_CONTEXT_MENU_CONTAINER_BORDER_CLASS = "dx-context-menu-container-border"; const DX_CONTEXT_MENU_CONTENT_DELIMITER_CLASS = "dx-context-menu-content-delimiter"; const DX_SUBMENU_CLASS = "dx-submenu"; const DX_STATE_DISABLED_CLASS = "dx-state-disabled"; const DX_STATE_HOVER_CLASS = "dx-state-hover"; const DX_STATE_ACTIVE_CLASS = "dx-state-active"; const DX_ADAPTIVE_MODE_CLASS = "dx-menu-adaptive-mode"; const DX_ADAPTIVE_HAMBURGER_BUTTON_CLASS = "dx-menu-hamburger-button"; const DX_ADAPTIVE_MODE_OVERLAY_WRAPPER_CLASS = `${DX_ADAPTIVE_MODE_CLASS}-overlay-wrapper`; const FOCUS_UP = "up"; const FOCUS_DOWN = "down"; const FOCUS_LEFT = "left"; const FOCUS_RIGHT = "right"; const SHOW_SUBMENU_OPERATION = "showSubmenu"; const NEXT_ITEM_OPERATION = "nextItem"; const PREV_ITEM_OPERATION = "prevItem"; const DEFAULT_DELAY = { show: 50, hide: 300 }; const ACTIONS = ["onSubmenuShowing", "onSubmenuShown", "onSubmenuHiding", "onSubmenuHidden", "onItemContextMenu", "onItemClick", "onSelectionChanged", "onItemRendered"]; class Menu extends _menu_base.default { _getDefaultOptions() { return Object.assign({}, super._getDefaultOptions(), { orientation: "horizontal", submenuDirection: "auto", showFirstSubmenuMode: { name: "onClick", delay: { show: 50, hide: 300 } }, hideSubmenuOnMouseLeave: false, onSubmenuShowing: null, onSubmenuShown: null, onSubmenuHiding: null, onSubmenuHidden: null, adaptivityEnabled: false }) } _setOptionsByReference() { super._setOptionsByReference(); (0, _extend.extend)(this._optionsByReference, { animation: true, selectedItem: true }) } _itemElements() { const rootMenuElements = super._itemElements(); const submenuElements = this._submenuItemElements(); return rootMenuElements.add(submenuElements) } _submenuItemElements() { const itemSelector = `.${DX_MENU_ITEM_CLASS}`; const currentSubmenu = this._submenus.length && this._submenus[0]; if (currentSubmenu && currentSubmenu.itemsContainer()) { var _currentSubmenu$items; return (null === (_currentSubmenu$items = currentSubmenu.itemsContainer()) || void 0 === _currentSubmenu$items ? void 0 : _currentSubmenu$items.find(itemSelector)) ?? (0, _renderer.default)() } return (0, _renderer.default)() } _focusTarget() { return this.$element() } _isMenuHorizontal() { const { orientation: orientation } = this.option(); return "horizontal" === orientation } _moveFocus(location) { const $items = this._getAvailableItems(); const isMenuHorizontal = this._isMenuHorizontal(); const $activeItem = this._getActiveItem(true); let $argument; let operation; switch (location) { case "up": operation = isMenuHorizontal ? "showSubmenu" : this._getItemsNavigationOperation("prevItem"); $argument = isMenuHorizontal ? $activeItem : $items; break; case "down": operation = isMenuHorizontal ? "showSubmenu" : this._getItemsNavigationOperation("nextItem"); $argument = isMenuHorizontal ? $activeItem : $items; break; case "right": operation = isMenuHorizontal ? this._getItemsNavigationOperation("nextItem") : "showSubmenu"; $argument = isMenuHorizontal ? $items : $activeItem; break; case "left": operation = isMenuHorizontal ? this._getItemsNavigationOperation("prevItem") : "showSubmenu"; $argument = isMenuHorizontal ? $items : $activeItem; break; default: return super._moveFocus(location) } const navigationAction = this._getKeyboardNavigationAction(operation, $argument); const $newTarget = navigationAction(); if ($newTarget && 0 !== $newTarget.length) { this.option("focusedElement", (0, _element.getPublicElement)($newTarget)) } } _getItemsNavigationOperation(operation) { const { rtlEnabled: rtlEnabled } = this.option(); if (rtlEnabled) { return "prevItem" === operation ? "nextItem" : "prevItem" } return operation } _getKeyboardNavigationAction(operation, argument) { let action = _common.noop; switch (operation) { case "showSubmenu": if (!argument.hasClass("dx-state-disabled")) { action = this._showSubmenu.bind(this, argument) } break; case "nextItem": action = this._nextItem.bind(this, argument); break; case "prevItem": action = this._prevItem.bind(this, argument) } return action } _clean() { super._clean(); const { templatesRenderAsynchronously: templatesRenderAsynchronously } = this.option(); if (templatesRenderAsynchronously) { clearTimeout(this._resizeEventTimer) } } _visibilityChanged(visible) { if (visible) { if (!this._menuItemsWidth) { this._updateItemsWidthCache() } this._dimensionChanged() } } _isAdaptivityEnabled() { const { adaptivityEnabled: adaptivityEnabled, orientation: orientation } = this.option(); return !!adaptivityEnabled && "horizontal" === orientation } _updateItemsWidthCache() { const $menuItems = this.$element().find("ul").first().children("li").children(`.${DX_MENU_ITEM_CLASS}`); this._menuItemsWidth = this._getSummaryItemsSize("width", $menuItems, true) } _dimensionChanged() { if (!this._isAdaptivityEnabled()) { return } const containerWidth = (0, _size.getOuterWidth)(this.$element()); this._toggleAdaptiveMode(this._menuItemsWidth > containerWidth) } _init() { super._init(); this._submenus = [] } _initActions() { this._actions = {}; (0, _iterator.each)(ACTIONS, ((_index, action) => { this._actions[action] = this._createActionByOption(action) })) } _initMarkup() { this._visibleSubmenu = null; this.$element().addClass("dx-menu"); super._initMarkup(); this._addCustomCssClass(this.$element()); this.setAria("role", "menubar") } _setAriaRole(state) { const role = this._isAdaptivityEnabled() && state ? void 0 : "menubar"; this.setAria({ role: role }) } _render() { super._render(); this._initAdaptivity() } _isTargetOutOfComponent(relatedTarget) { const isInsideRootMenu = 0 !== (0, _renderer.default)(relatedTarget).closest(".dx-menu").length; const isInsideContextMenu = 0 !== (0, _renderer.default)(relatedTarget).closest(".dx-context-menu").length; return !(isInsideRootMenu || isInsideContextMenu) } _focusOutHandler(e) { const { relatedTarget: relatedTarget } = e; if (relatedTarget) { const isTargetOutside = this._isTargetOutOfComponent(relatedTarget); if (isTargetOutside) { this._hideVisibleSubmenu() } } super._focusOutHandler(e) } _renderHamburgerButton() { this._hamburger = new _button.default((0, _renderer.default)("<div>").addClass("dx-menu-hamburger-button"), { icon: "menu", activeStateEnabled: false, onClick: () => { this._toggleTreeView() } }); return this._hamburger.$element() } _toggleTreeView(visible) { var _this$_overlay, _this$_overlay2; const isTreeViewVisible = visible ?? !(null !== (_this$_overlay = this._overlay) && void 0 !== _this$_overlay && null !== (_this$_overlay = _this$_overlay.option()) && void 0 !== _this$_overlay && _this$_overlay.visible); null === (_this$_overlay2 = this._overlay) || void 0 === _this$_overlay2 || _this$_overlay2.option("visible", isTreeViewVisible); if (isTreeViewVisible) { var _this$_treeView; null === (_this$_treeView = this._treeView) || void 0 === _this$_treeView || _this$_treeView.focus() } this._toggleHamburgerActiveState(isTreeViewVisible) } _toggleHamburgerActiveState(isActive) { var _this$_hamburger; null === (_this$_hamburger = this._hamburger) || void 0 === _this$_hamburger || _this$_hamburger.$element().toggleClass("dx-state-active", isActive) } _toggleAdaptiveMode(isAdaptive) { const $menuItemsContainer = this.$element().find(".dx-menu-horizontal"); const $adaptiveElements = this.$element().find(`.${DX_ADAPTIVE_MODE_CLASS}`); if (isAdaptive) { this._hideVisibleSubmenu() } else { var _this$_treeView2; null === (_this$_treeView2 = this._treeView) || void 0 === _this$_treeView2 || _this$_treeView2.collapseAll(); if (this._overlay) { this._toggleTreeView(isAdaptive) } } this._setAriaRole(isAdaptive); $menuItemsContainer.toggle(!isAdaptive); $adaptiveElements.toggle(isAdaptive) } _removeAdaptivity() { if (!this._$adaptiveContainer) { return } this._toggleAdaptiveMode(false); this._$adaptiveContainer.remove(); this._$adaptiveContainer = null; this._treeView = null; this._hamburger = null; this._overlay = null } _treeviewItemClickHandler(e) { var _e$node; this._actions.onItemClick(e); if (!(null !== (_e$node = e.node) && void 0 !== _e$node && null !== (_e$node = _e$node.children) && void 0 !== _e$node && _e$node.length)) { this._toggleTreeView(false) } } _getAdaptiveOverlayOptions() { var _this$_hamburger2; const { rtlEnabled: rtlEnabled } = this.option(); const position = rtlEnabled ? "right" : "left"; return { _ignoreFunctionValueDeprecation: true, maxHeight: () => (0, _utils2.getElementMaxHeightByWindow)(this.$element()), deferRendering: false, shading: false, animation: false, hideOnParentScroll: true, onHidden: () => { this._toggleHamburgerActiveState(false) }, height: "auto", hideOnOutsideClick: e => !(0, _renderer.default)(e.target).closest(".dx-menu-hamburger-button").length, position: { collision: "flipfit", at: `bottom ${position}`, my: `top ${position}`, of: null === (_this$_hamburger2 = this._hamburger) || void 0 === _this$_hamburger2 ? void 0 : _this$_hamburger2.$element() } } } _getTreeViewOptions() { const menuOptions = {}; (0, _iterator.each)(["rtlEnabled", "width", "accessKey", "activeStateEnabled", "animation", "dataSource", "disabled", "displayExpr", "displayExpr", "focusStateEnabled", "hint", "hoverStateEnabled", "itemsExpr", "items", "itemTemplate", "selectedExpr", "selectionMode", "tabIndex", "visible"], ((_index, option) => { menuOptions[option] = this.option(option) })); (0, _iterator.each)(["onItemContextMenu", "onSelectionChanged", "onItemRendered"], ((_index, actionName) => { menuOptions[actionName] = e => { this._actions[actionName](e) } })); const { animation: animation, selectByClick: selectByClick } = this.option(); return Object.assign({}, menuOptions, { dataSource: this.getDataSource(), animationEnabled: !!animation, onItemClick: this._treeviewItemClickHandler.bind(this), onItemExpanded: e => { var _this$_overlay3, _this$_actions$onSubm, _this$_actions; null === (_this$_overlay3 = this._overlay) || void 0 === _this$_overlay3 || _this$_overlay3.repaint(); null === (_this$_actions$onSubm = (_this$_actions = this._actions).onSubmenuShown) || void 0 === _this$_actions$onSubm || _this$_actions$onSubm.call(_this$_actions, e) }, onItemCollapsed: e => { var _this$_overlay4, _this$_actions$onSubm2, _this$_actions2; null === (_this$_overlay4 = this._overlay) || void 0 === _this$_overlay4 || _this$_overlay4.repaint(); null === (_this$_actions$onSubm2 = (_this$_actions2 = this._actions).onSubmenuHidden) || void 0 === _this$_actions$onSubm2 || _this$_actions$onSubm2.call(_this$_actions2, e) }, selectNodesRecursive: false, selectByClick: selectByClick, expandEvent: "click", _supportItemUrl: true }) } _initAdaptivity() { var _this$_overlay$$conte, _this$_overlay$$wrapp; if (!this._isAdaptivityEnabled()) { return } const { cssClass: cssClass } = this.option(); const $hamburger = this._renderHamburgerButton(); this._treeView = this._createComponent((0, _renderer.default)("<div>"), _tree_view.default, this._getTreeViewOptions()); this._overlay = this._createComponent((0, _renderer.default)("<div>"), _ui.default, this._getAdaptiveOverlayOptions()); null === (_this$_overlay$$conte = this._overlay.$content()) || void 0 === _this$_overlay$$conte || _this$_overlay$$conte.append(this._treeView.$element()).addClass(DX_ADAPTIVE_MODE_CLASS).addClass(cssClass); null === (_this$_overlay$$wrapp = this._overlay.$wrapper()) || void 0 === _this$_overlay$$wrapp || _this$_overlay$$wrapp.addClass(DX_ADAPTIVE_MODE_OVERLAY_WRAPPER_CLASS); this._$adaptiveContainer = (0, _renderer.default)("<div>").addClass(DX_ADAPTIVE_MODE_CLASS); this._$adaptiveContainer.append($hamburger); this._$adaptiveContainer.append(this._overlay.$element()); this.$element().append(this._$adaptiveContainer); this._updateItemsWidthCache(); this._dimensionChanged() } _getDelay(delayType) { const { showFirstSubmenuMode: showFirstSubmenuMode } = this.option(); const delay = (0, _type.isObject)(showFirstSubmenuMode) ? showFirstSubmenuMode.delay : void 0; if (!(0, _type.isDefined)(delay)) { return DEFAULT_DELAY[delayType] } return (0, _type.isObject)(delay) ? delay[delayType] ?? DEFAULT_DELAY[delayType] : delay } _keyboardHandler(e) { return super._keyboardHandler(e, !!this._visibleSubmenu) } _renderContainer() { const $wrapper = (0, _renderer.default)("<div>"); $wrapper.appendTo(this.$element()).addClass(this._isMenuHorizontal() ? "dx-menu-horizontal" : "dx-menu-vertical"); return super._renderContainer($wrapper) } _renderSubmenuItems(node, $itemFrame) { const submenu = this._createSubmenu(node, $itemFrame); this._submenus.push(submenu); this._renderBorderElement($itemFrame); return submenu } _getKeyboardListeners() { return super._getKeyboardListeners().concat(this._visibleSubmenu) } _createSubmenu(node, $rootItem) { const $submenuContainer = (0, _renderer.default)("<div>").addClass("dx-context-menu").appendTo($rootItem); const items = this._getChildNodes(node); const subMenu = this._createComponent($submenuContainer, _submenu.default, Object.assign({}, this._getSubmenuOptions(), { _dataAdapter: this._dataAdapter, _parentKey: node.internalFields.key, items: items, onHoverStart: this._clearTimeouts.bind(this), position: this.getSubmenuPosition($rootItem) })); this._attachSubmenuHandlers($rootItem, subMenu); return subMenu } _getSubmenuOptions() { const $submenuTarget = (0, _renderer.default)("<div>"); const isMenuHorizontal = this._isMenuHorizontal(); const { itemTemplate: itemTemplate, orientation: orientation, selectionMode: selectionMode, cssClass: cssClass, selectByClick: selectByClick, hoverStateEnabled: hoverStateEnabled, activeStateEnabled: activeStateEnabled, focusStateEnabled: focusStateEnabled, animation: animation, showSubmenuMode: showSubmenuMode, displayExpr: displayExpr, disabledExpr: disabledExpr, selectedExpr: selectedExpr, itemsExpr: itemsExpr } = this.option(); return { itemTemplate: itemTemplate, target: $submenuTarget, orientation: orientation, selectionMode: selectionMode, cssClass: cssClass, selectByClick: selectByClick, hoverStateEnabled: hoverStateEnabled, activeStateEnabled: activeStateEnabled, focusStateEnabled: focusStateEnabled, animation: animation, showSubmenuMode: showSubmenuMode, displayExpr: displayExpr, disabledExpr: disabledExpr, selectedExpr: selectedExpr, itemsExpr: itemsExpr, onFocusedItemChanged: e => { const { visible: visible, focusedElement: focusedElement } = e.component.option(); if (!visible) { return } this.option("focusedElement", focusedElement) }, onSelectionChanged: this._nestedItemOnSelectionChangedHandler.bind(this), onItemClick: this._nestedItemOnItemClickHandler.bind(this), onItemRendered: this._nestedItemOnItemRenderedHandler.bind(this), onLeftFirstItem: isMenuHorizontal ? null : this._moveMainMenuFocus.bind(this, "prevItem"), onLeftLastItem: isMenuHorizontal ? null : this._moveMainMenuFocus.bind(this, "nextItem"), onCloseRootSubmenu: this._moveMainMenuFocus.bind(this, isMenuHorizontal ? "prevItem" : null), onExpandLastSubmenu: isMenuHorizontal ? this._moveMainMenuFocus.bind(this, "nextItem") : null } } _getShowFirstSubmenuMode() { if (!this._isDesktopDevice()) { return "onClick" } const { showFirstSubmenuMode: optionValue } = this.option(); return (0, _type.isObject)(optionValue) ? optionValue.name : optionValue } _moveMainMenuFocus(direction) { const $items = this._getAvailableItems(); const itemCount = $items.length; const $currentItem = $items.filter(`.${DX_MENU_ITEM_EXPANDED_CLASS}`).eq(0); let itemIndex = $items.index($currentItem); this._hideSubmenu(this._visibleSubmenu); itemIndex += "prevItem" === direction ? -1 : 1; if (itemIndex >= itemCount) { itemIndex = 0 } else if (itemIndex < 0) { itemIndex = itemCount - 1 } const $newItem = $items.eq(itemIndex); this.option("focusedElement", (0, _element.getPublicElement)($newItem)) } _nestedItemOnSelectionChangedHandler(args) { const selectedItem = args.addedItems.length && args.addedItems[0]; const submenu = _submenu.default.getInstance(args.element); const { onSelectionChanged: onSelectionChanged } = this._actions; null === onSelectionChanged || void 0 === onSelectionChanged || onSelectionChanged(args); if (selectedItem) { this._clearSelectionInSubmenus(submenu) } this._clearRootSelection(); this._setOptionWithoutOptionChange("selectedItem", selectedItem) } _clearSelectionInSubmenus(targetSubmenu) { const cleanAllSubmenus = !arguments.length; (0, _iterator.each)(this._submenus, ((_index, submenu) => { const $submenu = submenu._itemContainer(); const isOtherItem = !$submenu.is(null === targetSubmenu || void 0 === targetSubmenu ? void 0 : targetSubmenu._itemContainer()); const $selectedItem = $submenu.find(`.${this._selectedItemClass()}`); if (isOtherItem && $selectedItem.length || cleanAllSubmenus) { $selectedItem.removeClass(this._selectedItemClass()); const selectedItemData = this._getItemData($selectedItem); if (selectedItemData) { selectedItemData.selected = false } submenu._clearSelectedItems() } })) } _clearRootSelection() { const $prevSelectedItem = this.$element().find(".dx-menu-items-container").first().children().children().filter(`.${this._selectedItemClass()}`); if ($prevSelectedItem.length) { const prevSelectedItemData = this._getItemData($prevSelectedItem); prevSelectedItemData.selected = false; $prevSelectedItem.removeClass(this._selectedItemClass()) } } _nestedItemOnItemClickHandler(e) { var _this$_actions$onItem, _this$_actions3; null === (_this$_actions$onItem = (_this$_actions3 = this._actions).onItemClick) || void 0 === _this$_actions$onItem || _this$_actions$onItem.call(_this$_actions3, e) } _nestedItemOnItemRenderedHandler(e) { var _this$_actions$onItem2, _this$_actions4; null === (_this$_actions$onItem2 = (_this$_actions4 = this._actions).onItemRendered) || void 0 === _this$_actions$onItem2 || _this$_actions$onItem2.call(_this$_actions4, e) } _attachSubmenuHandlers($menuAnchorItem, submenu) { const $submenuOverlayContent = submenu.getOverlayContent(); const submenus = null === $submenuOverlayContent || void 0 === $submenuOverlayContent ? void 0 : $submenuOverlayContent.find(".dx-submenu"); const submenuMouseLeaveName = (0, _utils.addNamespace)(_hover.end, `${this.NAME}_submenu`); submenu.option({ onShowing: this._submenuOnShowingHandler.bind(this, $menuAnchorItem, submenu), onShown: this._submenuOnShownHandler.bind(this, $menuAnchorItem, submenu), onHiding: this._submenuOnHidingHandler.bind(this, $menuAnchorItem, submenu), onHidden: this._submenuOnHiddenHandler.bind(this, $menuAnchorItem, submenu) }); (0, _iterator.each)(submenus, ((_index, subMenu) => { _events_engine.default.off(subMenu, submenuMouseLeaveName); _events_engine.default.on(subMenu, submenuMouseLeaveName, null, this._submenuMouseLeaveHandler.bind(this, $menuAnchorItem)) })) } _submenuOnShowingHandler($menuAnchorItem, submenu, _ref) { var _this$_actions$onSubm3, _this$_actions5; let { rootItem: rootItem } = _ref; const $border = $menuAnchorItem.children(".dx-context-menu-container-border"); const params = this._getVisibilityChangeEventParams(rootItem, submenu, $menuAnchorItem); null === (_this$_actions$onSubm3 = (_this$_actions5 = this._actions).onSubmenuShowing) || void 0 === _this$_actions$onSubm3 || _this$_actions$onSubm3.call(_this$_actions5, params); $border.show(); $menuAnchorItem.addClass(DX_MENU_ITEM_EXPANDED_CLASS) } _submenuOnShownHandler($menuAnchorItem, submenu, _ref2) { var _this$_actions$onSubm4, _this$_actions6; let { rootItem: rootItem } = _ref2; const params = this._getVisibilityChangeEventParams(rootItem, submenu, $menuAnchorItem); null === (_this$_actions$onSubm4 = (_this$_actions6 = this._actions).onSubmenuShown) || void 0 === _this$_actions$onSubm4 || _this$_actions$onSubm4.call(_this$_actions6, params) } _submenuOnHidingHandler($menuAnchorItem, submenu, eventArgs) { var _this$_actions$onSubm5, _this$_actions7; const $border = $menuAnchorItem.children(".dx-context-menu-container-border"); const params = this._getVisibilityChangeEventParams(eventArgs.rootItem, submenu, $menuAnchorItem, true); eventArgs.itemData = params.itemData; eventArgs.rootItem = params.rootItem; eventArgs.submenuContainer = params.submenuContainer; eventArgs.submenu = params.submenu; null === (_this$_actions$onSubm5 = (_this$_actions7 = this._actions).onSubmenuHiding) || void 0 === _this$_actions$onSubm5 || _this$_actions$onSubm5.call(_this$_actions7, eventArgs); const { focusedElement: focusedElement } = this.option(); const { focusedElement: submenuFocusedElement } = submenu.option(); const isVisibleSubmenuHiding = this._visibleSubmenu === submenu; const isFocusedElementHiding = focusedElement === submenuFocusedElement; if (isVisibleSubmenuHiding && isFocusedElementHiding) { this.option("focusedElement", (0, _element.getPublicElement)($menuAnchorItem)) } if (!eventArgs.cancel) { if (isVisibleSubmenuHiding) { this._visibleSubmenu = null } $border.hide(); $menuAnchorItem.removeClass(DX_MENU_ITEM_EXPANDED_CLASS) } } _submenuOnHiddenHandler($menuAnchorItem, submenu, _ref3) { var _this$_actions$onSubm6, _this$_actions8; let { rootItem: rootItem } = _ref3; const params = this._getVisibilityChangeEventParams(rootItem, submenu, $menuAnchorItem, true); null === (_this$_actions$onSubm6 = (_this$_actions8 = this._actions).onSubmenuHidden) || void 0 === _this$_actions$onSubm6 || _this$_actions$onSubm6.call(_this$_actions8, params) } _getVisibilityChangeEventParams(submenuItem, submenu, $menuAnchorItem, isHide) { let itemData; let $submenuContainer; if (submenuItem) { const anchor = isHide ? (0, _renderer.default)(submenuItem).closest(`.${DX_MENU_ITEM_CLASS}`)[0] : submenuItem; itemData = this._getItemData(anchor); $submenuContainer = (0, _renderer.default)(anchor).find(".dx-submenu").first() } else { var _submenu$_overlay; const $overlayContent = (0, _renderer.default)(null === (_submenu$_overlay = submenu._overlay) || void 0 === _submenu$_overlay ? void 0 : _submenu$_overlay.content()); itemData = this._getItemData($menuAnchorItem); $submenuContainer = $overlayContent.find(".dx-submenu").first() } return { itemData: itemData, rootItem: (0, _element.getPublicElement)($menuAnchorItem), submenuContainer: (0, _element.getPublicElement)($submenuContainer), submenu: submenu } } _submenuMouseLeaveHandler($rootItem, eventArgs) { var _submenu$getOverlayCo; const target = (0, _renderer.default)(eventArgs.relatedTarget).parents(".dx-context-menu")[0]; const submenu = this._getSubmenuByRootElement($rootItem); const contextMenu = null === submenu || void 0 === submenu || null === (_submenu$getOverlayCo = submenu.getOverlayContent()) || void 0 === _submenu$getOverlayCo ? void 0 : _submenu$getOverlayCo[0]; const { hideSubmenuOnMouseLeave: hideSubmenuOnMouseLeave } = this.option(); if (hideSubmenuOnMouseLeave && target !== contextMenu) { this._clearTimeouts(); setTimeout(this._hideSubmenuAfterTimeout.bind(this), this._getDelay("hide")) } } _hideSubmenuAfterTimeout() { var _this$_visibleSubmenu, _this$_visibleSubmenu2; if (!this._visibleSubmenu) { return } const isRootItemHovered = (0, _renderer.default)(this._visibleSubmenu.$element().context).hasClass("dx-state-hover"); const isSubmenuItemHovered = null === (_this$_visibleSubmenu = this._visibleSubmenu.getOverlayContent()) || void 0 === _this$_visibleSubmenu ? void 0 : _this$_visibleSubmenu.find(".dx-state-hover").length; const hoveredElementFromSubMenu = null === (_this$_visibleSubmenu2 = this._visibleSubmenu.getOverlayContent()) || void 0 === _this$_visibleSubmenu2 ? void 0 : _this$_visibleSubmenu2.get(0).querySelector(":hover"); if (!hoveredElementFromSubMenu && !isSubmenuItemHovered && !isRootItemHovered) { this._visibleSubmenu.hide() } } _getSubmenuByRootElement($rootItem) { if (!$rootItem) { return } const $submenu = $rootItem.children(".dx-context-menu"); if (!$submenu.length) { return } return _submenu.default.getInstance($submenu) } getSubmenuPosition($rootItem) { const { submenuDirection: submenuDirectionOption, rtlEnabled: rtlEnabled } = this.option(); const isHorizontalMenu = this._isMenuHorizontal(); const submenuDirection = null === submenuDirectionOption || void 0 === submenuDirectionOption ? void 0 : submenuDirectionOption.toLowerCase(); const submenuPosition = { collision: "flip", of: $rootItem, precise: true }; switch (submenuDirection) { case "leftortop": submenuPosition.at = "left top"; submenuPosition.my = isHorizontalMenu ? "left bottom" : "right top"; break; case "rightorbottom": submenuPosition.at = isHorizontalMenu ? "left bottom" : "right top"; submenuPosition.my = "left top"; break; default: if (isHorizontalMenu) { submenuPosition.at = rtlEnabled ? "right bottom" : "left bottom"; submenuPosition.my = rtlEnabled ? "right top" : "left top" } else { submenuPosition.at = rtlEnabled ? "left top" : "right top"; submenuPosition.my = rtlEnabled ? "right top" : "left top" } } return submenuPosition } _renderBorderElement($item) { (0, _renderer.default)("<div>").appendTo($item).addClass("dx-context-menu-container-border").hide() } _itemPointerHandler(e) { const $target = (0, _renderer.default)(e.target); const $closestItem = $target.closest(this._itemElements()); if ($closestItem.hasClass("dx-menu-item-has-submenu")) { this.option("focusedElement", null); return } super._itemPointerHandler(e) } _hoverStartHandler(e) { const mouseMoveEventName = (0, _utils.addNamespace)(_pointer.default.move, this.NAME); const $item = this._getItemElementByEventArgs(e); if (!$item || this._isItemDisabled($item)) { return } const node = this._dataAdapter.getNodeByItem(this._getItemData($item)); const isSelectionActive = (0, _type.isDefined)(e.buttons) && 1 === e.buttons || !(0, _type.isDefined)(e.buttons) && 1 === e.which; _events_engine.default.off($item, mouseMoveEventName); if (!this._hasChildren(node)) { this._showSubmenuTimer = setTimeout(this._hideSubmenuAfterTimeout.bind(this), this._getDelay("hide")); return } if ("onHover" === this._getShowFirstSubmenuMode() && !isSelectionActive) { const submenu = this._getSubmenuByElement($item); this._clearTimeouts(); if (!(null !== submenu && void 0 !== submenu && submenu.isOverlayVisible())) { _events_engine.default.on($item, mouseMoveEventName, this._itemMouseMoveHandler.bind(this)); this._showSubmenuTimer = this._getDelay("hide") } } } _hoverEndHandler(eventArg) { const $item = this._getItemElementByEventArgs(eventArg); const relatedTarget = (0, _renderer.default)(eventArg.relatedTarget); super._hoverEndHandler(eventArg); this._clearTimeouts(); if (!$item || this._isItemDisabled($item)) { return } if (relatedTarget.hasClass("dx-context-menu-content-delimiter")) { return } const { hideSubmenuOnMouseLeave: hideSubmenuOnMouseLeave } = this.option(); if (hideSubmenuOnMouseLeave && !relatedTarget.hasClass("dx-menu-items-container")) { this._hideSubmenuTimer = setTimeout((() => { this._hideSubmenuAfterTimeout() }), this._getDelay("hide")) } } _hideVisibleSubmenu() { if (!this._visibleSubmenu) { return false } this._hideSubmenu(this._visibleSubmenu); return true } _showSubmenu($itemElement) { const submenu = this._getSubmenuByElement($itemElement); if (this._visibleSubmenu !== submenu) { this._hideVisibleSubmenu() } if (submenu) { this._clearTimeouts(); this.focus(); submenu.show(); const { focusedElement: focusedElement } = submenu.option(); this.option("focusedElement", focusedElement) } this._visibleSubmenu = submenu; this._hoveredRootItem = $itemElement } _hideSubmenu(submenu) { if (submenu) { submenu.hide() } if (this._visibleSubmenu === submenu) { this._visibleSubmenu = null } this._hoveredRootItem = null } _itemMouseMoveHandler(e) { var _e$pointers; if (null !== (_e$pointers = e.pointers) && void 0 !== _e$pointers && _e$pointers.length) { return } const $item = (0, _renderer.default)(e.currentTarget); if (!(0, _type.isDefined)(this._showSubmenuTimer)) { return } this._clearTimeouts(); this._showSubmenuTimer = setTimeout((() => { const submenu = this._getSubmenuByElement($item); if (submenu && !submenu.isOverlayVisible()) { this._showSubmenu($item) } }), this._getDelay("show")) } _clearTimeouts() { clearTimeout(this._hideSubmenuTimer); clearTimeout(this._showSubmenuTimer) } _getSubmenuByElement($itemElement, itemData) { const submenu = this._getSubmenuByRootElement($itemElement); if (submenu) { return submenu } const node = this._dataAdapter.getNodeByItem(itemData ?? this._getItemData($itemElement)); if (node && this._hasChildren(node)) { return this._renderSubmenuItems(node, $itemElement) } return } _updateSubmenuVisibilityOnClick(actionArgs) { var _actionArgs$args; const args = null === (_actionArgs$args = actionArgs.args) || void 0 === _actionArgs$args ? void 0 : _actionArgs$args[0]; if (!args || this._disabledGetter(args.itemData)) { return } const $itemElement = (0, _renderer.default)(args.itemElement); const currentSubmenu = this._getSubmenuByElement($itemElement, args.itemData); this._updateSelectedItemOnClick(actionArgs); if (this._visibleSubmenu) { if (this._visibleSubmenu === currentSubmenu) { const { showFirstSubmenuMode: showFirstSubmenuMode } = this.option(); if ("onClick" === showFirstSubmenuMode) { this._hideSubmenu(this._visibleSubmenu) } return } this._hideSubmenu(this._visibleSubmenu) } if (!currentSubmenu) { return } if (!currentSubmenu.isOverlayVisible()) { this._showSubmenu($itemElement) } } _optionChanged(args) { if (ACTIONS.includes(args.name)) { this._initActions(); return } switch (args.name) { case "orientation": case "submenuDirection": this._invalidate(); break; case "showFirstSubmenuMode": case "hideSubmenuOnMouseLeave": break; case "showSubmenuMode": this._changeSubmenusOption(args); break; case "adaptivityEnabled": if (args.value) { this._initAdaptivity() } else { this._removeAdaptivity() } break; case "width": if (this._isAdaptivityEnabled()) { var _this$_treeView3, _this$_overlay5; null === (_this$_treeView3 = this._treeView) || void 0 === _this$_treeView3 || _this$_treeView3.option(args.name, args.value); null === (_this$_overlay5 = this._overlay) || void 0 === _this$_overlay5 || _this$_overlay5.option(args.name, args.value) } super._optionChanged(args); this._dimensionChanged(); break; case "animation": if (this._isAdaptivityEnabled()) { var _this$_treeView4; null === (_this$_treeView4 = this._treeView) || void 0 === _this$_treeView4 || _this$_treeView4.option("animationEnabled", !!args.value) } super._optionChanged(args); break; default: if (this._isAdaptivityEnabled() && (args.name === args.fullName || "items" === args.name)) { var _this$_treeView5; null === (_this$_treeView5 = this._treeView) || void 0 === _this$_treeView5 || _this$_treeView5.option(args.fullName, args.value) } super._optionChanged(args) } } _changeSubmenusOption(_ref4) { let { name: name, value: value } = _ref4; (0, _iterator.each)(this._submenus, ((_index, submenu) => { submenu.option(name, value) })) } selectItem(itemElement) { this._hideSubmenu(this._visibleSubmenu); super.selectItem(itemElement) } unselectItem(itemElement) { this._hideSubmenu(this._visibleSubmenu); super.unselectItem(itemElement) } }(0, _component_registrator.default)("dxMenu", Menu); var _default = exports.default = Menu;