UNPKG

@openui5/sap.tnt

Version:

OpenUI5 UI Library sap.tnt

594 lines (506 loc) 16.2 kB
/*! * OpenUI5 * (c) Copyright 2026 SAP SE or an SAP affiliate company. * Licensed under the Apache License, Version 2.0 - see LICENSE.txt. */ sap.ui.define([ "./library", "sap/ui/core/Item", "sap/ui/core/Icon", "sap/ui/core/Lib", "sap/ui/events/KeyCodes", "sap/base/i18n/Localization" ], function (library, Item, Icon, Lib, KeyCodes, Localization) { "use strict"; const EXPAND_ICON_SRC = "sap-icon://navigation-right-arrow"; const COLLAPSE_ICON_SRC = "sap-icon://navigation-down-arrow"; const EXTERNAL_LINK_ICON = "sap-icon://arrow-right"; /** * Constructor for a new <code>NavigationListItemBase</code>. * * @param {string} [sId] ID for the new control, generated automatically if no ID is given * @param {object} [mSettings] Initial settings for the new control * * @class * The <code>NavigationListItemBase</code> class represents a base class for the items that are accepted by the <code>NavigationList</code> control. * @extends sap.ui.core.Item * * @author SAP SE * @version 1.146.0 * * @constructor * @public * @abstract * @since 1.121 * @alias sap.tnt.NavigationListItemBase */ const NavigationListItemBase = Item.extend("sap.tnt.NavigationListItemBase", /** @lends sap.tnt.NavigationListItemBase.prototype */ { metadata: { library: "sap.tnt", properties: { /** * Specifies if the item is expanded. * @since 1.121 */ expanded: { type: "boolean", group: "Misc", defaultValue: true }, /** * Specifies if the item is allowed to be expanded or collapsed by the user. */ hasExpander: { type: "boolean", group: "Misc", defaultValue: true }, /** * Specifies if the item should be shown. * * @since 1.121 */ visible: { type: "boolean", group: "Appearance", defaultValue: true } }, aggregations: { /** * The icon for the expanded items. * @since 1.121 */ _expandIconControl: { type: "sap.ui.core.Icon", multiple: false, visibility: "hidden" }, /** * The icon for external links. * @since 1.121 */ _externalLinkIconControl: { type: "sap.ui.core.Icon", multiple: false, visibility: "hidden" } }, events: { /** * Fired when an item is pressed. * @since 1.133 */ press: { allowPreventDefault: true, parameters: { /** * The pressed item. */ item: { type: "sap.ui.core.Item" }, /** * Indicates whether the CTRL key was pressed when the link was selected. * @since 1.137 */ ctrlKey: { type: "boolean" }, /** * Indicates whether the Shift key was pressed when the link was selected. * @since 1.137 */ shiftKey: { type: "boolean" }, /** * Indicates whether the Alt key was pressed when the link was selected. * @since 1.137 */ altKey: { type: "boolean" }, /** * Indicates whether the "meta" key was pressed when the link was selected. * * On Macintosh keyboards, this is the command key (⌘). * On Windows keyboards, this is the windows key (⊞). * * @since 1.137 */ metaKey: { type: "boolean" } } } } } }); NavigationListItemBase.prototype.init = function () { this._resourceBundleCore = Lib.getResourceBundleFor("sap.ui.core"); this._resourceBundleTnt = Lib.getResourceBundleFor("sap.tnt"); }; NavigationListItemBase.prototype.exit = function () { this._resourceBundleCore = null; this._resourceBundleTnt = null; }; /** * Gets the tree level of this item. * * @private * @returns {number} level */ NavigationListItemBase.prototype.getLevel = function () { const iBaseLevel = 0; const oParent = this.getParent(); if (oParent && oParent.isA("sap.tnt.NavigationListItem")) { return oParent.getLevel() + 1; } return iBaseLevel; }; /** * Gets the <code>NavigationList</code> control, which holds this item. * * @private * @returns {sap.tnt.NavigationList} control instance */ NavigationListItemBase.prototype.getNavigationList = function () { let oParent = this.getParent(); while (oParent && !oParent.isA("sap.tnt.NavigationList")) { oParent = oParent.getParent(); } return oParent; }; /** * Returns false if any of the parents up the chain of items has its property enabled set to false. * Otherwise returns true. * * @private * @returns {boolean} enabled */ NavigationListItemBase.prototype.getAllParentsEnabled = function () { let oParent = this.getParent(); while (oParent && !oParent.isA("sap.tnt.NavigationList")) { if (!oParent.getEnabled()) { return false; } oParent = oParent.getParent(); } return true; }; /** * Returns true if the parent <code>NavigationList</code> control is expanded. * * @private * @returns {boolean} expanded */ NavigationListItemBase.prototype._isListExpanded = function () { const oNavList = this.getNavigationList(); if (!oNavList) { return false; } return oNavList.getExpanded() || oNavList.hasStyleClass("sapTntNLPopup"); }; /** * If the item doesn't have a key, the function returns the ID of the <code>NavigationListItem</code>, * so the <code>NavigationList</code> can remember the selected item. * * @private * @returns {string} key */ NavigationListItemBase.prototype._getUniqueKey = function () { const sKey = this.getKey(); return sKey ? sKey : this.getId(); }; /** * Gets DOM references of the navigation items. * @abstract */ NavigationListItemBase.prototype._getFocusDomRefs = function () { }; /** * Returns the <code>sap.ui.core.Icon</code> control used to display the expand/collapse icon. * * @returns {sap.ui.core.Icon} Icon control instance * @private */ NavigationListItemBase.prototype._getExpandIconControl = function () { let oIcon = this.getAggregation("_expandIconControl"); if (!oIcon) { const bExpanded = this.getExpanded(); oIcon = new Icon({ src: bExpanded ? COLLAPSE_ICON_SRC : EXPAND_ICON_SRC, visible: !!this.getItems()?.length && this.getHasExpander(), useIconTooltip: false, tooltip: this._getExpandIconTooltip(!bExpanded) }).addStyleClass(`sapTntNLIExpandIcon ${this._getExpandIconStyleClass()}`); this.setAggregation("_expandIconControl", oIcon, true); } return oIcon; }; /** * Returns the <code>sap.ui.core.Icon</code> control used to display the external link icon. * * @returns {sap.ui.core.Icon} Icon control instance * @private */ NavigationListItemBase.prototype._getExternalIcon = function () { var oIcon = this.getAggregation("_externalLinkIconControl"); if (!oIcon) { oIcon = new Icon({ src: EXTERNAL_LINK_ICON }).addStyleClass(`sapTntNLIExternalLinkIcon`); this.setAggregation("_externalLinkIconControl", oIcon); } return oIcon; }; /** * Returns a custom style class for the _expandIconControl aggregation. * * @private * @returns {string} custom style class */ NavigationListItemBase.prototype._getExpandIconStyleClass = function () { return ""; }; /** * Gets the expand/collapse icon tooltip. * * @param {boolean} bExpanded whether the <code>NavigationListItemBase</code> is expanded * @private * @returns {string} sTooltip tooltip */ NavigationListItemBase.prototype._getExpandIconTooltip = function (bExpanded) { if (!this.getEnabled() || !this.getAllParentsEnabled()) { return ""; } const sKey = bExpanded ? "Icon.expand" : "Icon.collapse"; return this._resourceBundleCore.getText(sKey); }; /** * Returns the DOM Element that should get the focus. * * @return {Element} Returns the DOM Element that should get the focus * @protected */ NavigationListItemBase.prototype.getFocusDomRef = function () { const oFocusRef = this.getDomRef()?.querySelector("[tabindex]"); if (!oFocusRef) { return null; } return oFocusRef; }; /** * Handles key down event. * * @param {sap.ui.base.Event} oEvent keydown event * @private */ NavigationListItemBase.prototype.onkeydown = function (oEvent) { const bRtl = Localization.getRTL(); if (oEvent.key ? oEvent.key === " " : oEvent.keyCode === KeyCodes.SPACE) { oEvent.preventDefault(); } if (this._isInsidePopover()) { if ((oEvent.which == KeyCodes.ARROW_LEFT && !bRtl) || (oEvent.which == KeyCodes.ARROW_RIGHT && bRtl)) { this.getNavigationList().oParent.close(); // prevent ItemNavigation to move the focus to the next/previous item oEvent.stopPropagation(); } if ((oEvent.which == KeyCodes.ARROW_RIGHT && !bRtl) || (oEvent.which == KeyCodes.ARROW_LEFT && bRtl)) { // prevent ItemNavigation to move the focus to the next/previous item oEvent.stopPropagation(); } return; } if (!this._isListExpanded()) { if ((oEvent.which == KeyCodes.ARROW_RIGHT && !bRtl) || (oEvent.which == KeyCodes.ARROW_LEFT && bRtl)) { if (this.getItems().length > 0 ) { this.ontap(oEvent); } // prevent ItemNavigation to move the focus to the next/previous item oEvent.stopPropagation(); } if ((oEvent.which == KeyCodes.ARROW_LEFT && !bRtl) || (oEvent.which == KeyCodes.ARROW_RIGHT && bRtl)) { // prevent ItemNavigation to move the focus to the next/previous item oEvent.stopPropagation(); } return; } if (oEvent.isMarked("subItem")) { return; } if (oEvent.srcControl.getLevel() === 1) { oEvent.setMarked("subItem"); } if (this.getLevel() !== 0) { if (oEvent.which == KeyCodes.ARROW_RIGHT && !bRtl || oEvent.which == KeyCodes.ARROW_LEFT && bRtl || oEvent.which == KeyCodes.ARROW_LEFT && !bRtl || oEvent.which == KeyCodes.ARROW_RIGHT && bRtl) { // prevent ItemNavigation to move the focus to the next/previous item oEvent.stopPropagation(); } return; } // KeyCodes.MINUS is not returning 189 if ((oEvent.shiftKey && oEvent.which == 189) || oEvent.which == KeyCodes.NUMPAD_MINUS || (oEvent.which == KeyCodes.ARROW_RIGHT && bRtl) || (oEvent.which == KeyCodes.ARROW_LEFT && !bRtl)) { this.collapse(); oEvent.preventDefault(); // prevent ItemNavigation to move the focus to the next/previous item oEvent.stopPropagation(); } else if (oEvent.which == KeyCodes.NUMPAD_PLUS || (oEvent.shiftKey && oEvent.which == KeyCodes.PLUS) || oEvent.which == KeyCodes.ARROW_LEFT && bRtl || oEvent.which == KeyCodes.ARROW_RIGHT && !bRtl) { this.expand(); oEvent.preventDefault(); // prevent ItemNavigation to move the focus to the next/previous item oEvent.stopPropagation(); } }; /** * Handles ontap event. * * @param {sap.ui.base.Event} oEvent tap event * @private * @returns {boolean} whether the event was handled */ NavigationListItemBase.prototype.ontap = function (oEvent) { if (this.getEnabled() && !(oEvent.srcControl.isA("sap.ui.core.Icon")) && !this._isOverflow && !(!this.getNavigationList().getExpanded() && this.getItems().length)) { if (!this._firePress(oEvent, this)) { return true; } oEvent.stopPropagation(); } if (oEvent.isMarked("subItem")) { return true; } oEvent.setMarked("subItem"); if (!this.getEnabled() || !this.getAllParentsEnabled()) { oEvent.stopPropagation(); return true; } if (this._handleExpanderClick(oEvent)) { return true; } return false; }; /** * Handle the mouseover event * @param {jQuery.Event} oEvent The event object for the mouseover event in the callout. * @private */ NavigationListItemBase.prototype.onmouseover = function (oEvent) { const oTarget = oEvent.target, oSrcControl = oEvent.srcControl; if (!oTarget || (oSrcControl && !oSrcControl.isA("sap.tnt.NavigationListItemBase"))) { return; } oEvent.stopPropagation(); const oTooltipElement = this._getTooltipElement(); if (!oTooltipElement) { return; } const oTextElement = oTooltipElement.querySelector(".sapMText") || oTooltipElement.querySelector(".sapTntNLGroupText"); if (oTextElement.offsetWidth >= oTextElement.scrollWidth) { return; } let sText = oSrcControl?.getText(); const sTooltip = oSrcControl.getTooltip_AsString(); if (sTooltip) { sText += " - " + sTooltip; } oTooltipElement.setAttribute("title", sText); }; NavigationListItemBase.prototype._getTooltipElement = function () { return this.getDomRef().querySelector("[role='treeitem']"); }; /** * Handle the onmouseout event * @param {jQuery.Event} oEvent The event object for the onmouseout event in the callout. * @private */ NavigationListItemBase.prototype.onmouseout = function (oEvent) { const oTarget = oEvent.target, oSrcControl = oEvent.srcControl; if (!oTarget || oSrcControl && !oSrcControl.isA("sap.tnt.NavigationListItemBase")) { return; } oEvent.stopPropagation(); const oTooltipElement = this._getTooltipElement(); const sTooltip = oSrcControl?.getTooltip_AsString(); if (oTooltipElement) { if (sTooltip) { oTooltipElement.setAttribute("title", sTooltip); } else { oTooltipElement.removeAttribute("title"); } } }; /** * Fires a press event on an item. * @param {sap.ui.base.Event} oEvent press event * @param {sap.tnt.NavigationListMenuItem|sap.tnt.NavigationListItem} oItem The item that triggered the event * @returns {boolean} whether the event was successfully fired * @private */ NavigationListItemBase.prototype._firePress = function(oEvent, oItem) { const oNavList = this.getNavigationList(); const oParams = oEvent.getParameters ? oEvent.getParameters() : { item: oItem, ctrlKey: !!oEvent.ctrlKey, shiftKey: !!oEvent.shiftKey, altKey: !!oEvent.altKey, metaKey: !!oEvent.metaKey }; if (!this.getEnabled()) { return false; } if (!this.firePress(oParams)) { oEvent.preventDefault(); return false; } if (!oNavList?.fireItemPress(oParams)) { oEvent.preventDefault(); return false; } return true; }; /** * Handles the logic for expanding/collapsing the child items. * * @param {sap.ui.base.Event} oEvent tap event * @private * @returns {boolean} whether the event was handled */ NavigationListItemBase.prototype._handleExpanderClick = function (oEvent) { const sClickTargetClassName = this._getExpanderActivationTarget(), oClickedRef = oEvent.target.closest(sClickTargetClassName); if (!this._isListExpanded() || this.getLevel() !== 0 || !oClickedRef) { return false; } if ((oEvent.key ? oEvent.key === "Enter" : oEvent.keyCode === KeyCodes.ENTER) || (oEvent.key ? oEvent.key === " " : oEvent.keyCode === KeyCodes.SPACE)) { return false; } if (this.getExpanded()) { this.collapse(); } else { this.expand(); } return true; }; /** * Returns the root CSS selector of the element that will handle the expanding/collapsing of the child items. * * @private * @returns {string} CSS selector of the target */ NavigationListItemBase.prototype._getExpanderActivationTarget = function () { if (!this.getSelectable() && !(this.getHref() && this.getTarget() === "_blank")) { return ".sapTntNLIFirstLevel"; } return ".sapTntNLIExpandIcon"; }; /** * Expands the child items (works only on first-level items). * @returns {boolean} whether the items will be expanded */ NavigationListItemBase.prototype.expand = function () { if (!this.getEnabled() || this.getExpanded() || !this.getHasExpander() || this.getItems().length == 0 || this.getLevel() !== 0) { return false; } this.setProperty("expanded", true); this._animateExpand = true; return true; }; /** * Collapses the child items (works only on first-level items). * * @returns {boolean} whether the items will be collapsed */ NavigationListItemBase.prototype.collapse = function () { if (!this.getEnabled() || !this.getExpanded() || !this.getHasExpander() || this.getItems().length == 0 || this.getLevel() !== 0) { return false; } this.setProperty("expanded", false); this._animateCollapse = true; return true; }; NavigationListItemBase.prototype._isInsidePopover = function () { return !!this.getNavigationList()?.hasStyleClass("sapTntNLPopup"); }; return NavigationListItemBase; });