/*! * SAPUI5 * Copyright (c) 2025 SAP SE or an SAP affiliate company. All rights reserved. */ import List, { $ListSettings } from "sap/m/List"; import { MetadataOptions } from "sap/ui/base/ManagedObject"; import { ResultSetItem } from "../../ResultSetApi"; import SearchBasketModel, { SearchBasketApi } from "./SearchBasketModel"; import { callConfigExit } from "../../error/callConfigExit"; import CustomListItem from "sap/m/CustomListItem"; import Text from "sap/m/Text"; import Context from "sap/ui/model/Context"; import { initialValueUnicode } from "../../uiConstants"; import HBox from "sap/m/HBox"; import Icon from "sap/ui/core/Icon"; import SearchLink from "../SearchLink"; import VBox from "sap/m/VBox"; import Event from "sap/ui/base/Event"; import { ButtonType, ListMode } from "sap/m/library"; import OverflowToolbar from "sap/m/OverflowToolbar"; import Button from "sap/m/Button"; import i18n from "../../i18n"; export interface $SearchBasketSapMListSettings extends $ListSettings { basketConfigurator?: { adaptColumns: (columns: any[]) => any[]; adaptRow: (publicItem: ResultSetItem) => ResultSetItem; }; showDeleteAction?: boolean; selectionMode?: string; // maps to ListMode of sap.m.List ('Multi' → MultiSelect, 'None' → None) } /** * @namespace sap.esh.search.ui.controls.basket */ export default class SearchBasketSapMList extends List implements SearchBasketApi { static readonly metadata: MetadataOptions = { library: "sap.esh.search.ui.controls.basket", aggregations: {}, properties: { /** * An object containing the basket configurator functions 'adaptColumns' and 'adaptRow'. * @since 1.145.0 */ basketConfigurator: { type: "object", group: "Data", }, /** * Whether to show an X (delete) button per row to remove items from the basket. * When true, clicking X removes the item from the basket and, when basketLinkByResultViewItemSelection * is active, also deselects it in the result view. * @since 1.145.0 */ showDeleteAction: { type: "boolean", group: "Appearance", defaultValue: false, }, }, }; constructor(sId?: string, settings?: $SearchBasketSapMListSettings) { super(sId, settings); let columns = []; if (settings?.basketConfigurator) { columns = callConfigExit("basketInit (basketConfigurator.adaptColumns)", "HAN-AS-INA-UI", () => settings?.basketConfigurator?.adaptColumns([]) ); } const basketModel = new SearchBasketModel({ columns: columns ? columns : [], rows: [], publicItems: [], basketCount: 0, config: { basketConfigurator: settings.basketConfigurator ? settings.basketConfigurator : null, }, customData: {}, }); // add binding for basket model property "/selectAll" to select/deselect all items in the table basketModel.bindProperty("/selectAll").attachChange((oEvent) => { const selectAll = oEvent.getSource().getValue(); if (selectAll) { this.selectAll(); } else if (typeof selectAll !== "undefined") { this.removeSelections(true); } }); // set basket model this.setModel(basketModel, "eshBasket"); // add default headerToolbar with Remove All button if none provided via settings if (!settings?.headerToolbar) { this.setHeaderToolbar(this._createDefaultToolbar()); } // define group for F6 handling this.data("sap-ui-fastnavgroup", "true", true /* write into DOM */); // this.setAlternateRowColors(true); this.addStyleClass("sapUiSmallMarginTop"); this.addStyleClass("sapElisaSearchBasketTable"); this.bindItems({ path: "eshBasket>/rows", factory: (rowPath: string, oContext: Context) => { let newItem; const idPrefix = (oContext.getObject() as ResultSetItem).key.replace(/[^a-zA-Z0-9_-]/g, "_"); const hasIcon = oContext.getProperty("hasIcon"); const iconPath = oContext.getProperty("iconPath"); // const width = context.getProperty("width"); const oItem = oContext.getObject() as ResultSetItem; // title template let oTitleTemplate; if (oItem.data.defaultNavigationTarget) { oTitleTemplate = new SearchLink(`${idPrefix}-searchLink`, { wrapping: false, text: { path: "eshBasket>title" }, navigationTarget: { path: "eshBasket>data/defaultNavigationTarget" }, }).addStyleClass("sapUiSmallMarginBegin"); } else { oTitleTemplate = new Text(`${idPrefix}-text`, { text: { parts: [{ path: `eshBasket>title` }], formatter: (text: unknown) => { if (text === null || text === undefined || text === "") { return initialValueUnicode; } return String(text).replace(//g, "").replace(/<\/b>/g, ""); }, }, }); if (hasIcon && iconPath) { oTitleTemplate = new HBox(`${idPrefix}-containerWithIcon`, { items: [ new Icon({ src: `{eshBasket>${iconPath}}` }).addStyleClass( "sapUiTinyMarginEnd" ), oTitleTemplate, ], }); } } // details attributes template const oAttributeTemplates = []; if (oItem.data.detailAttributes && oItem.data.detailAttributes.length > 0) { for ( let i = 0; i < oItem.data.detailAttributes.length && oAttributeTemplates.length < 5; i++ ) { const detailAttr = oItem.data.detailAttributes[i]; oAttributeTemplates.push( new Text(`${idPrefix}-${detailAttr.id}-text`, { text: `{eshBasket>data/detailAttributes/${i}/valueFormatted}`, visible: { parts: [{ path: `eshBasket>data/detailAttributes/${i}/valueFormatted` }], formatter: (valueFormatted) => { return ( valueFormatted !== null && valueFormatted !== undefined && valueFormatted !== "" ); }, }, }).addStyleClass("sapUiSmallMarginBegin") ); } newItem = new CustomListItem(`${idPrefix}-customListItem`, { content: new VBox(`${idPrefix}-vbox`, { items: [oTitleTemplate, ...oAttributeTemplates], }), }); } else { newItem = new CustomListItem(`${idPrefix}-customListItem`, { content: [oTitleTemplate], }); } /* if (width) { newItem.setWidth(width); } */ return newItem; }, }); if (typeof settings?.selectionMode !== "undefined") { if (settings.selectionMode === "Multi") { this.setMode(ListMode.MultiSelect); } else if (settings.selectionMode === "None") { this.setMode(ListMode.None); } } this.attachSelectionChange(() => { const oBasketModel = this.getModel("eshBasket") as SearchBasketModel; if (oBasketModel.getProperty("/_skipRowSelectionChange")) { return; } oBasketModel.syncSearchCompControl(this); }); if (settings?.showDeleteAction) { // add delete action to each row this.setMode(ListMode.Delete); } this.attachDelete((oEvent: Event) => { const oBasketModel = this.getModel("eshBasket") as SearchBasketModel; if (oBasketModel.getProperty("/_skipRowSelectionChange")) { return; } const listItem = oEvent.getParameters()["listItem"] as CustomListItem; const itemKey = listItem.getBindingContext("eshBasket").getObject()["key"]; oBasketModel.removeItemsFromBasket([itemKey], this); oBasketModel.logItemRemove(1); }); } getBasketModel(): SearchBasketModel { return this.getModel("eshBasket") as SearchBasketModel; } private _clearBasketButton: Button; createClearBasketButton(): Button { if (!this._clearBasketButton) { this._clearBasketButton = new Button(`${this.getId()}-clearBasketButton`, { text: i18n.getText("clearBasket"), tooltip: i18n.getText("clearBasket_tooltip"), icon: "sap-icon://clear-all", type: ButtonType.Transparent, enabled: { parts: [{ path: "eshBasket>/count" }], formatter: (count: number) => count > 0, }, press: () => { const oBasketModel = this.getBasketModel(); const itemCount = oBasketModel.getProperty("/count") as number; oBasketModel.clearBasket(this); oBasketModel.logClear(itemCount); }, }); } return this._clearBasketButton; } private _createDefaultToolbar(): OverflowToolbar { return new OverflowToolbar(`${this.getId()}-defaultToolbar`, { content: [this.createClearBasketButton()], }); } static renderer = { apiVersion: 2, }; }