UNPKG

devextreme

Version:

HTML5 JavaScript Component Suite for Responsive Web Development

580 lines (575 loc) • 24.2 kB
/** * DevExtreme (cjs/ui/context_menu/ui.menu_base.js) * Version: 23.2.6 * Build date: Wed May 01 2024 * * Copyright (c) 2012 - 2024 Developer Express Inc. ALL RIGHTS RESERVED * Read about DevExtreme licensing here: https://js.devexpress.com/Licensing/ */ "use strict"; exports.default = void 0; var _renderer = _interopRequireDefault(require("../../core/renderer")); var _common = require("../../core/utils/common"); var _type = require("../../core/utils/type"); var _iterator = require("../../core/utils/iterator"); var _extend = require("../../core/utils/extend"); var _utils = require("../widget/utils.ink_ripple"); var _ui = _interopRequireDefault(require("../hierarchical_collection/ui.hierarchical_collection_widget")); var _uiMenu_baseEdit = _interopRequireDefault(require("./ui.menu_base.edit.strategy")); var _devices = _interopRequireDefault(require("../../core/devices")); var _item = _interopRequireDefault(require("../collection/item")); function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj } } function _inheritsLoose(subClass, superClass) { subClass.prototype = Object.create(superClass.prototype); subClass.prototype.constructor = subClass; _setPrototypeOf(subClass, superClass) } function _setPrototypeOf(o, p) { _setPrototypeOf = Object.setPrototypeOf ? Object.setPrototypeOf.bind() : function(o, p) { o.__proto__ = p; return o }; return _setPrototypeOf(o, p) } const DX_MENU_CLASS = "dx-menu"; const DX_MENU_NO_ICONS_CLASS = "dx-menu-no-icons"; const DX_MENU_BASE_CLASS = "dx-menu-base"; const ITEM_CLASS = "dx-menu-item"; const DX_ITEM_CONTENT_CLASS = ITEM_CLASS + "-content"; const DX_MENU_SELECTED_ITEM_CLASS = ITEM_CLASS + "-selected"; const DX_MENU_ITEM_WRAPPER_CLASS = ITEM_CLASS + "-wrapper"; const DX_MENU_ITEMS_CONTAINER_CLASS = "dx-menu-items-container"; const DX_MENU_ITEM_EXPANDED_CLASS = ITEM_CLASS + "-expanded"; const DX_MENU_SEPARATOR_CLASS = "dx-menu-separator"; const DX_MENU_ITEM_LAST_GROUP_ITEM = "dx-menu-last-group-item"; const DX_ITEM_HAS_TEXT = ITEM_CLASS + "-has-text"; const DX_ITEM_HAS_ICON = ITEM_CLASS + "-has-icon"; const DX_ITEM_HAS_SUBMENU = ITEM_CLASS + "-has-submenu"; const DX_MENU_ITEM_POPOUT_CLASS = ITEM_CLASS + "-popout"; const DX_MENU_ITEM_POPOUT_CONTAINER_CLASS = "dx-menu-item-popout-container"; const DX_MENU_ITEM_CAPTION_CLASS = ITEM_CLASS + "-text"; const SINGLE_SELECTION_MODE = "single"; const DEFAULT_DELAY = { show: 50, hide: 300 }; const DX_MENU_ITEM_CAPTION_URL_CLASS = "".concat("dx-menu-item-text", "-with-url"); const DX_ICON_WITH_URL_CLASS = "dx-icon-with-url"; const ITEM_URL_CLASS = "dx-item-url"; let MenuBase = function(_HierarchicalCollecti) { _inheritsLoose(MenuBase, _HierarchicalCollecti); function MenuBase() { return _HierarchicalCollecti.apply(this, arguments) || this } var _proto = MenuBase.prototype; _proto._getDefaultOptions = function() { return (0, _extend.extend)(_HierarchicalCollecti.prototype._getDefaultOptions.call(this), { items: [], cssClass: "", activeStateEnabled: true, showSubmenuMode: { name: "onHover", delay: { show: 50, hide: 300 } }, animation: { show: { type: "fade", from: 0, to: 1, duration: 100 }, hide: { type: "fade", from: 1, to: 0, duration: 100 } }, selectByClick: false, focusOnSelectedItem: false, keyExpr: null, _itemAttributes: { role: "menuitem" }, useInkRipple: false }) }; _proto._itemDataKey = function() { return "dxMenuItemDataKey" }; _proto._itemClass = function() { return ITEM_CLASS }; _proto._setAriaSelectionAttribute = function() {}; _proto._selectedItemClass = function() { return "dx-menu-item-selected" }; _proto._widgetClass = function() { return "dx-menu-base" }; _proto._focusTarget = function() { return this._itemContainer() }; _proto._clean = function() { this.option("focusedElement", null); _HierarchicalCollecti.prototype._clean.call(this) }; _proto._supportedKeys = function() { return (0, _extend.extend)(_HierarchicalCollecti.prototype._supportedKeys.call(this), { space: () => { const $item = (0, _renderer.default)(this.option("focusedElement")); if (!$item.length || !this._isSelectionEnabled()) { return } this.selectItem($item[0]) }, pageUp: _common.noop, pageDown: _common.noop }) }; _proto._isSelectionEnabled = function() { return "single" === this.option("selectionMode") }; _proto._init = function() { this._activeStateUnit = ".".concat(ITEM_CLASS); _HierarchicalCollecti.prototype._init.call(this); this._renderSelectedItem(); this._initActions() }; _proto._getLinkContainer = function(iconContainer, textContainer, _ref) { let { linkAttr: linkAttr, url: url } = _ref; null === iconContainer || void 0 === iconContainer ? void 0 : iconContainer.addClass("dx-icon-with-url"); null === textContainer || void 0 === textContainer ? void 0 : textContainer.addClass(DX_MENU_ITEM_CAPTION_URL_CLASS); return _HierarchicalCollecti.prototype._getLinkContainer.call(this, iconContainer, textContainer, { linkAttr: linkAttr, url: url }) }; _proto._addContent = function($container, itemData) { const { html: html, url: url } = itemData; if (url) { $container.html(html); const link = this._getLinkContainer(this._getIconContainer(itemData), this._getTextContainer(itemData), itemData); $container.append(link) } else { _HierarchicalCollecti.prototype._addContent.call(this, $container, itemData) } $container.append(this._getPopoutContainer(itemData)); this._addContentClasses(itemData, $container.parent()) }; _proto._getTextContainer = function(itemData) { const { text: text } = itemData; if (!text) { return } const $itemContainer = (0, _renderer.default)("<span>").addClass("dx-menu-item-text"); const itemText = (0, _type.isPlainObject)(itemData) ? text : String(itemData); return $itemContainer.text(itemText) }; _proto._getItemExtraPropNames = function() { return ["url", "linkAttr"] }; _proto._getPopoutContainer = function(itemData) { const items = itemData.items; let $popOutContainer; if (items && items.length) { const $popOutImage = (0, _renderer.default)("<div>").addClass("dx-menu-item-popout"); $popOutContainer = (0, _renderer.default)("<span>").addClass("dx-menu-item-popout-container").append($popOutImage) } return $popOutContainer }; _proto._getDataAdapterOptions = function() { return { rootValue: 0, multipleSelection: false, recursiveSelection: false, recursiveExpansion: false, searchValue: "" } }; _proto._selectByItem = function(selectedItem) { if (!selectedItem) { return } const nodeToSelect = this._dataAdapter.getNodeByItem(selectedItem); this._dataAdapter.toggleSelection(nodeToSelect.internalFields.key, true) }; _proto._renderSelectedItem = function() { const selectedKeys = this._dataAdapter.getSelectedNodesKeys(); const selectedKey = selectedKeys.length && selectedKeys[0]; const selectedItem = this.option("selectedItem"); if (!selectedKey) { this._selectByItem(selectedItem); return } const node = this._dataAdapter.getNodeByKey(selectedKey); if (false === node.selectable) { return } if (!selectedItem) { this.option("selectedItem", node.internalFields.item); return } if (selectedItem !== node.internalFields.item) { this._dataAdapter.toggleSelection(selectedKey, false); this._selectByItem(selectedItem) } }; _proto._initActions = function() {}; _proto._initMarkup = function() { _HierarchicalCollecti.prototype._initMarkup.call(this); this.option("useInkRipple") && this._renderInkRipple() }; _proto._renderInkRipple = function() { this._inkRipple = (0, _utils.render)() }; _proto._toggleActiveState = function($element, value, e) { _HierarchicalCollecti.prototype._toggleActiveState.apply(this, arguments); if (!this._inkRipple) { return } const config = { element: $element, event: e }; if (value) { this._inkRipple.showWave(config) } else { this._inkRipple.hideWave(config) } }; _proto._getShowSubmenuMode = function() { let optionValue = this.option("showSubmenuMode"); optionValue = (0, _type.isObject)(optionValue) ? optionValue.name : optionValue; return this._isDesktopDevice() ? optionValue : "onClick" }; _proto._initSelectedItems = function() {}; _proto._isDesktopDevice = function() { return "desktop" === _devices.default.real().deviceType }; _proto._initEditStrategy = function() { const Strategy = _uiMenu_baseEdit.default; this._editStrategy = new Strategy(this) }; _proto._addCustomCssClass = function($element) { $element.addClass(this.option("cssClass")) }; _proto._itemWrapperSelector = function() { return ".".concat("dx-menu-item-wrapper") }; _proto._hoverStartHandler = function(e) { const $itemElement = this._getItemElementByEventArgs(e); if (!$itemElement || this._isItemDisabled($itemElement)) { return } e.stopPropagation(); if ("onHover" === this._getShowSubmenuMode()) { clearTimeout(this._showSubmenusTimeout); this._showSubmenusTimeout = setTimeout(this._showSubmenu.bind(this, $itemElement), this._getSubmenuDelay("show")) } }; _proto._getAvailableItems = function($itemElements) { return _HierarchicalCollecti.prototype._getAvailableItems.call(this, $itemElements).filter((function() { return "hidden" !== (0, _renderer.default)(this).css("visibility") })) }; _proto._isItemDisabled = function($item) { return this._disabledGetter($item.data(this._itemDataKey())) }; _proto._showSubmenu = function($itemElement) { this._addExpandedClass($itemElement) }; _proto._addExpandedClass = function(itemElement) { (0, _renderer.default)(itemElement).addClass("dx-menu-item-expanded") }; _proto._getSubmenuDelay = function(action) { const { delay: delay } = this.option("showSubmenuMode"); if (!(0, _type.isDefined)(delay)) { return DEFAULT_DELAY[action] } return (0, _type.isObject)(delay) ? delay[action] : delay }; _proto._getItemElementByEventArgs = function(eventArgs) { let $target = (0, _renderer.default)(eventArgs.target); if ($target.hasClass(this._itemClass()) || $target.get(0) === eventArgs.currentTarget) { return $target } while (!$target.hasClass(this._itemClass())) { $target = $target.parent(); if ($target.hasClass("dx-submenu")) { return null } } return $target }; _proto._hoverEndHandler = function() { clearTimeout(this._showSubmenusTimeout) }; _proto._hasSubmenu = function(node) { return node && node.internalFields.childrenKeys.length }; _proto._renderContentImpl = function() { this._renderItems(this._dataAdapter.getRootNodes()) }; _proto._renderItems = function(nodes, submenuContainer) { if (nodes.length) { this.hasIcons = false; const $nodeContainer = this._renderContainer(this.$element(), submenuContainer); let firstVisibleIndex = -1; let nextGroupFirstIndex = -1; (0, _iterator.each)(nodes, (index, node) => { const isVisibleNode = false !== node.visible; if (isVisibleNode && firstVisibleIndex < 0) { firstVisibleIndex = index } const isBeginGroup = firstVisibleIndex < index && (node.beginGroup || index === nextGroupFirstIndex); if (isBeginGroup) { nextGroupFirstIndex = isVisibleNode ? index : index + 1 } if (index === nextGroupFirstIndex && firstVisibleIndex < index) { this._renderSeparator($nodeContainer) } this._renderItem(index, node, $nodeContainer) }); if (!this.hasIcons) { $nodeContainer.addClass("dx-menu-no-icons") } } }; _proto._renderContainer = function($wrapper) { const $container = (0, _renderer.default)("<ul>"); this.setAria("role", "none", $container); return $container.appendTo($wrapper).addClass("dx-menu-items-container") }; _proto._createDOMElement = function($nodeContainer) { const $node = (0, _renderer.default)("<li>"); this.setAria("role", "none", $node); return $node.appendTo($nodeContainer).addClass("dx-menu-item-wrapper") }; _proto._renderItem = function(index, node, $nodeContainer, $nodeElement) { const items = this.option("items"); const $node = $nodeElement || this._createDOMElement($nodeContainer); if (items[index + 1] && items[index + 1].beginGroup) { $node.addClass("dx-menu-last-group-item") } const $itemFrame = _HierarchicalCollecti.prototype._renderItem.call(this, index, node.internalFields.item, $node); if (node.internalFields.item === this.option("selectedItem")) { $itemFrame.addClass("dx-menu-item-selected") } $itemFrame.attr("tabIndex", -1); if (this._hasSubmenu(node)) { this.setAria("haspopup", "true", $itemFrame) } }; _proto._renderItemFrame = function(index, itemData, $itemContainer) { const $itemFrame = $itemContainer.children(".".concat(ITEM_CLASS)); return $itemFrame.length ? $itemFrame : _HierarchicalCollecti.prototype._renderItemFrame.apply(this, arguments) }; _proto._refreshItem = function($item, item) { const node = this._dataAdapter.getNodeByItem(item); const index = $item.data(this._itemIndexKey()); const $nodeContainer = $item.closest("ul"); const $nodeElement = $item.closest("li"); this._renderItem(index, node, $nodeContainer, $nodeElement) }; _proto._addContentClasses = function(itemData, $itemFrame) { const hasText = itemData.text ? !!itemData.text.length : false; const hasIcon = !!itemData.icon; const hasSubmenu = itemData.items ? !!itemData.items.length : false; $itemFrame.toggleClass(DX_ITEM_HAS_TEXT, hasText); $itemFrame.toggleClass(DX_ITEM_HAS_ICON, hasIcon); if (!this.hasIcons) { this.hasIcons = hasIcon } $itemFrame.toggleClass(DX_ITEM_HAS_SUBMENU, hasSubmenu) }; _proto._getItemContent = function($itemFrame) { let $itemContent = _HierarchicalCollecti.prototype._getItemContent.call(this, $itemFrame); if (!$itemContent.length) { $itemContent = $itemFrame.children(".".concat(DX_ITEM_CONTENT_CLASS)) } return $itemContent }; _proto._postprocessRenderItem = function(args) { const $itemElement = (0, _renderer.default)(args.itemElement); const selectedIndex = this._dataAdapter.getSelectedNodesKeys(); if (!selectedIndex.length || !this._selectedGetter(args.itemData) || !this._isItemSelectable(args.itemData)) { this._setAriaSelectionAttribute($itemElement, "false"); return } const node = this._dataAdapter.getNodeByItem(args.itemData); if (node.internalFields.key === selectedIndex[0]) { $itemElement.addClass(this._selectedItemClass()); this._setAriaSelectionAttribute($itemElement, "true") } else { this._setAriaSelectionAttribute($itemElement, "false") } }; _proto._isItemSelectable = function(item) { return false !== item.selectable }; _proto._renderSeparator = function($itemsContainer) { (0, _renderer.default)("<li>").appendTo($itemsContainer).addClass("dx-menu-separator") }; _proto._itemClickHandler = function(e) { if (e._skipHandling) { return } const itemClickActionHandler = this._createAction(this._updateSubmenuVisibilityOnClick.bind(this)); this._itemDXEventHandler(e, "onItemClick", {}, { beforeExecute: this._itemClick, afterExecute: itemClickActionHandler.bind(this) }); e._skipHandling = true }; _proto._itemClick = function(actionArgs) { const { event: event, itemData: itemData } = actionArgs.args[0]; const $itemElement = this._getItemElementByEventArgs(event); const link = $itemElement && $itemElement.find(".".concat("dx-item-url")).get(0); if (itemData.url && link) { link.click() } }; _proto._updateSubmenuVisibilityOnClick = function(actionArgs) { this._updateSelectedItemOnClick(actionArgs); if ("onClick" === this._getShowSubmenuMode()) { this._addExpandedClass(actionArgs.args[0].itemElement) } }; _proto._updateSelectedItemOnClick = function(actionArgs) { const args = actionArgs.args ? actionArgs.args[0] : actionArgs; if (!this._isItemSelectAllowed(args.itemData)) { return } const selectedItemKey = this._dataAdapter.getSelectedNodesKeys(); const selectedNode = selectedItemKey.length && this._dataAdapter.getNodeByKey(selectedItemKey[0]); if (selectedNode) { this._toggleItemSelection(selectedNode, false) } if (!selectedNode || selectedNode.internalFields.item !== args.itemData) { this.selectItem(args.itemData) } else { this._fireSelectionChangeEvent(null, this.option("selectedItem")); this._setOptionWithoutOptionChange("selectedItem", null) } }; _proto._isItemSelectAllowed = function(item) { const isSelectByClickEnabled = this._isSelectionEnabled() && this.option("selectByClick"); return !this._isContainerEmpty() && isSelectByClickEnabled && this._isItemSelectable(item) && !this._itemsGetter(item) }; _proto._isContainerEmpty = function() { return this._itemContainer().is(":empty") }; _proto._syncSelectionOptions = function() { return (0, _common.asyncNoop)() }; _proto._optionChanged = function(args) { switch (args.name) { case "showSubmenuMode": break; case "selectedItem": { const node = this._dataAdapter.getNodeByItem(args.value); const selectedKey = this._dataAdapter.getSelectedNodesKeys()[0]; if (node && node.internalFields.key !== selectedKey) { if (false === node.selectable) { break } if (selectedKey) { this._toggleItemSelection(this._dataAdapter.getNodeByKey(selectedKey), false) } this._toggleItemSelection(node, true); this._updateSelectedItems() } break } case "cssClass": case "position": case "selectByClick": case "animation": case "useInkRipple": this._invalidate(); break; default: _HierarchicalCollecti.prototype._optionChanged.call(this, args) } }; _proto._toggleItemSelection = function(node, value) { const itemElement = this._getElementByItem(node.internalFields.item); itemElement && (0, _renderer.default)(itemElement).toggleClass("dx-menu-item-selected"); this._dataAdapter.toggleSelection(node.internalFields.key, value) }; _proto._getElementByItem = function(itemData) { let result; (0, _iterator.each)(this._itemElements(), (_, itemElement) => { if ((0, _renderer.default)(itemElement).data(this._itemDataKey()) !== itemData) { return true } result = itemElement; return false }); return result }; _proto._updateSelectedItems = function(oldSelection, newSelection) { if (oldSelection || newSelection) { this._fireSelectionChangeEvent(newSelection, oldSelection) } }; _proto._fireSelectionChangeEvent = function(addedSelection, removedSelection) { this._createActionByOption("onSelectionChanged", { excludeValidators: ["disabled", "readOnly"] })({ addedItems: [addedSelection], removedItems: [removedSelection] }) }; _proto.selectItem = function(itemElement) { const itemData = itemElement.nodeType ? this._getItemData(itemElement) : itemElement; const selectedKey = this._dataAdapter.getSelectedNodesKeys()[0]; const selectedItem = this.option("selectedItem"); const node = this._dataAdapter.getNodeByItem(itemData); if (node.internalFields.key !== selectedKey) { if (selectedKey) { this._toggleItemSelection(this._dataAdapter.getNodeByKey(selectedKey), false) } this._toggleItemSelection(node, true); this._updateSelectedItems(selectedItem, itemData); this._setOptionWithoutOptionChange("selectedItem", itemData) } }; _proto.unselectItem = function(itemElement) { const itemData = itemElement.nodeType ? this._getItemData(itemElement) : itemElement; const node = this._dataAdapter.getNodeByItem(itemData); const selectedItem = this.option("selectedItem"); if (node.internalFields.selected) { this._toggleItemSelection(node, false); this._updateSelectedItems(selectedItem, null); this._setOptionWithoutOptionChange("selectedItem", null) } }; return MenuBase }(_ui.default); MenuBase.ItemClass = _item.default; var _default = MenuBase; exports.default = _default; module.exports = exports.default; module.exports.default = exports.default;