@openui5/sap.m
Version:
OpenUI5 UI Library sap.m
440 lines (360 loc) • 13.1 kB
JavaScript
/*!
* OpenUI5
* (c) Copyright 2009-2023 SAP SE or an SAP affiliate company.
* Licensed under the Apache License, Version 2.0 - see LICENSE.txt.
*/
sap.ui.define([
"sap/ui/layout/Grid", "./BasePanel", "sap/ui/core/ListItem", "sap/m/CustomListItem", "sap/m/ComboBox", "sap/m/List", "sap/m/HBox", "sap/m/library", "sap/m/Button", "sap/base/util/merge", "sap/ui/core/library", "sap/ui/core/InvisibleMessage"
], function (Grid, BasePanel, Item, CustomListItem, ComboBox, List, HBox, mLibrary, Button, merge, coreLibrary, InvisibleMessage) {
"use strict";
var ValueState = coreLibrary.ValueState;
/**
* Constructor for a new <code>QueryPanel</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
* This control serves as base class for a query builder like personalization implementation.
*
* @extends sap.m.p13n.BasePanel
*
* @author SAP SE
* @version 1.117.4
*
* @private
* @ui5-restricted sap.m, sap.ui.mdc
*
* @since 1.96
* @alias sap.m.p13n.QueryPanel
*/
var QueryPanel = BasePanel.extend("sap.m.p13n.QueryPanel", {
metadata: {
library: "sap.m",
properties: {
queryLimit: {
type: "int",
defaultValue: -1 //unlimited queries
}
}
},
renderer: {
apiVersion: 2
}
});
// shortcut for sap.m.ListType
var ListItemType = mLibrary.ListType;
// shortcut for sap.m.FlexJustifyContent
var FlexJustifyContent = mLibrary.FlexJustifyContent;
// shortcut for sap.m.ButtonType
var ButtonType = mLibrary.ButtonType;
QueryPanel.prototype.init = function () {
BasePanel.prototype.init.apply(this, arguments);
this._bFocusOnRearrange = false;
this.setEnableReorder(true);
this.addStyleClass("sapMP13nQueryPanel");
};
QueryPanel.prototype.setP13nData = function(aP13nData) {
BasePanel.prototype.setP13nData.apply(this, arguments);
this._oListControl.removeAllItems();
//Add rows for grouped items
if (aP13nData instanceof Array) {
aP13nData.forEach(function (oItem) {
if (oItem[this.PRESENCE_ATTRIBUTE]) {
this._addQueryRow(oItem);
}
}.bind(this));
this._addQueryRow();
}
return this;
};
QueryPanel.prototype.getP13nData = function (bOnlyActive) {
var aItems = [];
this._oListControl.getItems().forEach(function (oItem) {
var sKey = this._getControlFromRow(oItem)._key;
if (sKey) {
var oField = this._getP13nModel().getProperty("/items").find(function (o) {
return o.name == sKey;
});
aItems.push(oField);
}
}.bind(this));
if (!bOnlyActive) {
this._getP13nModel().getProperty("/items").forEach(function(oItem){
if (aItems.indexOf(oItem) === -1) {
aItems.push(oItem);
}
});
}
return merge([], aItems);
};
QueryPanel.prototype._allEntriesUsed = function() {
return this.getP13nData().length === this.getP13nData(true).length;
};
QueryPanel.prototype._moveTableItem = function (oItem, iNewIndex) {
var iCurrentIndex = this._oListControl.getItems().indexOf(oItem);
var iMaxListLength = this._oListControl.getItems().length - 1;
var iQueryLimit = this.getQueryLimit();
// Rules for the movement:
// 1) The row is not the template row
// 2) in case all entries are used, allow reordering for all rows
// 3) in case a query limit is provided, limit the movement to the allowed limit
if ((iCurrentIndex !== iMaxListLength || this._allEntriesUsed()) && (iQueryLimit === -1 || iNewIndex < iQueryLimit)) {
this._oListControl.removeItem(oItem);
this._oListControl.insertItem(oItem, iNewIndex);
this._updateEnableOfMoveButtons(oItem, false);
this._getP13nModel().checkUpdate(true);
this.fireChange({
reason: this.CHANGE_REASON_MOVE,
item: this._getModelEntry(oItem)
});
}
};
QueryPanel.prototype._updateEnableOfMoveButtons = function(oTableItem, bFocus) {
BasePanel.prototype._updateEnableOfMoveButtons.apply(this, arguments);
//The last item is always the "$_none" field
// 1) check if its the item before, if yes do not allow to reorder it below
// 2) Also check the case if all entries are used --> then there is no $_none row and the buttons can be enabled.
if (this._oListControl.getItems().indexOf(oTableItem) === (this._oListControl.getItems().length - 2) && !this._allEntriesUsed()) {
this._getMoveDownButton().setEnabled(false);
}
};
QueryPanel.prototype._createInnerListControl = function () {
return new List(this.getId() + "-innerP13nList", {
itemPress: [this._onItemPressed, this],
dragDropConfig: this._getDragDropConfig()
});
};
QueryPanel.prototype._getModelEntry = function(oRow) {
var sKey = this._getControlFromRow(oRow)._key;
var oField = this._getP13nModel().getProperty("/items").find(function (o) {
return o.name == sKey;
});
return oField;
};
QueryPanel.prototype._getAvailableItems = function (sKey) {
var aItems = this._getP13nModel().getProperty("/items");
var aAvailableItems = [];
aItems.forEach(function (oNonPresent, iIndex) {
aAvailableItems.push(new Item({
key: oNonPresent.name,
text: oNonPresent.label,
enabled: {
path: this.P13N_MODEL + ">/items/" + iIndex + "/" + this.PRESENCE_ATTRIBUTE,
formatter: function(bQueried) {
var oComboBox = this.getParent();
var selItem = oComboBox.getSelectedItem();
var selItemIndex = selItem && oComboBox.getItems().indexOf(selItem);
var sPath = this.getBindingPath("enabled");
var pathIndex = parseInt(sPath.split("/")[2]);
return !bQueried || selItemIndex === pathIndex; //Only enable the selection in case there is not yet a query present or the item is the selected item
}
}
}));
}.bind(this));
return aAvailableItems;
};
QueryPanel.prototype._addQueryRow = function (oItem) {
var bLimitedQueries = this.getQueryLimit() > -1;
var bQueryLimitReached = this.getQueryLimit() <= this._oListControl.getItems().length;
if ((bLimitedQueries && bQueryLimitReached && !oItem) || this._allEntriesUsed()) {
return;
}
oItem = oItem ? oItem : {name: null};
var oQueryRowGrid = this._createQueryRowGrid(oItem);
var oRow = new CustomListItem({
type: ListItemType.Active,
content: [
oQueryRowGrid
]
});
//We only need 'move' buttons if:
// 1) Reordering is enabled
// 2) At least 2 queries can be made
// 3) The row is not exeeding the query limit
if (
this.getEnableReorder() &&
(this.getQueryLimit() === -1 || (this.getQueryLimit() > 1 && this._oListControl.getItems().length < this.getQueryLimit()))
){
this._addHover(oRow);
}
this._getControlFromRow(oRow)._key = oItem.name;
this._oListControl.addItem(oRow);
var bShowRemoveBtn = !!oItem.name;
var oRemoveButton = this._createRemoveButton(bShowRemoveBtn);
oRow.getContent()[0].addContent(oRemoveButton);
return oRow;
};
QueryPanel.prototype._createQueryRowGrid = function(oItem) {
var oSelect = this._createKeySelect(oItem.name);
return new Grid({
containerQuery: true,
defaultSpan: "XL6 L6 M6 S6",
content: [
oSelect
]
}).addStyleClass("sapUiTinyMargin");
};
QueryPanel.prototype._handleActivated = function(oHoveredItem) {
var oQueryRow = oHoveredItem.getContent()[0];
if (oQueryRow) {
var oButtonBox = this._getControlFromRow(oHoveredItem, -1);
//Only add the buttons if 1) an hovered item is provided 2) the buttons are not already there
if (oHoveredItem && oButtonBox.getItems().length < 2) {
oButtonBox.insertItem(this._getMoveUpButton(), 0);
oButtonBox.insertItem(this._getMoveDownButton(), 1);
this._updateEnableOfMoveButtons(oHoveredItem, false);
}
}
};
QueryPanel.prototype._getPlaceholderText = function () {
return "";
};
QueryPanel.prototype._getRemoveButtonTooltipText = function () {
return "";
};
QueryPanel.prototype._getRemoveButtonAnnouncementText = function () {
return "";
};
QueryPanel.prototype._announce = function (sMessage) {
var InvisibleMessageMode = coreLibrary.InvisibleMessageMode;
var oInvisibleMessage = InvisibleMessage.getInstance();
oInvisibleMessage.announce(sMessage, InvisibleMessageMode.Assertive);
};
QueryPanel.prototype._createKeySelect = function (sKey) {
var that = this;
var oKeySelect = new ComboBox({
width: "14rem",
enabled: {
path: this.P13N_MODEL + ">/items/",
formatter: function(aItems) {
if (that.getQueryLimit() < 0) {
return true;
}
var aPresentKeys = that.getP13nData(true).map(function(oItem){
return oItem.name;
});
var sKey = this._key; //'this' is the select control passed by the formatter
var iPositon = aPresentKeys.indexOf(sKey) + 1;
return iPositon <= that.getQueryLimit();
}
},
items: this._getAvailableItems(sKey),
selectedKey: sKey,
placeholder: this._getPlaceholderText(),
selectionChange: function(oEvt) {
var oComboBox = oEvt.getSource();
var oSelItem = oComboBox.getSelectedItem();
// var sNewKey = oComboBox.getSelectedKey();
if (!oSelItem) {
this._selectKey(oComboBox);
}
}.bind(this),
change: function(oEvt) {
var oComboBox = oEvt.getSource();
var newValue = oEvt.getParameter("newValue");
this._selectKey(oComboBox);
oComboBox.setValueState( newValue && !oComboBox.getSelectedItem() ? ValueState.Error : ValueState.None);
}.bind(this)
});
return oKeySelect;
};
QueryPanel.prototype._selectKey = function(oComboBox) {
var sNewKey = oComboBox.getSelectedKey();
var sOldKey = oComboBox._key;
var oListItem = oComboBox.getParent().getParent();
var bIsLastRow = this._oListControl.getItems().length - 1 == this._oListControl.getItems().indexOf(oListItem);
var oBtnContainer = this._getControlFromRow(oListItem, -1);
oBtnContainer.setVisible(!(bIsLastRow && sNewKey == ""));
//Remove previous
if (sOldKey) {
this._updatePresence(sOldKey, false, undefined);
}
//store old key
oComboBox._key = sNewKey;
//add new
this._updatePresence(sNewKey, true, this._oListControl.getItems().indexOf(oListItem));
//Add a new row in case the last "empty" row has been configured
if (sNewKey !== "" && bIsLastRow) {
this._addQueryRow();
}
};
QueryPanel.prototype._createRemoveButton = function (bVisible) {
var oRemoveBox = new HBox({
justifyContent: FlexJustifyContent.End,
width: "100%",
visible: bVisible,
items: [
new Button({
type: ButtonType.Transparent,
icon: "sap-icon://decline",
press: function (oEvt) {
var oRow = oEvt.getSource().getParent().getParent().getParent();
var iQueries = this._oListControl.getItems().length;
//A new row with (none) needs to be created if either no row is left, or if the last potential row
//has been removed, as no row will be created if every possible key has been used
var bNewRowRequired = iQueries === 1 || iQueries == this.getP13nData(true).length;
this._oListControl.removeItem(oRow);
this._updatePresence(this._getControlFromRow(oRow)._key, false, undefined);
if (bNewRowRequired) {
this._addQueryRow();
}
this._announce(this._getRemoveButtonAnnouncementText());
//In case an item has been removed, focus the Select control of the new 'none' row
//Needs timeout because the new queryRow and control might not be rendered
setTimeout(function() {
if (!this.bIsDestroyed) {
this.getInitialFocusedControl().focus();
}
}.bind(this), 0);
this._getP13nModel().checkUpdate(true);
}.bind(this)
})
]
});
if (this._getRemoveButtonTooltipText()) {
oRemoveBox.getItems()[0].setTooltip(this._getRemoveButtonTooltipText());
}
return oRemoveBox;
};
QueryPanel.prototype._moveSelectedItem = function(){
this._oSelectedItem = this._getMoveUpButton().getParent().getParent().getParent();
BasePanel.prototype._moveSelectedItem.apply(this, arguments);
};
QueryPanel.prototype._updatePresence = function (sKey, bAdd, iNewIndex) {
var aItems = merge([], this._getP13nModel().getProperty("/items"));
var aRelevant = aItems.filter(function (oItem) {
return oItem.name === sKey;
});
if (aRelevant[0]) {
aRelevant[0][this.PRESENCE_ATTRIBUTE] = bAdd;
}
this._getP13nModel().setProperty("/items", aItems);
this.fireChange({
reason: bAdd ? this.CHANGE_REASON_ADD : this.CHANGE_REASON_REMOVE,
item: aRelevant[0]
});
};
QueryPanel.prototype.getInitialFocusedControl = function() {
var oRow = this._getRow(-1);
return this._getControlFromRow(oRow);
};
QueryPanel.prototype._getRow = function(iIndex) {
var aItems = this._oListControl.getItems();
if (iIndex < 0) {
iIndex = aItems.length + iIndex;
}
return aItems[iIndex];
};
QueryPanel.prototype._getControlFromRow = function(oRow, iIndex) {
var aContent = oRow.getContent()[0].getContent();
if (iIndex === undefined) {
iIndex = 0;
}
if (iIndex < 0) {
iIndex = aContent.length + iIndex;
}
return aContent[iIndex];
};
return QueryPanel;
});