@openui5/sap.m
Version:
OpenUI5 UI Library sap.m
441 lines (392 loc) • 14.1 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/base/i18n/Localization", "sap/ui/core/Renderer", "sap/ui/core/InvisibleText", "sap/ui/Device", "./library", "./ListBaseRenderer", "./ColumnListItemRenderer", "sap/ui/core/Lib"],
function(Localization, Renderer, InvisibleText, Device, library, ListBaseRenderer, ColumnListItemRenderer, Library) {
"use strict";
var MultiSelectMode = library.MultiSelectMode;
/**
* Table renderer.
*
* TableRenderer extends the ListBaseRenderer
*
* @namespace
*/
var TableRenderer = Renderer.extend(ListBaseRenderer);
TableRenderer.apiVersion = 2;
// store the flex alignment for the column header based on the RTL mode
var bRtl = Localization.getRTL();
TableRenderer.columnAlign = {
left: bRtl ? "flex-end" : "flex-start",
center: "center",
right: bRtl ? "flex-start" : "flex-end"
};
/**
* Renders the Header and/or Footer of the Table like List Control
*
* @param {sap.ui.core.RenderManager} rm RenderManager
* @param {sap.m.ListBase} oTable Table control
* @param {string} sType Whether "Head" or "Foot"
*/
TableRenderer.renderColumns = function(rm, oTable, sType) {
var iIndex = 0,
aAriaOwns = [],
bHasPopin = false,
bHasFlexibleColumn,
bHeaderHidden = false,
bRenderAriaSelected = false,
bColumnHeadersActive = false,
bHasFooter = (sType == "Foot"),
sMode = oTable.getMode(),
sMultiSelectMode = oTable.getMultiSelectMode(),
iModeOrder = ListBaseRenderer.ModeOrder[sMode],
sClassPrefix = "sapMListTbl",
sIdPrefix = oTable.getId("tbl"),
sCellTag = (sType == "Head") ? "th" : "td",
sTypeTag = "t" + sType.toLowerCase(),
aColumns = oTable.getColumns(),
vFixedLayout = oTable.getFixedLayout(),
openStartCell = function(vIdSuffixOrControl, sClassSuffix, sLabelKey) {
var sAriaOwns, vIdOrControl;
if (typeof vIdSuffixOrControl == "string") {
sAriaOwns = vIdOrControl = sIdPrefix + sType + vIdSuffixOrControl;
} else {
vIdOrControl = vIdSuffixOrControl;
sAriaOwns = vIdOrControl.getId();
}
rm.openStart(sCellTag, vIdOrControl);
rm.class(sClassPrefix + sClassSuffix);
rm.attr("aria-colindex", aAriaOwns.push(sAriaOwns));
if (!bHeaderHidden) {
ColumnListItemRenderer.makeFocusable(rm);
}
if (sLabelKey) {
rm.attr("aria-label", Library.getResourceBundleFor("sap.m").getText(sLabelKey));
}
if (sType == "Head") {
rm.class("sapMTableTH");
rm.attr("role", "columnheader");
if (bRenderAriaSelected) {
rm.attr("aria-selected", "false");
}
} else {
rm.attr("role", "gridcell");
}
return rm;
},
createBlankCell = function(sIdSuffix, sClassSuffix) {
rm.openStart(sCellTag, sIdPrefix + sType + sIdSuffix);
sType == "Head" && rm.class("sapMTableTH");
rm.class(sClassPrefix + sClassSuffix);
rm.attr("role", "none");
rm.openEnd();
rm.close(sCellTag);
iIndex++;
};
if (sType == "Head") {
var oFirstVisibleColumn = aColumns.find(function(oColumn) {
return oColumn.getVisible();
});
var oForcedColumn = aColumns.reduce(function(oRefColumn, oColumn, iOrder) {
oColumn.setIndex(-1);
oColumn.setInitialOrder(iOrder);
oColumn.setForcedColumn(false);
return (oColumn.getVisible() && oColumn.getCalculatedMinScreenWidth() < oRefColumn.getCalculatedMinScreenWidth()) ? oColumn : oRefColumn;
}, oFirstVisibleColumn);
var iRenderedColumnsLength = aColumns.filter(function(oColumn) {
return oColumn.getVisible() && !oColumn.isHidden();
}).length;
if (!iRenderedColumnsLength && oForcedColumn) {
oForcedColumn.setForcedColumn(true);
iRenderedColumnsLength = 1;
}
if (iRenderedColumnsLength == 1 && vFixedLayout === "Strict") {
oTable._bCheckLastColumnWidth = true;
}
bHeaderHidden = !iRenderedColumnsLength || aColumns.every(function(oColumn) {
return !oColumn.getHeader() || !oColumn.getHeader().getVisible() || !oColumn.getVisible() || oColumn.isHidden();
});
}
rm.openStart(sTypeTag).class("sapMTableT" + sType).openEnd();
rm.openStart("tr", oTable.addNavSection(sIdPrefix + sType + "er"));
rm.attr("role", "row");
if (bHeaderHidden) {
rm.class("sapMListTblHeaderNone");
rm.attr("aria-hidden", "true");
} else {
rm.class("sapMListTblRow").class("sapMListTbl" + sType + "er");
if (Device.system.desktop) {
rm.attr("tabindex", "-1");
rm.class("sapMLIBFocusable").class("sapMTableRowCustomFocus");
}
if (sType == "Head") {
rm.attr("aria-rowindex", "1");
if (sMode === "MultiSelect" && sMultiSelectMode !== MultiSelectMode.ClearAll) {
rm.attr("aria-selected", "false");
bRenderAriaSelected = true;
}
} else {
rm.attr("aria-rowindex", oTable.getVisibleItems().length + !oTable._headerHidden + 1);
}
}
rm.openEnd();
createBlankCell("Highlight", "HighlightCol");
if (iModeOrder == -1) {
openStartCell("ModeCol", "SelCol", "TABLE_SELECTION_COLUMNHEADER");
if (sMode == "MultiSelect" && sType == "Head") {
const oBundle = Library.getResourceBundleFor("sap.m");
if (oTable.getMultiSelectMode() == MultiSelectMode.ClearAll) {
rm.attr("title", oBundle.getText("TABLE_CLEARBUTTON_TOOLTIP"))
.class("sapMTableClearAll")
.openEnd();
rm.renderControl(oTable._getClearAllIcon());
} else {
rm.attr("aria-description",
oBundle.getText("TABLE_SELECTION_COLUMNHEADER_DESCRIPTION") + " " + oBundle.getText("ACC_CTR_STATE_NOT_CHECKED"));
rm.openEnd();
rm.renderControl(oTable._getSelectAllCheckbox());
}
} else {
rm.openEnd();
}
rm.close(sCellTag);
iIndex++;
}
oTable.getColumns(true).forEach(function(oColumn) {
if (!oColumn.getVisible()) {
return;
}
if (oColumn.isPopin()) {
bHasPopin = true;
return;
}
if (oColumn.isHidden()) {
return;
}
var oControl = oColumn["get" + sType + "er"](),
sWidth = (iRenderedColumnsLength == 1 && vFixedLayout !== "Strict") ? "" : oColumn.getWidth(),
aStyleClass = oColumn.getStyleClass().split(" ").filter(Boolean),
sAlign = oColumn.getCssAlign(),
bActiveHeader = false;
if (sType == "Head") {
openStartCell(oColumn, "Cell");
var sSortIndicator = oColumn.getSortIndicator().toLowerCase();
if (sSortIndicator != "none") {
rm.attr("aria-sort", sSortIndicator);
}
if (oControl) {
var oMenu = oColumn.getHeaderMenuInstance();
bActiveHeader = (oMenu || oTable.bActiveHeaders) && !oControl.isA("sap.ui.core.InvisibleText");
if (bActiveHeader) {
rm.attr("aria-haspopup", oMenu ? oMenu.getAriaHasPopupType().toLowerCase() : "dialog");
bColumnHeadersActive = true;
}
if (oControl.getRequired?.()) {
rm.attr("aria-describedby", InvisibleText.getStaticId("sap.m", "CONTROL_IN_COLUMN_REQUIRED"));
}
}
if (!bHasFlexibleColumn) {
bHasFlexibleColumn = !sWidth || sWidth == "auto";
}
if (!bHasFooter) {
bHasFooter = !!oColumn.getFooter();
}
} else {
openStartCell(oColumn.getId() + "-footer", "Cell");
rm.style("text-align", sAlign);
}
aStyleClass.forEach(function (sClass) {
rm.class(sClass);
});
rm.class(sClassPrefix + sType + "erCell");
rm.attr("data-sap-ui-column", oColumn.getId());
rm.style("width", sWidth);
rm.openEnd();
if (oControl) {
if (sType === "Head") {
rm.openStart("div", oColumn.getId() + "-ah");
rm.class("sapMColumnHeader");
if (bActiveHeader) {
rm.class("sapMColumnHeaderActive");
}
if (sAlign) {
rm.style("justify-content", TableRenderer.columnAlign[sAlign]);
rm.style("text-align", sAlign);
}
rm.openEnd();
rm.renderControl(oColumn.getAggregation("_action"));
rm.renderControl(oControl.addStyleClass("sapMColumnHeaderContent"));
rm.close("div");
} else {
rm.renderControl(oControl);
}
}
rm.close(sCellTag);
oColumn.setIndex(iIndex++);
});
if (sType == "Head") {
oTable._dummyColumn = (bHasFlexibleColumn != undefined && !bHasFlexibleColumn && vFixedLayout === "Strict");
}
if (bHasPopin && oTable._dummyColumn) {
createBlankCell("DummyCell", "DummyCell");
}
const iActionCount = oTable._getItemActionCount();
if (iActionCount > 0) {
openStartCell("Actions", "ActionsCol", "TABLE_ROW_ACTIONS");
rm.class(`sapMTable${iActionCount}ActionsCol`);
rm.openEnd();
this.hideFromScreenReader(rm, "TABLE_ROW_ACTIONS");
rm.close(sCellTag);
iIndex++;
}
if (oTable.doItemsNeedTypeColumn()) {
openStartCell("Nav", "NavCol").openEnd();
this.hideFromScreenReader(rm, "TABLE_ROW_ACTIONS");
rm.close(sCellTag);
iIndex++;
}
if (iActionCount === -1 && iModeOrder == 1) {
openStartCell("ModeCol", "SelCol").openEnd();
this.hideFromScreenReader(rm, sMode == "Delete" ? "TABLE_ROW_ACTIONS" : "TABLE_SELECTION_COLUMNHEADER");
rm.close(sCellTag);
iIndex++;
}
createBlankCell("Navigated", "NavigatedCol");
if (!bHasPopin && oTable._dummyColumn) {
createBlankCell("DummyCell", "DummyCell");
}
rm.close("tr");
if (bHasPopin) {
var sPopinColumnHeaderId = sIdPrefix + "Popin" + sType;
rm.openStart("tr").attr("role", "none").openEnd();
rm.openStart("td").attr("role", "none").attr("colspan", iIndex).class("sapMTablePopinColumn").class("sapMTblItemNav").openEnd();
if (sType == "Head") {
rm.openStart("div", sPopinColumnHeaderId);
rm.class("sapMListTblHeaderNone");
rm.attr("role", sType == "Head" ? "columnheader" : "gridcell");
rm.attr("aria-colindex", aAriaOwns.push(sPopinColumnHeaderId));
rm.openEnd();
this.hideFromScreenReader(rm, "TABLE_COLUMNHEADER_POPIN");
rm.close("div");
}
rm.close("td");
rm.close("tr");
}
rm.close(sTypeTag);
if (sType === "Head") {
oTable._colCount = iIndex;
oTable._hasPopin = bHasPopin;
oTable._hasFooter = bHasFooter;
oTable._headerHidden = bHeaderHidden;
oTable._colHeaderAriaOwns = aAriaOwns;
oTable._columnHeadersActive = bColumnHeadersActive;
}
};
/**
* add table container class name
*/
TableRenderer.renderContainerAttributes = function(rm, oControl) {
rm.attr("data-sap-ui-pasteregion", "true");
rm.class("sapMListTblCnt");
};
/**
* render table tag and add required classes
*/
TableRenderer.renderListStartAttributes = function(rm, oControl) {
rm.openStart("table", oControl.getId("listUl"));
rm.accessibilityState(oControl, this.getAccessibilityState(oControl));
rm.attr("aria-roledescription", Library.getResourceBundleFor("sap.m").getText("TABLE_ROLE_DESCRIPTION"));
rm.class("sapMListTbl");
if (oControl.getFixedLayout() === false) {
rm.style("table-layout", "auto");
}
if (oControl.doItemsNeedTypeColumn()) {
rm.class("sapMListTblHasNav");
}
};
/**
* generate table columns
*/
TableRenderer.renderListHeadAttributes = function(rm, oControl) {
oControl._aPopinHeaders = [];
this.renderColumns(rm, oControl, "Head");
rm.openStart("tbody", oControl.addNavSection(oControl.getId("tblBody")));
rm.class("sapMListItems");
rm.class("sapMTableTBody");
if (oControl.hasPopin()) {
rm.class("sapMListTblHasPopin");
}
rm.openEnd();
};
/**
* render footer and finish rendering table
*/
TableRenderer.renderListEndAttributes = function(rm, oControl) {
rm.close("tbody"); // items should be rendered before foot
oControl._hasFooter && this.renderColumns(rm, oControl, "Foot");
rm.close("table");
// render popin headers in a separate div element for ACC
this.renderPopinColumnHeaders(rm, oControl);
};
/**
* Renders the actual column header control that is moved to the pop-in area.
* This ensure correct accessibility mappings to focusable content in the pop-in area.
* @param {sap.ui.core.RenderManager} rm RenderManager instance
* @param {sap.m.Table} oControl the table instance
*/
TableRenderer.renderPopinColumnHeaders = function(rm, oControl) {
if (!oControl._aPopinHeaders || !oControl._aPopinHeaders.length) {
return;
}
rm.openStart("div", oControl.getId("popin-headers"));
rm.class("sapMTablePopinHeaders");
rm.attr("aria-hidden", "true");
rm.openEnd();
oControl._aPopinHeaders.forEach(function(oHeader) {
rm.renderControl(oHeader);
});
rm.close("div");
};
/**
* render no data
*/
TableRenderer.renderNoData = function(rm, oControl) {
rm.openStart("tr", oControl.getId("nodata"));
rm.class("sapMLIB").class("sapMListTblRow").class("sapMLIBTypeInactive").class("sapMListTblRowNoData");
if (Device.system.desktop) {
rm.attr("tabindex", "-1");
rm.class("sapMLIBFocusable");
}
if (!oControl._headerHidden || (!oControl.getHeaderText() && !oControl.getHeaderToolbar())) {
rm.class("sapMLIBShowSeparator");
}
rm.openEnd();
rm.openStart("td", oControl.getId("nodata-text"));
rm.attr("colspan", oControl.getColCount()); // no data cell must span all columns
rm.class("sapMListTblCell").class("sapMListTblCellNoData");
if (oControl.getNoData() === null || ( typeof oControl.getNoData() === "string" || !oControl.getNoData().isA("sap.m.IllustratedMessage"))) {
rm.class("sapMListTblCellNoIllustratedMessage");
}
rm.openEnd();
if (!oControl.shouldRenderItems()) {
if (oControl.getAggregation("_noColumnsMessage")) {
// If _noColumnsMessage is set, there is for sure an IllustratedMessage used for no data visualization
rm.renderControl(oControl.getAggregation("_noColumnsMessage"));
} else {
rm.text(Library.getResourceBundleFor("sap.m").getText("TABLE_NO_COLUMNS"));
}
} else {
this.renderNoDataArea(rm, oControl);
}
rm.close("td");
rm.close("tr");
};
TableRenderer.hideFromScreenReader = function(rm, sBundleKey) {
rm.openStart("div").class("sapMTableScreenReaderOnly").openEnd();
rm.text(Library.getResourceBundleFor("sap.m").getText(sBundleKey));
rm.close("div");
};
return TableRenderer;
}, /* bExport= */ true);