@openui5/sap.m
Version:
OpenUI5 UI Library sap.m
299 lines (259 loc) • 9.53 kB
JavaScript
/*!
* 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([
"sap/m/p13n/QueryPanel",
"sap/m/VBox",
"sap/m/Text",
"sap/ui/layout/Grid",
"sap/ui/layout/GridData",
"sap/m/ComboBox",
"sap/ui/core/library",
"sap/m/library",
"sap/m/Label",
"sap/ui/core/Lib"
], (
QueryPanel,
VBox,
Text,
Grid,
GridData,
ComboBox,
coreLibrary,
mLibrary,
Label,
Library
) => {
"use strict";
//shortcut for sap.ui.core.ValueState
const ValueState = coreLibrary.ValueState;
// shortcut for sap.m.ListKeyboardMode
const ListKeyboardMode = mLibrary.ListKeyboardMode;
// shortcut for sap.m.FlexJustifyContent
const FlexJustifyContent = mLibrary.FlexJustifyContent;
// shortcut for sap.m.WrappingType
const WrappingType = mLibrary.WrappingType;
/**
* Constructor for a new <code>FilterPanel</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 can be used to customize personalization content for filtering
* for an associated control instance.
*
* @extends sap.m.p13n.QueryPanel
*
* @author SAP SE
* @version 1.146.0
*
* @private
* @since 1.121
* @alias sap.m.p13n.FilterPanel
*/
const FilterPanel = QueryPanel.extend("sap.m.p13n.FilterPanel", {
metadata: {
library: "sap.m",
properties: {
/**
* A factory function that is called whenever the user selects a new entry from the <code>ComboBox</code>.
* The factory must return a single control instance of an input-based control to provide custom filter capabilities.
* This control is then going to be added in the grid layout provided by the <code>QueryPanel</code>.
* Whenever the <code>FilterPanel#setP13nData</code> method is called, <code>active</code> can be used to update the
* current set of active factory controls.
*
* <b>Note:</b>: The panel does not handle the lifecylce of the provided factory control instance, if the row is removed. The consumer needs to decide about destroying or keeping the control instance.
* In addition, the <code>getIdForLabel</code> method can be used to return a focusable child control to provide the <code>labelFor</code> reference.
*/
itemFactory: {
type: "function"
},
/**
* A short text describing the panel.
* <b>Note:</b> This text will only be displayed if the panel is being used in a <code>sap.m.p13n.Popup</code>.
*/
title: {
type: "string",
defaultValue: Library.getResourceBundleFor("sap.m").getText("p13n.DEFAULT_TITLE_FILTER")
}
}
},
renderer: {
apiVersion: 2
}
});
/**
* Personalization <code>FilterItem</code> object type.
*
* @static
* @constant
* @typedef {object} sap.m.p13n.FilterItem
* @property {string} name The unique key of the item
* @property {string} label The label describing the personalization item
* @property {boolean} active Defines whether there is a visible grid shown in the panel for this key, also triggers the call of the <code>#itemFactory</code> function
* @property {object[]} [conditions] The conditions that are optionally used for persisted when using the <code>FilterPanel</code> within a <code>FilterController</code>
*
* @private
*/
/**
* Sets the personalization state of the panel instance.
*
* @name sap.m.p13n.FilterPanel.prototype.setP13nData
* @function
* @param {sap.m.p13n.FilterItem[]} aP13nData An array containing the personalization state
* @returns {this} The FilterPanel instance
*/
FilterPanel.prototype.PRESENCE_ATTRIBUTE = "active";
FilterPanel.prototype._createInnerListControl = function() {
const oList = QueryPanel.prototype._createInnerListControl.apply(this, arguments);
return oList;
};
FilterPanel.prototype._createQueryRowGrid = function(oItem) {
const oRowContent = oItem.name ? this._createRowContainer(oItem.label, oItem.key, oItem.tooltip) : this._createKeySelect(oItem.name);
const aContent = [oRowContent];
if (oItem.name) {
const oFilterItem = this._createFactoryControl(oItem);
aContent.push(oFilterItem);
this._setLabelForOnBox(oFilterItem, oRowContent);
}
return new Grid({
containerQuery: true,
defaultSpan: "XL4 L4 M4 S4",
content: aContent
}).addStyleClass("sapUiTinyMargin");
};
FilterPanel.prototype._getPlaceholderText = function() {
return this._getResourceText("p13n.FILTER_PLACEHOLDER");
};
FilterPanel.prototype._getRemoveButtonTooltipText = function() {
return this._getResourceText("p13n.FILTER_REMOVEICONTOOLTIP");
};
FilterPanel.prototype._getRemoveButtonAnnouncementText = function() {
return this._getResourceText("p13n.FILTER_REMOVEICONANNOUNCE");
};
FilterPanel.prototype._createKeySelect = function(sKey) {
const oComboBox = new ComboBox({
width: "100%",
items: this._getAvailableItems(),
placeholder: this._getPlaceholderText(),
selectionChange: (oEvt) => {
const oComboBox = oEvt.getSource();
this._selectKey(oComboBox);
},
change: (oEvt) => {
const oComboBox = oEvt.getSource();
const newValue = oEvt.getParameter("newValue");
oComboBox.setValueState(newValue && !oComboBox.getSelectedItem() ? ValueState.Error : ValueState.None);
this._selectKey();
}
});
oComboBox.setLayoutData(new GridData({
span: "XL4 L4 M4 S11"
}));
return oComboBox;
};
FilterPanel.prototype._createRemoveButton = function(bVisible) {
const oRemoveBtn = QueryPanel.prototype._createRemoveButton.apply(this, arguments);
oRemoveBtn.setJustifyContent(FlexJustifyContent.Start); //avoid remove button overlapping with input field
oRemoveBtn.setLayoutData(new GridData({
span: "XL1 L1 M1 S1"
}));
return oRemoveBtn;
};
FilterPanel.prototype._createRowContainer = (sText, sKey, sTooltip) => {
// var sKey = oSelect._key;
const oLabel = new Label({
text: sText,
tooltip: sTooltip ?? undefined,
showColon: true,
wrapping: true,
wrappingType: WrappingType.Hyphenated
});
const oFieldBox = new VBox({
items: [oLabel.addStyleClass("sapUiTinyMarginBegin")]
});
oFieldBox._key = sKey;
return oFieldBox;
};
FilterPanel.prototype._setLabelForOnBox = (oFilterItem, oFieldBox) => {
oFieldBox.getItems()[0].setLabelFor(oFilterItem);
};
FilterPanel.prototype._selectKey = function(oComboBox) {
let oQueryRowGrid, sKey;
if (oComboBox) {
this._oComboBox = oComboBox;
oQueryRowGrid = oComboBox.getParent();
sKey = oComboBox.getSelectedKey();
} else if (this._oComboBox) {
oComboBox = this._oComboBox;
oQueryRowGrid = oComboBox.getParent();
sKey = oComboBox.getSelectedKey();
let oFilterItem;
if (sKey) {
QueryPanel.prototype._selectKey.call(this, oComboBox);
const oSelect = oQueryRowGrid.getContent()[0];
oQueryRowGrid.removeContent(oSelect);
const sText = sKey ? oComboBox.getSelectedItem().getText() : "";
const sTooltip = this.getP13nData().find((oItem) => oItem.key === oComboBox.getSelectedItem().getKey())?.tooltip ?? undefined;
const oFieldBox = this._createRowContainer(sText, sKey, sTooltip); //Create a container with a VBox and a label with some padding inside and insert it in the grid
oQueryRowGrid.insertContent(oFieldBox, 0);
oFilterItem = this._createFactoryControl({
name: sKey
}); //Create the actual filterable control and insert it in the grid
this._setLabelForOnBox(oFilterItem, oFieldBox);
oQueryRowGrid.insertContent(oFilterItem, 1);
}
//FIXME: Check why this workaround is necessary
setTimeout(() => {
if (this._oListControl && !this._oListControl.bIsDestroyed) {
this._oListControl.setKeyboardMode(ListKeyboardMode.Edit);
}
// Note: the control in mdc is wrapped in a filter group layout, hence it needs to be checked if the item is in mdc context to
// properly set the focus. In comp and freestyle, the item itself is the filterable control
const oControlForFocus = oFilterItem?.getMetadata().getName().includes("sap.ui.mdc") ? oFilterItem.getItems()?.[0] : oFilterItem;
oControlForFocus?.focus();
}, 20);
delete this._oComboBox;
}
};
/**
* @private
* Retrieve the factory control for a current row
* @param {sap.m.CustomListItem} oRow The list item
* @returns {sap.ui.core.Control} The factory control of the provided row
*/
FilterPanel.prototype._getFactoryControlForRow = (oRow) => {
return oRow.getContent()[0].getContent()[1];
};
FilterPanel.prototype._createFactoryControl = function(oItem) {
const oField = this.getItemFactory().call(this, oItem);
oField.setLayoutData(new GridData({
span: "XL7 L7 M7 S7"
}));
let iModelIndex;
this._getP13nModel().getProperty("/items").forEach((oP13nItem, index) => {
if (oP13nItem.key == oItem.name) {
iModelIndex = index;
}
});
const oBindingContext = this._getP13nModel().createBindingContext(`/items/${iModelIndex}/`);
oField.setBindingContext(oBindingContext, this.P13N_MODEL);
return oField;
};
FilterPanel.prototype._updatePresence = function(sKey, bAdd, iNewIndex) {
QueryPanel.prototype._updatePresence.apply(this, arguments);
if (!bAdd) {
const oRelevant = this._getP13nModel().getProperty("/items").find((oItem) => {
return oItem.name === sKey;
});
oRelevant.conditions = [{
operator: "Contains",
conditions: []
}];
}
};
return FilterPanel;
});