UNPKG

@openui5/sap.m

Version:

OpenUI5 UI Library sap.m

1,475 lines (1,346 loc) 70.4 kB
/*! * UI development toolkit for HTML5 (OpenUI5) * (c) Copyright 2009-2022 SAP SE or an SAP affiliate company. * Licensed under the Apache License, Version 2.0 - see LICENSE.txt. */ // Provides control sap.m.ViewSettingsPopover. sap.ui.define([ "./ResponsivePopover", "./Button", "./Toolbar", "./ToolbarSpacer", "./Bar", "./List", "./StandardListItem", "./library", "sap/ui/core/Control", "sap/ui/core/IconPool", "./SegmentedButton", "./Page", "./NavContainer", "./ViewSettingsItem", "sap/ui/base/ManagedObject", "sap/ui/Device", "sap/ui/core/InvisibleText", "./ViewSettingsPopoverRenderer", "sap/base/Log" ], function( ResponsivePopover, Button, Toolbar, ToolbarSpacer, Bar, List, StandardListItem, library, Control, IconPool, SegmentedButton, Page, NavContainer, ViewSettingsItem, ManagedObject, Device, InvisibleText, ViewSettingsPopoverRenderer, Log ) { "use strict"; // shortcut for sap.m.VerticalPlacementType var VerticalPlacementType = library.VerticalPlacementType; // shortcut for sap.m.ListType var ListType = library.ListType; // shortcut for sap.m.ListMode var ListMode = library.ListMode; var TOOLBAR_SUFFIX = '-toolbar'; var SEGMENTED_BUTTON_SUFFIX = '-segmented'; var LIST_ITEMS_SUFFIX = '-listitem'; var LIST_ITEMS_SUFFIX_GROUP = '-group'; var LIST_ITEMS_SUFFIX_FILTER = '-filter'; var LIST_ITEMS_SUFFIX_SORT = '-sort'; var FILTERDETAIL_LIST_ITEMS_SUFFIX = '-filterdetailItem'; var NAV_CONTAINER_SUFFIX = '-navContainer'; var MAIN_PAGE_SUFFIX = '-mainPage'; var DETAILS_PAGE_SUFFIX = '-detailspage'; var BACK_BUTTON_SUFFIX = '-backbutton'; var TITLE_SUFFIX = '-title'; var SEARCH_FIELD_SUFFIX = '-searchfield'; var SELECT_ALL_SUFFIX = '-selectall'; var CUSTOM_TAB_SUFFIX = '-custom-button'; /** * Constructor for a new <code>ViewSettingsPopover</code>. * * @param {string} [sId] ID for the new control, generated automatically if no ` is given * @param {Object} [mSettings] Initial settings for the new control * * @class * A <code>ViewSettingsPopover</code> is a Popover containing a summarized list with messages. * @extends sap.ui.core.Control * * @author SAP SE * @version 1.60.39 * * @constructor * @private * @since 1.38 * @alias sap.m.ViewSettingsPopover * @ui5-metamodel This control also will be described in the legacy UI5 design-time metamodel */ var ViewSettingsPopover = Control.extend("sap.m.ViewSettingsPopover", /** @lends sap.m.ViewSettingsPopover.prototype */ { metadata: { library: "sap.m", aggregations: { /** * Holds public collection of sort items. */ sortItems: {type: "sap.ui.core.Item", multiple: true, singularName: "sortItem"}, /** * Holds public collection of filter items. */ filterItems: {type: "sap.ui.core.Item", multiple: true, singularName: "filterItem"}, /** * Holds public collection of filter detail items. */ filterDetailItems: {type: "sap.ui.core.Item", multiple: true, singularName: "filterDetailItem"}, /** * Holds public collection of group items. */ groupItems: {type: "sap.ui.core.Item", multiple: true, singularName: "groupItem"}, /** * The list of all the custom tabs. */ customTabs: {type: "sap.m.ViewSettingsCustomTab", multiple: true, singularName: "customTab", bindable : "bindable"} }, associations : { /** * Association to controls / IDs which label this control (see WAI-ARIA attribute aria-labelledby). */ ariaLabelledBy: {type: "sap.ui.core.Control", multiple: true, singularName: "ariaLabelledBy"} }, events: { /** * Fired after the popover is opened. */ afterOpen: { parameters: { /** * This Refers to the control that opens the popover */ openBy: {type: "sap.ui.core.Control"} } }, /** * Fired after the popover is closed. */ afterClose: { parameters: { /** * Refers to the control that opens the popover */ openBy: {type: "sap.ui.core.Control"} } }, /** * Fired when the popover is opened */ beforeOpen: { parameters: { /** * Refers to the control that opens the popover */ openBy: {type: "sap.ui.core.Control"} } }, /** * Fired when the popover is closed */ beforeClose: { parameters: { /** * Refers to the control that opens the popover */ openBy: {type: "sap.ui.core.Control"} } }, /** * Fired when sort filters are selected. */ sortSelected: { allowPreventDefault: true, parameters: { /** * The item to be closed. */ items: {type: "array"} } }, /** * Fired when filter filters are selected. */ filterSelected: { allowPreventDefault: true, parameters: { /** * The item to be closed. */ items: {type: "array"} } }, /** * Fired when group filters are selected. */ groupSelected: { allowPreventDefault: true, parameters: { /** * The item to be closed. */ items: {type: "array"} } }, /** * Fired when the filter detail page is opened. */ afterFilterDetailPageOpened: { parameters: { /** * The filter item for which the details are opened. */ parentFilterItem: {type: "sap.m.ViewSettingsFilterItem"} } } } }, constructor : function (vId, mSettings) { this._stashedItems = {}; // normalize the expected arguments if (!mSettings && vId && typeof vId === 'object') { mSettings = vId; } // remove all items before creating the whole aggregation hierarchy and add them afterwards this._stashItems(mSettings); if (mSettings && Array.isArray(mSettings['sortItems'])) { mSettings['sortItems'] = null; } if (mSettings && Array.isArray(mSettings['filterItems'])) { mSettings['filterItems'] = null; } if (mSettings && Array.isArray(mSettings['groupItems'])) { mSettings['groupItems'] = null; } ManagedObject.prototype.constructor.apply(this, arguments); this._getPopover().addContent(this._getNavContainer()); // add the items this._addStashedItems(); } }); /** * Initialization method for creating some base internal properties. * @public */ ViewSettingsPopover.prototype.init = function () { /* * The following internal properties are assigned upon instantiating the control /triggered in the constructor/. * this._currentPageId; // ID of current open page if in opened state this._initialHeight; // Remember height of the toolbar without content this._oPreviousSelectedFilters; // Object storing ids of selected filter detail items this._lastViewedFilterParent; // Last standard list item instance for which detail page was opened. this._sortList; // Internal list instance for rendering sort items this._filterList; // For filter this._filterDetailList; // For filter detail this._groupList; // For group this._mainPage; // Internal page instance for sort/filter/group pages content this._detailsPage; // Internal page instance for filter detail content this._navContainer; // Internal instance for managing and rendering main and detail pages this._toolbar; // Internal toolbar instance for toolbar tabs and close button this._title; // Internal instance storing the current title text for the opened page this._popover; // Internal popover instance for rendering this._segmentedButton // Internal segmented button instance for toolbar tabs this._filterSearchField // Internal search input field instance this._removeSortingItem // Standard list item for removing sorting this._removeGroupingItem // Standard list item for removing grouping this._removeFilteringItem // Standard list item for removing filtering */ /** * Internal map object, each property is id of a "button ID/page content ID" in the popover. * @type {{sort: string, filter: string, filterDetail: string, group: string}} * @private */ this._tabMap = { sort : 'sort', filter : 'filter', filterDetail : 'filterDetail', group : 'group' }; }; /** * Opens the popover. * @param {Object} oControl Instance of the control that triggered the opening * @param {sap.ui.core.CSSSize} sPopoverWidth Width of the popover. */ ViewSettingsPopover.prototype.openBy = function (oControl, sPopoverWidth) { var oPopover = this._getPopover(oControl), sPageToOpen = this._determinePageToOpen(); oPopover.openBy(oControl); if (sPageToOpen) { if (Device.system.phone) { this._showContentFor(sPageToOpen); } else { // no tab pressed by default this._removeSegmentedButtonSelection(); // _adjustInitialWidth() calculates the width of the popover based on the first segmented button // if the first segmented button is not visible then this results in an error, hence the below workaround if (sPopoverWidth) { this._getPopover().setContentWidth(sPopoverWidth); } else { this._adjustInitialWidth(); } } } this._initialHeight = this._getPopover().getContentHeight(); // if only one tab is present, directly show it's content if (this._getSegmentedButton().getItems() && this._getSegmentedButton().getItems().length === 1 && sPageToOpen) { this._showContentFor(sPageToOpen); } if (oPopover.getAriaLabelledBy() && oPopover.getAriaLabelledBy().indexOf(this._getPopoverAriaLabel()) === -1) { oPopover.addAriaLabelledBy(this._getPopoverAriaLabel()); } }; /** * Removes default selected item of <code>SegmentedButton</code>. */ ViewSettingsPopover.prototype._removeSegmentedButtonSelection = function () { this._getSegmentedButton().setProperty('selectedKey', '', true).removeAllAssociation('selectedButton', true); // by default the SegmentedButton sets the first button as selected if the association is set to false // the only way to not have a selected button is to give the association invalid value this._getSegmentedButton().setAssociation("selectedButton", "no_selected_button", true); this._getSegmentedButton().getButtons().forEach(function (oButton) { oButton.$().removeClass("sapMSegBBtnSel").attr("aria-checked", false); }); }; /** * Toggles between open and closed state of the <code>ViewSettingsPopover</code> instance. * oControl parameter is mandatory in the same way as in <code>openBy</code> method. * oControl parameter is mandatory in the same way as in 'openBy' method * * @param {sap.ui.core.Control} oControl Control which opens the <code>ViewSettingsPopover</code> * @returns {sap.m.ViewSettingsPopover} Reference to the 'this' for chaining purposes * @public */ ViewSettingsPopover.prototype.toggle = function (oControl) { if (this.isOpen()) { this.close(); } else { this.openBy(oControl); } return this; }; /** * The method checks if the <code>ViewSettingsPopover</code> is open. It returns true when the <code>ViewSettingsPopover</code> is currently open * (this includes opening and closing animations), otherwise it returns false * * @public * @returns {boolean} Whether that <code>ViewSettingsPopover</code> is open */ ViewSettingsPopover.prototype.isOpen = function () { return this._getPopover().isOpen(); }; /** * Closes the <code>ViewSettingsPopover</code>. * * @returns {sap.m.ViewSettingsPopover} Reference to the 'this' for chaining purposes * @public */ ViewSettingsPopover.prototype.close = function () { this._getPopover().close(); this._cleanAfterClose(); return this; }; /** * Determines the page ID of the right page to open by default. * @returns {string} sPageId ID of the right page to be opened * @private */ ViewSettingsPopover.prototype._determinePageToOpen = function () { var i, j, sProperty, sType, aItems, aSegmentedButtonItems, oCustomTab, sCustomTabButtonId, oCustomTabs = this.getCustomTabs(); // check for page to open among the predefined tabs for (sProperty in this._tabMap) { sType = this._tabMap[sProperty]; sType = sType.slice(0,1).toUpperCase() + sType.slice(1); aItems = this['_get' + sType + 'List']().getItems(); if (aItems.length === 1) { // if we have only one item, don't open page, it will be selected by default return; } else if (aItems.length > 1) { return this._tabMap[sProperty]; } } // if there are custom tabs check for page to open if (oCustomTabs) { aSegmentedButtonItems = this._getSegmentedButton().getItems(); for (i = 0; i < oCustomTabs.length; i++) { oCustomTab = oCustomTabs[i]; sCustomTabButtonId = this.getId() + oCustomTab.getId() + CUSTOM_TAB_SUFFIX; if (!this._isEmptyCustomTab(oCustomTab)) { for (j = 0; j < aSegmentedButtonItems.length; j++) { if (sCustomTabButtonId === aSegmentedButtonItems[j].getId()) { return oCustomTab.getId(); } } } } } // if no page is found open default empty page return this._tabMap['sort']; }; /** * Removes the internal popover footer. */ ViewSettingsPopover.prototype._removeFooter = function () { // hide any footer buttons from detail page if (this._getPopover()._oFooter) { this._getPopover()._oFooter.destroy(); this._getPopover()._oFooter = null; } this._getPopover().destroyAggregation('beginButton'); this._getPopover().destroyAggregation('endButton'); }; /** * Manage internal aggregations so that the correct contents are being set for rendering. * @param {string} sPageId ID of the page for which to show content * @param {Object} oParentItem of a parent item (e.g. filter details page parent) * @param {boolean} bDisableSlideEffect Flag enabling or disabling the slide animation on pages navigation * @private */ ViewSettingsPopover.prototype._showContentFor = function (sPageId, oParentItem, bDisableSlideEffect) { var oPopoverAriaLabelledBy = sap.ui.getCore().byId(this._getPopoverAriaLabel()), sAriaText; this._getPopover().setContentHeight('300px'); this._getPopover().setContentWidth('300px'); // remove any current contents from the page this._removePageContents(sPageId); // add new content to the page to show this._addPageContents(sPageId); if (sPageId === this._tabMap['filterDetail']) { sAriaText = this._getText('VIEWSETTINGS_TITLE_FILTERBY') + this._updateTitleText(oParentItem.getTitle(), true); this._goToDetailsPage(oParentItem, bDisableSlideEffect); } else { if (sPageId in this._tabMap) { sAriaText = this._updateTitleText(sPageId); if (sPageId === this._tabMap['filter']) { this._updateFilterListItemsCount(); } } this._goToMainPage(); } oPopoverAriaLabelledBy.setText(sAriaText); this._getSegmentedButton().setSelectedKey(sPageId); // make sure segmented button is always in sync this._currentPageId = sPageId; }; /** * Updates the text of the title aggregation. * @param {string} sText String to be shown as new title * @param {boolean} bSkipTranslate Whether to translate a key ot displayed a string directly * @returns {string} the computed title text * @private */ ViewSettingsPopover.prototype._updateTitleText = function (sText, bSkipTranslate) { var sStringKey, sString = sText; if (!bSkipTranslate) { sStringKey = sText; if (sStringKey == 'filterDetail') { sStringKey = 'filter'; } sStringKey = "VIEWSETTINGS_TITLE_" + sStringKey.toUpperCase(); sString = this._getText(sStringKey); } if (bSkipTranslate && this._getDetailsPage().getHeaderContent()[0].getContentMiddle()) { // filter detail page title is a bit more special this._getDetailsPage().getHeaderContent()[0].getContentMiddle()[0].setText(sString); } else { this._getTitle().setText(sString); } return sString; }; /** * Goes to the details page. * @param {Object} oParentItem The parent item * @param {boolean} bDisableSlideEffect Flag enabling or disabling the slide animation on pages navigation * @private */ ViewSettingsPopover.prototype._goToDetailsPage = function (oParentItem, bDisableSlideEffect) { var bMultiSelectMode = this._findViewSettingsItemFromListItem(oParentItem).getMultiSelect(); if (bMultiSelectMode) { // add toolbar with 'search' field and 'show selected only' button this._getSearchField().setValue(''); this._getDetailsPage().insertAggregation('content', new Toolbar({ content: [ this._getSearchField().addStyleClass('sapMVSDFilterSearchField'), this._getShowSelectedOnlyButton() ] }), 0); // add 'select all' checkbox this._getFilterDetailList().setHeaderToolbar(new Toolbar({ content: [ this._getSelectAllCheckbox(this._findViewSettingsItemFromListItem(oParentItem).getItems(), this._getFilterDetailList()) ] }).addStyleClass('sapMVSDFilterHeaderToolbar')); } else { this._getFilterDetailList().removeAllAggregation('headerToolbar'); } this._updateFilterDetailListFor(oParentItem); this._navigateToPage('Details', bDisableSlideEffect); this._addFooterButtons(); this._updateSelectAllCheckBoxState(); if (Device.system.phone) { // hide the header on filter detail page this._hideToolbarButtons(); } this._lastViewedFilterParent = oParentItem; this._oPreviousSelectedFilters = { selectedItemIds: this._getFilterDetailList().getSelectedItems().map(function (oItem) { return oItem.getId(); }) }; this.fireAfterFilterDetailPageOpened({parentFilterItem : oParentItem}); }; /** * Returns reference to the button for filtering selected items. * @returns {Object} Reference to <code>sap.m.Button</code> * @private */ ViewSettingsPopover.prototype._getShowSelectedOnlyButton = function () { var bShowSelectedOnly = false; if (!this._oShowSelectedOnlyButton) { this._oShowSelectedOnlyButton = new Button({ icon : IconPool.getIconURI("multiselect-all"), tooltip: this._getText('SHOW_SELECTED_ONLY'), press: function (oEvent) { bShowSelectedOnly = !bShowSelectedOnly; if (bShowSelectedOnly) { oEvent.getSource().$("inner").addClass('sapMBtnActive'); } this._getFilterDetailList().getItems().forEach(function (oItem) { if (bShowSelectedOnly) { if (!oItem.getSelected()) { oItem.setVisible(false); } } else if (!bShowSelectedOnly) { this._filterItemsBy(this._getSearchField().getValue()); } }, this); this._updateSelectAllCheckBoxState(); }.bind(this) }); } return this._oShowSelectedOnlyButton; }; /** * Updates the state of the select all checkbox after selecting a single item or after filtering items. * * @private */ ViewSettingsPopover.prototype._updateSelectAllCheckBoxState = function() { var oSelectAllCheckBox = sap.ui.getCore().byId(this.getId() + SELECT_ALL_SUFFIX), aItems = this._getFilterDetailList().getItems() || [], bAllSelected = true, iVisibleItems = 0, i; for (i = 0; i < aItems.length; i++) { if (aItems[i].getVisible()) { iVisibleItems++; if (!aItems[i].getSelected()) { bAllSelected = false; } } } if (oSelectAllCheckBox) { oSelectAllCheckBox.setSelected(bAllSelected && iVisibleItems > 0); } }; /** * Adds footer buttons. * @private */ ViewSettingsPopover.prototype._addFooterButtons = function () { var oButtonOk = new Button({ text: this._getText("VIEWSETTINGS_ACCEPT"), press: this._confirmFilterDetail.bind(this) }), oButtonCancel = new Button({ text: this._getText("VIEWSETTINGS_CANCEL"), press: this._cancel.bind(this) }); this._getPopover().setBeginButton(oButtonOk); this._getPopover().setEndButton(oButtonCancel); }; /** * Handles selected items confirmation. * @private */ ViewSettingsPopover.prototype._confirmFilterDetail = function () { var oSelectedListItems = this._getFilterDetailList().getItems().filter(function (oItem) { return oItem.getSelected(); }); this.fireFilterSelected({ items: oSelectedListItems.map(function (oListItem) { return this._findViewSettingsItemFromListItem(oListItem); }.bind(this)) }); this.close(); }; /** * Handles the cancellation of selected items. * @private */ ViewSettingsPopover.prototype._cancel = function () { this._restorePreviousState(); this._updateFilterListItemsCount(); this.close(); }; /** * Restores the state of the items. * @private */ ViewSettingsPopover.prototype._restorePreviousState = function () { var fnRestorePreviousState; if (this._oPreviousSelectedFilters) { // select again those that were initially selected fnRestorePreviousState = function (aPrevStateItems, oItem, oVSPItem) { var i; for (i = 0; i < aPrevStateItems.length; i++) { if (oItem.getId() === aPrevStateItems[i]) { oVSPItem.setProperty('selected', true, true); break; } } }; this._getFilterDetailList().getItems().forEach(function (oItem) { // reset all to false var oVSPItem = this._findViewSettingsItemFromListItem(oItem); oVSPItem.setProperty('selected', false, true); fnRestorePreviousState(this._oPreviousSelectedFilters.selectedItemIds, oItem, oVSPItem); }, this); this._updateSelectAllCheckBoxState(); } }; /** * Hildes the toolbar buttons. * @private */ ViewSettingsPopover.prototype._hideToolbarButtons = function () { this._getPopover().setShowHeader(false); setTimeout(function () { if (this._getPopover().getAggregation('_popup')._internalHeader) { this._getPopover().getAggregation('_popup')._internalHeader.$().hide(); } }.bind(this), 0); }; /** * Goes to the main page. * @private */ ViewSettingsPopover.prototype._goToMainPage = function () { // show main page this._getPopover().setShowHeader(true); this._getPopover().setCustomHeader(this._getToolbar()); this._oPreviousSelectedFilters = null; this._navigateToPage('Main'); }; /** * Adjusts the initial toolbar width. * @private */ ViewSettingsPopover.prototype._adjustInitialWidth = function () { var iButtonWidth, iButtonMargin, iButtonsLen, iNewWidth, oSegmentedButton = this._getSegmentedButton(), aSegmentedButtonAggregations = oSegmentedButton && oSegmentedButton.getButtons(); if (!aSegmentedButtonAggregations || !aSegmentedButtonAggregations[0]) { return; } iButtonWidth = aSegmentedButtonAggregations[0].$().width(); iButtonMargin = parseInt(aSegmentedButtonAggregations[0].$().css('margin-right'), 10); iButtonsLen = aSegmentedButtonAggregations.length; if (library._bSizeCompact || !!document.querySelector('.sapUiSizeCompact')) { iButtonWidth = iButtonWidth * 2; } iNewWidth = (iButtonWidth + iButtonMargin) * (iButtonsLen + 1.6); // make more room for close button this._getPopover().setContentWidth(iNewWidth + "px"); }; /** * Triggers the sliding effect of nav container to display certain page. * @param {string} sPageName Name of the page to be shown * @param {boolean} bDisableSlideEffect Flag enabling or disabling sliding animation on page navigation * @private */ ViewSettingsPopover.prototype._navigateToPage = function (sPageName, bDisableSlideEffect) { var oBackButton; // navigate to details page if (this._getNavContainer().getCurrentPage().getId() !== this['_get' + sPageName + 'PageId']()) { if (sPageName === 'Details') { if (bDisableSlideEffect) { this._getNavContainer().to(this['_get' + sPageName + 'Page'](), 'show'); oBackButton = sap.ui.getCore().byId(this.getId() + BACK_BUTTON_SUFFIX); oBackButton && oBackButton.destroy(); oBackButton = null; } else { setTimeout(this._getNavContainer()["to"].bind(this._getNavContainer(), this['_get' + sPageName + 'Page'](), "slide"), 0); } } else { setTimeout(this._getNavContainer()['back'].bind(this._getNavContainer()), 0); } } this._getNavContainer().attachEventOnce("afterNavigate", function() { if (this._currentPageId !== this._tabMap['filterDetail']) { this._removeFooter(); if (Device.system.desktop && this._lastViewedFilterParent && this._lastViewedFilterParent.getFocusDomRef()) { // focus filter item this._lastViewedFilterParent.getFocusDomRef().focus(); } } else { // focus first item on filter detail page if (Device.system.desktop && this._getFilterDetailList().getItems()[0] && this._getFilterDetailList().getItems()[0].getFocusDomRef()) { this._getFilterDetailList().getItems()[0].getFocusDomRef().focus(); } } }.bind(this)); }; /** * Updates sub selected items count on filter items. * @private */ ViewSettingsPopover.prototype._updateFilterListItemsCount = function () { var iFilterCount, oVSPItem, aListItems = this._getFilterList().getItems(); aListItems.forEach(function (oListItem) { if (oListItem.getId().indexOf('nofiltering') === -1) { oVSPItem = this._findViewSettingsItemFromListItem(oListItem); if (oVSPItem instanceof sap.m.ViewSettingsCustomItem) { // for custom filter oItems the oItem is directly selected iFilterCount = oVSPItem.getFilterCount(); } else if (oVSPItem instanceof sap.m.ViewSettingsFilterItem) { // for filter oItems the oItem counter has to be calculated from // the sub oItems iFilterCount = oVSPItem.getItems().filter(function (oSubItem) { return oSubItem.getSelected(); }).length; } oListItem.setCounter(iFilterCount); } }, this); }; /** * Updates the list with the items for a concrete parent filter item * @param {Object} oParentFilterItem The parent filter item * @private */ ViewSettingsPopover.prototype._updateFilterDetailListFor = function (oParentFilterItem) { var bMultiSelectMode = this._findViewSettingsItemFromListItem(oParentFilterItem).getMultiSelect(); var oParent = sap.ui.getCore().byId(oParentFilterItem.getId().split(LIST_ITEMS_SUFFIX).shift()); var oVSPItems = oParent && oParent.getItems() || []; var oList = this._getFilterDetailList(); oList.destroyAggregation("items"); if (bMultiSelectMode) { oList.setIncludeItemInSelection(true); oList.setMode(ListMode.MultiSelect); } else { oList.setMode(ListMode.SingleSelectLeft); } // create items anew oVSPItems.forEach(function (oVSPItem) { oList.addItem(new StandardListItem({ id: oVSPItem.getId() + FILTERDETAIL_LIST_ITEMS_SUFFIX, title: oVSPItem.getText(), type: ListType.Active, selected: oVSPItem.getSelected() })); }, this); }; /** * Removes any current contents from a page by making them aggregations of this instance. * @param {string} sPageId ID of the page for which to remove content * @private */ ViewSettingsPopover.prototype._removePageContents = function(sPageId) { var sProperty, sType, oPageContent, oPageList, sGetPageMethodName = '_getMainPage'; if (sPageId === 'filterDetail') { sGetPageMethodName = '_getDetailsPage'; } oPageContent = this[sGetPageMethodName]().getContent(); oPageList = oPageContent[0]; for (sProperty in this._tabMap) { sType = this._tabMap[sProperty]; if (oPageList) { if (oPageList.getId() === sType + 'list') { this['_' + sType + 'List'] = oPageList; } } } if (!(sPageId in this._tabMap) || isLastPageContentCustomTab.call(this)) { // custom tabs this.getCustomTabs().forEach(function (oCustomTab) { if (this._currentPageId === oCustomTab.getId()) { oPageContent.forEach(function (oContent) { oCustomTab.addAggregation('content', oContent, true); }); } }, this); } this[sGetPageMethodName]().removeAllContent(); }; /** * Adds corresponding contents to a page. * @param {string} sPageId ID of the page for which to add content * @private */ ViewSettingsPopover.prototype._addPageContents = function(sPageId) { var sProperty, sType, oList, aCustomTabs = this.getCustomTabs(), sGetPageMethodName = '_getMainPage'; if (sPageId === 'filterDetail') { sGetPageMethodName = '_getDetailsPage'; } for (sProperty in this._tabMap) { sType = this._tabMap[sProperty]; if (sType === sPageId) { sType = sType.slice(0, 1).toUpperCase() + sType.slice(1); oList = this['_get' + sType + 'List'](); this[sGetPageMethodName]().addContent(oList); } } if (!(sPageId in this._tabMap)) { // custom tabs aCustomTabs.forEach(function (oCustomTab) { if (oCustomTab.getId() === sPageId) { oCustomTab.getContent().forEach(function (oContent) { this[sGetPageMethodName]().addContent(oContent); }, this); } }, this); } }; /** * Stash items for later use. * @param {Object} mSettings Object holding a collection of settings * @private */ ViewSettingsPopover.prototype._stashItems = function (mSettings) { /* Store the items for later and remove them for the initialization of the control to avoid racing * condition with the initialization of <code>ViewSettingsPopover</code>. This is only required when the items aggregation * is initialized directly with an array of ViewSettingsPopover items without data binding and a template. */ var aTabs = ['sort','filter','group']; aTabs.forEach(function (sType) { if (mSettings && Array.isArray(mSettings[sType + 'Items'])) { this._stashedItems[sType] = mSettings[sType + 'Items']; } }, this); }; /** * If any items are stashed, used them and add them to the corresponding aggregation. * @param {array} aStashedItems Stashed items * @private */ ViewSettingsPopover.prototype._addStashedItems = function (aStashedItems) { // re-introduce any existing items from the constructor settings var sProperty, vStashedItems, sStashedItemKey, sType; for (sProperty in this._tabMap) { // sort/filter/group var sType = this._tabMap[sProperty]; vStashedItems = this._stashedItems[sType]; for (sStashedItemKey in vStashedItems) { var oStashedItem = vStashedItems[sStashedItemKey]; this.addAggregation(sType + 'Items', oStashedItem); } } }; /** * Handles "back" navigation logic. * @param {Object} oEvent Original event trigger for the "back" action */ ViewSettingsPopover.prototype._handleBack = function (oEvent) { if (this._currentPageId === 'filterDetail') { this._showContentFor('filter'); } }; /** * Creates "select all" checkbox. * @param {array} aFilterSubItems The filter sub-items * @param {Object} oFilterDetailList The filter details list * @returns {sap.m.CheckBox} The created checkBox * @private */ ViewSettingsPopover.prototype._getSelectAllCheckbox = function (aFilterSubItems, oFilterDetailList) { var oCheckBox = sap.ui.getCore().byId(this.getId() + SELECT_ALL_SUFFIX); if (oCheckBox) { return oCheckBox; } return new sap.m.CheckBox({ id: this.getId() + SELECT_ALL_SUFFIX, text: 'Select All', selected: aFilterSubItems && aFilterSubItems.every(function(oItem) { return oItem && oItem.getSelected(); }), select: function(oEvent) { var bSelected = oEvent.getParameter('selected'); //update the list items //and corresponding view settings items oFilterDetailList.getItems().filter(function(oItem) { return oItem.getVisible(); }).forEach(function(oItem) { var oVSDItem = this._findViewSettingsItemFromListItem(oItem); oVSDItem.setProperty('selected', bSelected, true); }.bind(this)); this._toggleRemoveFilterItem(); }.bind(this) }); }; /** * Creates a single <code>sap.m.List</code>. * @param {string} sType Adds namespace for list's Id to avoid duplicates and make list selections easier * @private */ ViewSettingsPopover.prototype._createList = function (sType) { var oVSPItem, sEventName = sType.slice(0,1).toUpperCase() + sType.slice(1), oList = new List({ id : this.getId() + '-' + sType + 'list', itemPress: function (oEvent) { oVSPItem = this._findViewSettingsItemFromListItem(oEvent.getParameter('listItem')); // if we click on an already selected item from grouping or sorting fire select event // inside filtering the select event is fired after "OK" button is pressed if (sType === 'group' || sType === 'sort') { this['fire' + sEventName + 'Selected']({ items: [oVSPItem] }); this.close(); } }.bind(this), selectionChange: function (oEvent) { var aFilterItems; var aSubItems; var aAllDetailItems = []; this._updateSelectAllCheckBoxState(); oVSPItem = this._findViewSettingsItemFromListItem(oEvent.getParameter('listItem')); oVSPItem.setProperty('selected', oEvent.getParameter('selected'), true); // make sure only one item is selected in single select mode if (oList.getMode() !== ListMode.MultiSelect) { aFilterItems = this.getFilterItems(); if (aFilterItems) { aFilterItems.forEach(function (oItem) { aSubItems = oItem.getItems(); if (aSubItems) { aAllDetailItems = aAllDetailItems.concat(aSubItems); } }); } aAllDetailItems.forEach(function (oFilterDetailItem) { if ( oFilterDetailItem.getParent().getId() === oVSPItem.getParent().getId() && oFilterDetailItem.getSelected(true) && oFilterDetailItem.getId() !== oVSPItem.getId() ) { oFilterDetailItem.setProperty('selected', false, true); } }); } if (sType === 'filterDetail') { sEventName = 'Filter'; } else { this['fire' + sEventName + 'Selected']({ items: [oVSPItem] }); this.close(); } switch (sType) { case 'group': // add 'no grouping' option this._getGroupList().addItem(this._getRemoveGroupingItem()); break; } }.bind(this) }); if (sType !== 'filter') { oList.setMode(ListMode.SingleSelectMaster); } this['_' + sType + 'List'] = oList; }; /** * Returns or create list item for removing any existing grouping. * @returns {sap.m.StandardListItem} List item for removing any existing grouping * @private */ ViewSettingsPopover.prototype._getRemoveGroupingItem = function () { if (!this._removeGroupingItem) { this._removeGroupingItem = new StandardListItem({ id: this.getId() + '-nogrouping', title: this._getText('NO_GROUPING'), type: ListType.Active }); } return this._removeGroupingItem; }; /** * Returns or creates list item for removing any existing filtering. * @returns {sap.m.StandardListItem|*} List item for removing any existing filtering * @private */ ViewSettingsPopover.prototype._getRemoveFilterItem = function () { if (!this._removeFilteringItem) { this._removeFilteringItem = new StandardListItem({ id: this.getId() + '-nofiltering', title: this._getText('REMOVE_FILTER'), type: ListType.Active, press: function () { this.getFilterItems().forEach(function (oFilterItem) { oFilterItem.getItems().forEach(function (oSubItem) { oSubItem.setProperty('selected', false, true); }); }); this.close(); // self destruct this._removeFilteringItem.destroy(); this._removeFilteringItem = null; }.bind(this) }); } return this._removeFilteringItem; }; /** * Create <code>sap.m.SegmentedButtonItem</code> for the <code>customTab</code>. * @param {sap.m.ViewSettingsCustomTab} oCustomTab custom tab for which should be created SegmentedButtonItem * @returns {sap.m.SegmentedButtonItem} * @private */ ViewSettingsPopover.prototype._getTabButtonItem = function (oCustomTab) { var sButtonId = this.getId() + oCustomTab.getId() + CUSTOM_TAB_SUFFIX, oButton = sap.ui.getCore().byId(sButtonId); if (oButton) { return oButton; } else { return new sap.m.SegmentedButtonItem({ key : sButtonId, id : sButtonId, icon : oCustomTab.getIcon(), tooltip : oCustomTab.getTooltip() }); } }; /** * Adds <code>sap.m.SegmentedButtonItem</code>. * @param {string} sType Type of item to add * @private */ ViewSettingsPopover.prototype._addPredefinedTab = function (sType) { var sIconName = this._tabMap[sType]; switch (sIconName) { case 'group': sIconName = sIconName + '-2'; break; } var oNewButton = new sap.m.SegmentedButtonItem({ key: sType, icon : IconPool.getIconURI(sIconName), tooltip : this._getText("VIEWSETTINGS_TITLE_" + sType.toUpperCase()), press: function onTabPress (oEvent) { var sPageId = oEvent.getSource().getProperty('key'); var aItems = this['get' + sPageId.slice(0, 1).toUpperCase() + sPageId.slice(1) + 'Items'](); if (this._currentPageId === sPageId || this._currentPageId === this._tabMap['filterDetail'] && aItems && aItems.length > 1) { if (Device.system.phone) { this._cancel(); } else { this._hideContent(); } } else { if (aItems && aItems.length === 1) { if (sPageId !== 'filter') { // if there's a single item for 'sort' and 'group' - directly consider it as selected aItems.forEach(function (oItem) { // toggle selection property oItem.setSelected(!oItem.getSelected()); }); this['fire' + sPageId.slice(0, 1).toUpperCase() + sPageId.slice(1) + 'Selected']({ items: aItems }); this.close(); } else { this._showContentFor('filterDetail', this._findListItemFromViewSettingsItem(aItems[0]), true); } } else { this._showContentFor(sPageId); } } }.bind(this) }); switch (sType) { case 'sort': this._getSegmentedButton().insertItem(oNewButton, 0); break; case 'filter': this._getSegmentedButton().insertItem(oNewButton, 1); break; case 'group': this._getSegmentedButton().insertItem(oNewButton, 2); break; } }; /** * Overwrites the aggregation setter in order to have ID validation logic as some strings * are reserved for the predefined tabs. * * @overwrite * @public * @param {sap.m.ViewSettingsCustomTab} oCustomTab The custom tab to be added * @param {function} fnCustomTabPress Function to attach to the press event of the custom tab * @param {sap.ui.core.Control} oListener The control that listen to the event * @returns {sap.m.ViewSettingsPopover} this pointer for chaining */ ViewSettingsPopover.prototype.addCustomTab = function (oCustomTab, fnCustomTabPress, oListener) { var sId = oCustomTab.getId(); if (sId === 'sort' || sId === 'filter' || sId === 'group') { throw new Error('Id "' + sId + '" is reserved and cannot be used as custom tab id.'); } this.addAggregation('customTabs', oCustomTab); if (!this._isEmptyCustomTab(oCustomTab)) { var oButton = this._getTabButtonItem(oCustomTab); if (!fnCustomTabPress) { oButton.attachEvent("press", this._handleCustomTabPress, this); } else { // attach press event with the provided function and the listener oButton.attachEvent("press", fnCustomTabPress, oListener); } // add custom tab to segmented button this._getSegmentedButton().addItem(oButton); } return this; }; ViewSettingsPopover.prototype._handleCustomTabPress = function (oEvent) { var i, oCustomTab, sCustomTabButtonId, sCurrentPage, aCustomTabs = this.getCustomTabs(), iCustomTabsLength = aCustomTabs.length, sPageId = oEvent.getParameter('id'); for (i = 0; i < iCustomTabsLength; i++) { oCustomTab = aCustomTabs[i]; sCustomTabButtonId = this.getId() + oCustomTab.getId() + CUSTOM_TAB_SUFFIX; sCurrentPage = this.getId() + this._currentPageId + CUSTOM_TAB_SUFFIX; if (sCurrentPage === sPageId) { if (Device.system.phone) { this._cancel(); break; } else { this._hideContent(); break; } } else { if (!this._isEmptyCustomTab(oCustomTab) && sPageId === sCustomTabButtonId) { this._showContentFor(oCustomTab.getId()); break; } } } }; /** * Hides content and collapses in toolbar view. */ ViewSettingsPopover.prototype._hideContent = function () { this._removeSegmentedButtonSelection(); this._cleanAfterClose(); setTimeout(this['_adjustInitialWidth'].bind(this), 0); }; /** * Cleans up the state after close. * @private */ ViewSettingsPopover.prototype._cleanAfterClose = function () { this._removePageContents(this._currentPageId); this._getPopover().setContentHeight(this._initialHeight); this._removeFooter(); this._navigateToPage('Main'); this._currentPageId = null; }; /** * Removes <code>sap.m.SegmentedButtonItem</code>. * @param {string} sType Type of item to remove * @private */ ViewSettingsPopover.prototype._removePredefinedTab = function (sType) { var aTabs = this._getSegmentedButton().getItems(); aTabs.forEach(function (oItem) { if (oItem.getKey() === sType.toLowerCase()) { this._getSegmentedButton().removeItem(oItem); } }, this); if (this._currentPageId === sType.toLowerCase()) { this._showContentFor(this._determinePageToOpen()); } }; /** * Removes <code>sap.m.SegmentedButtonItem</code>. * @param {Object} oObject if given only the button for that custom tab will be removed * @private */ ViewSettingsPopover.prototype._removeCustomTab = function (oObject) { var bShouldRemovePage, sCustomTabButtonId, sCurrentCustomPageId = this.getId() + this._currentPageId + CUSTOM_TAB_SUFFIX, bObjectIsCustomTabButton = false, aTabs = this._getSegmentedButton().getItems(); aTabs.forEach(function (oItem) { if (oItem.getKey().indexOf(CUSTOM_TAB_SUFFIX) !== -1) { if (oObject) { bShouldRemovePage = (this._currentPageId === oObject.getId()); sCustomTabButtonId = this.getId() + oObject.getId() + CUSTOM_TAB_SUFFIX; bObjectIsCustomTabButton = (oObject && sCustomTabButtonId === oItem.getId()); } else { bShouldRemovePage = (sCurrentCustomPageId === oItem.getId()); } if (!oObject || bObjectIsCustomTabButton) { this._getSegmentedButton().removeItem(oItem); } // if the opened page belongs to the removed item of the segementedButton // it will be removed also and we should find which page should be opened on its place if (bShouldRemovePage) { this._showContentFor(this._determinePageToOpen()); } } }, this); }; /** * Gets <code>LabelledBy</code> association or create label and return its ID * @returns {sap.ui.core.InvisibleText} The created label * @private */ ViewSettingsPopover.prototype._getPopoverAriaLabel = function () { var sLabel = this.getAssociation("ariaLabelledBy"); if (!sLabel) { sLabel = new InvisibleText({ text: this._getText("ARIA_LABELLED_BY_POPOVER") }).toStatic().getId(); this.setAssociation("ariaLabelledBy", sLabel, true); } return sLabel; }; /** * Determine if a string is actually a name of one of the items aggregations. * @param {string} sAggregationName Suggested name of aggregation * @returns {boolean} Whether a string is actually a name of one of the items aggregations * @private */ ViewSettingsPopover.prototype._isItemsAggregation = function (sAggregationName) { var aItemsAggregations = []; var sPropertyKey; for (sPropertyKey in this._tabMap) { aItemsAggregations.push(sPropertyKey + 'Items'); } if (aItemsAggregations.indexOf(sAggregationName) === -1) { return false; } return true; }; /** * Adds an entity <code>oObject</code> to the aggregation identified by <code>sAggregationName</code>. * * @param {string} sAggregationName The name of the aggregation where the new entity is to be added * @param {any} oObject The value of the aggregation to be added * @param {boolean} bSuppressInvalidate Whether to suppress invalidation * @returns {sap.m.ViewSettingsPopover} <code>this</code> pointer for chaining * @override */ ViewSettingsPopover.prototype.addAggregation = function(sAggregationName, oObject, bSuppressInvalidate) { if (this._isItemsAggregation(sAggregationName)) { (!this.getAggregation(sAggregationName) || this.getAggregation(sAggregationName).length === 0) && this._addPredefinedTab(sAggregationName.replace('Items', '')); this._handleItemsAggregation.call(this, ['addAggregation', sAggregationName, oObject, bSuppressInvalidate], true); } return Control.prototype.addAggregation.call(this, sAggregationName, oObject, bSuppressInvalidate); }; /** * Inserts an entity to the aggregation named <code>sAggregationName</code> at position <code>iIndex</code>. * * @param {string} sAggregationName The name of the aggregation * @param {any} oObject The value of the aggregation to be inserted * @param {int} iIndex Where to insert * @param {boolean} bSuppressInvalidate Whether to suppress invalidation * @returns {sap.m.ViewSettingsPopover} <code>this</code> pointer for chaining * @override */ ViewSettingsPopover.prototype.insertAggregation = function(sAggregationName, oObject, iIndex, bSuppressInvalidate) { if (this._isItemsAggregation(sAggregationName)) { (!this.getAggregation(sAggregationName) || this.getAggregation(sAggregationName).length === 0) && this._addPredefinedTab(sAggregationName.replace('Items', '')); this._handleItemsAggregation.call(this, ['insertAggregation', sAggregationName, oObject, iIndex, bSuppressInvalidate], true); } return Control.prototype.insertAggregation.call(this, sAggregationName, oObject, iIndex, bSuppressInvalidate); }; /** * Removes an entity from the aggregation named <code>sAggregationName</code>. * * @param {string} sAggregationName The name of the aggregation * @param {any} oObject The value of aggregation to be removed * @param {boolean} bSuppressInvalidate Whether to suppress invalidation * @returns {sap.m.ViewSettingsPopover} <code>this</code> pointer for chaining * @override */ ViewSettingsPopover.prototype.removeAggregation = function(sAggregationName, oObject, bSuppressInvalidate) { if (this._isItemsAggregation(sAggregationName)) { this._handleItemsAggregation.call(this, ['removeAggregation', sAggregationName, oObject, bSuppressInvalidate]); if (!this['getAggregation'](sAggregationName)) { this._removePredefinedTab(sAggregationName.replace('Items', '')); } } else { this._removeCustomTab(oObject); } return Control.prototype.removeAggregation.call(this, sAggregationName, oObject, bSuppressInvalidate); }; /** * Removes all objects from the aggregation named <code>sAggregationName</code>. * * @param {string} sAggregationName The name of aggregation * @param {boolean} bSuppressInvalidate Whether to suppress invalidation * @returns {sap.m.ViewSettingsPopover} <code>this</code> pointer for chaining * @override */ ViewSettingsPopover.prototype.removeAllAggregation = function(sAggregationName, bSuppressInvalidate) { if (this._isItemsAggregation(sAggregationName)) { this._handleItemsAggregation.call(this, ['removeAllAggregation', sAggregationName, null, bSuppressInvalidate]); this._removePredefinedTab(sAggregationName.replace('Items', '')); } else { this._removeCustomTab(); } return Control.prototype.removeAllAggregation.call(this, sAggregationName, bSuppressInvalidate); }; /** * Destroys all the entities in the aggregation named <code>sAggregationName</code>. * * @param {string} sAggregationName The name of aggregation * @param {boolean} bSuppressInvalidate Whether to suppress invalidation * @returns {sap.m.ViewSettingsPopover} <code>this</code> pointer for chaining * @override */ ViewSettingsPopover.prototype.destroyAggregation = function(sAggregationName, bSuppressInvalidate) { if (this._isItemsAggregation(sAggregationName)) { var sType = sAggregationName.replace('Items', ''); this._handleItemsAggregation.call(this, ['destroyAggregation', sAggregationName, bSuppressInvalidate]); this._removePredefinedTab(sType.slice(0,1).toUpperCase() + sType.slice(1)); } else if (this._segmentedButton) { // check if the segmentedButton exists before removing some of its buttons this._removeCustomTab(); } return Control.prototype.destroyAggregation.call(this, sAggregationName, bSuppressInvalidate); }; /** * Ensures proper handling of <code>ViewSettingsPopover</code> <code>items</code> aggregation> and proxies to the list <code>items</code> aggregation. * * @param {array} aArgs * @param {boolean} bIsAdding * @returns {sap.m.Vi