@openui5/sap.ui.table 1.143.1 → 1.144.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (78) hide show
  1. package/THIRDPARTY.txt +1 -1
  2. package/package.json +3 -3
  3. package/src/sap/ui/table/.library +2 -2
  4. package/src/sap/ui/table/AnalyticalColumn.js +2 -2
  5. package/src/sap/ui/table/AnalyticalColumnMenu.js +2 -2
  6. package/src/sap/ui/table/AnalyticalTable.js +2 -2
  7. package/src/sap/ui/table/Column.js +2 -2
  8. package/src/sap/ui/table/ColumnMenu.js +2 -2
  9. package/src/sap/ui/table/CreationRow.js +2 -2
  10. package/src/sap/ui/table/CreationRowRenderer.js +2 -2
  11. package/src/sap/ui/table/HeaderSelector.js +90 -0
  12. package/src/sap/ui/table/HeaderSelectorRenderer.js +88 -0
  13. package/src/sap/ui/table/Row.js +2 -2
  14. package/src/sap/ui/table/RowAction.js +2 -2
  15. package/src/sap/ui/table/RowActionItem.js +2 -2
  16. package/src/sap/ui/table/RowActionRenderer.js +1 -1
  17. package/src/sap/ui/table/RowSettings.js +2 -2
  18. package/src/sap/ui/table/Table.js +37 -60
  19. package/src/sap/ui/table/TablePersoController.js +2 -2
  20. package/src/sap/ui/table/TableRenderer.js +1624 -718
  21. package/src/sap/ui/table/TreeTable.js +2 -2
  22. package/src/sap/ui/table/designtime/AnalyticalTable.designtime.js +5 -1
  23. package/src/sap/ui/table/designtime/Table.designtime.js +5 -1
  24. package/src/sap/ui/table/designtime/library.designtime.js +1 -1
  25. package/src/sap/ui/table/designtime/messagebundle.properties +6 -0
  26. package/src/sap/ui/table/extensions/Accessibility.js +28 -53
  27. package/src/sap/ui/table/extensions/AccessibilityRender.js +3 -4
  28. package/src/sap/ui/table/extensions/DragAndDrop.js +2 -2
  29. package/src/sap/ui/table/extensions/ExtensionBase.js +2 -2
  30. package/src/sap/ui/table/extensions/Keyboard.js +5 -31
  31. package/src/sap/ui/table/extensions/KeyboardDelegate.js +2 -2
  32. package/src/sap/ui/table/extensions/Pointer.js +2 -2
  33. package/src/sap/ui/table/extensions/Scrolling.js +2 -10
  34. package/src/sap/ui/table/extensions/ScrollingIOS.js +2 -2
  35. package/src/sap/ui/table/extensions/Synchronization.js +16 -18
  36. package/src/sap/ui/table/library.js +11 -11
  37. package/src/sap/ui/table/library.support.js +1 -1
  38. package/src/sap/ui/table/menus/AnalyticalTableContextMenu.js +2 -2
  39. package/src/sap/ui/table/menus/ColumnHeaderMenuAdapter.js +2 -2
  40. package/src/sap/ui/table/menus/ContextMenu.js +2 -2
  41. package/src/sap/ui/table/menus/LegacyColumnMenuAdapter.js +1 -1
  42. package/src/sap/ui/table/menus/MobileColumnHeaderMenuAdapter.js +2 -2
  43. package/src/sap/ui/table/plugins/BindingSelection.js +27 -13
  44. package/src/sap/ui/table/plugins/MultiSelectionPlugin.js +63 -52
  45. package/src/sap/ui/table/plugins/ODataV4Aggregation.js +2 -2
  46. package/src/sap/ui/table/plugins/ODataV4Hierarchy.js +2 -2
  47. package/src/sap/ui/table/plugins/ODataV4MultiLevel.js +2 -2
  48. package/src/sap/ui/table/plugins/ODataV4MultiSelection.js +78 -71
  49. package/src/sap/ui/table/plugins/ODataV4Selection.js +2 -2
  50. package/src/sap/ui/table/plugins/ODataV4SingleSelection.js +2 -2
  51. package/src/sap/ui/table/plugins/PluginBase.js +2 -2
  52. package/src/sap/ui/table/plugins/SelectionModelSelection.js +26 -13
  53. package/src/sap/ui/table/plugins/SelectionPlugin.js +16 -14
  54. package/src/sap/ui/table/rowmodes/Auto.js +5 -13
  55. package/src/sap/ui/table/rowmodes/Fixed.js +3 -4
  56. package/src/sap/ui/table/rowmodes/Interactive.js +21 -27
  57. package/src/sap/ui/table/rowmodes/RowMode.js +20 -88
  58. package/src/sap/ui/table/rowmodes/Type.js +1 -1
  59. package/src/sap/ui/table/rowmodes/Variable.js +2 -2
  60. package/src/sap/ui/table/rules/Accessibility.support.js +1 -1
  61. package/src/sap/ui/table/rules/Binding.support.js +1 -1
  62. package/src/sap/ui/table/rules/ColumnTemplate.support.js +1 -1
  63. package/src/sap/ui/table/rules/Plugins.support.js +1 -1
  64. package/src/sap/ui/table/rules/Rows.support.js +1 -1
  65. package/src/sap/ui/table/rules/TableHelper.support.js +1 -1
  66. package/src/sap/ui/table/themes/base/Cell.less +26 -16
  67. package/src/sap/ui/table/themes/base/CheckBox.less +51 -0
  68. package/src/sap/ui/table/themes/base/HeaderSelector.less +61 -0
  69. package/src/sap/ui/table/themes/base/RowSelection.less +9 -138
  70. package/src/sap/ui/table/themes/base/library.source.less +3 -1
  71. package/src/sap/ui/table/themes/sap_hcb/base_Cell.less +1 -1
  72. package/src/sap/ui/table/themes/sap_hcb/base_RowSelection.less +1 -1
  73. package/src/sap/ui/table/themes/sap_hcb/library.source.less +1 -1
  74. package/src/sap/ui/table/utils/TableUtils.js +2 -2
  75. package/src/sap/ui/table/utils/_ColumnUtils.js +2 -2
  76. package/src/sap/ui/table/utils/_GroupingUtils.js +2 -2
  77. package/src/sap/ui/table/utils/_HookUtils.js +2 -2
  78. package/src/sap/ui/table/utils/_MenuUtils.js +2 -2
@@ -1,33 +1,29 @@
1
1
  /*!
2
2
  * OpenUI5
3
- * (c) Copyright 2025 SAP SE or an SAP affiliate company.
3
+ * (c) Copyright 2026 SAP SE or an SAP affiliate company.
4
4
  * Licensed under the Apache License, Version 2.0 - see LICENSE.txt.
5
5
  */
6
6
 
7
- //Provides default renderer for control sap.ui.table.Table
8
7
  sap.ui.define([
9
- "sap/ui/Device",
10
- "./library",
11
8
  "./Column",
12
9
  "./utils/TableUtils",
13
10
  "./extensions/ExtensionBase",
14
11
  "sap/ui/core/Renderer",
15
12
  "sap/ui/core/library",
13
+ "sap/ui/Device",
16
14
  "sap/base/Log"
17
15
  ], function(
18
- Device,
19
- library,
20
16
  Column,
21
17
  TableUtils,
22
18
  ExtensionBase,
23
19
  Renderer,
24
20
  CoreLibrary,
21
+ Device,
25
22
  Log
26
23
  ) {
27
24
  "use strict";
28
25
 
29
26
  const SortOrder = CoreLibrary.SortOrder;
30
- const ColumnUtils = TableUtils.Column;
31
27
  const mFlexCellContentAlignment = {
32
28
  Begin: "flex-start",
33
29
  End: "flex-end",
@@ -48,10 +44,11 @@ sap.ui.define([
48
44
  };
49
45
 
50
46
  /**
51
- * Renders the HTML for the given control, using the provided {@link sap.ui.core.RenderManager}.
47
+ * Renders the table.
52
48
  *
53
- * @param {sap.ui.core.RenderManager} rm The RenderManager that can be used for writing to the Render-Output-Buffer.
54
- * @param {sap.ui.table.Table} oTable The instance of the table that should be rendered.
49
+ * @param {sap.ui.core.RenderManager} rm RenderManager instance
50
+ * @param {sap.ui.table.Table} oTable Table instance
51
+ * @private
55
52
  */
56
53
  TableRenderer.render = function(rm, oTable) {
57
54
  // Clear cashed header row count
@@ -60,10 +57,47 @@ sap.ui.define([
60
57
  mFlexCellContentAlignment.Left = oTable._bRtlMode ? "flex-end" : "flex-start";
61
58
  mFlexCellContentAlignment.Right = oTable._bRtlMode ? "flex-start" : "flex-end";
62
59
 
63
- // basic table div
64
60
  rm.openStart("div", oTable);
61
+ this._decorateRootElement(rm, oTable);
62
+ rm.openEnd();
63
+ this.renderTabElement(rm, {className: "sapUiTableOuterBefore"});
64
+ this._renderTopSection(rm, oTable);
65
+ this._renderMainSection(rm, oTable);
66
+ this._renderBottomSection(rm, oTable);
67
+ this.renderTabElement(rm, {className: "sapUiTableOuterAfter"});
68
+ rm.close("div");
69
+ };
70
+
71
+ /**
72
+ * Decorates the table's root element with attributes, styles and CSS classes.
73
+ *
74
+ * @param {sap.ui.core.RenderManager} rm RenderManager instance
75
+ * @param {sap.ui.table.Table} oTable Table instance
76
+ * @private
77
+ */
78
+ TableRenderer._decorateRootElement = function(rm, oTable) {
65
79
  rm.class("sapUiTable");
66
80
 
81
+ this._addBrowserSpecificClasses(rm);
82
+ this._addTableStateClasses(rm, oTable);
83
+ /** @deprecated As of version 1.118 */
84
+ this._addDeprecatedClasses(rm, oTable);
85
+
86
+ if (oTable._bFirstRendering) {
87
+ rm.class("sapUiTableNoOpacity");
88
+ }
89
+
90
+ rm.style("width", oTable.getWidth());
91
+ TableUtils.Hook.call(oTable, Hook.RenderTableStyles, rm);
92
+ };
93
+
94
+ /**
95
+ * Adds browser or environment specific CSS classes.
96
+ *
97
+ * @param {sap.ui.core.RenderManager} rm RenderManager instance
98
+ * @private
99
+ */
100
+ TableRenderer._addBrowserSpecificClasses = function(rm) {
67
101
  if (Device.browser.chrome && window.devicePixelRatio < 1) {
68
102
  rm.class("sapUiTableZoomout");
69
103
  }
@@ -71,23 +105,87 @@ sap.ui.define([
71
105
  if ('ontouchstart' in document) {
72
106
  rm.class("sapUiTableTouch");
73
107
  }
108
+ };
109
+
110
+ /**
111
+ * Adds table state related CSS classes.
112
+ *
113
+ * @param {sap.ui.core.RenderManager} rm RenderManager instance
114
+ * @param {sap.ui.table.Table} oTable Table instance
115
+ * @private
116
+ */
117
+ TableRenderer._addTableStateClasses = function(rm, oTable) {
74
118
  rm.class("sapUiTableSelMode" + oTable.getSelectionMode());
75
119
 
76
120
  if (oTable.getColumnHeaderVisible()) {
77
- rm.class("sapUiTableCHdr"); // show column headers
121
+ rm.class("sapUiTableCHdr");
78
122
  }
79
123
  if (TableUtils.hasRowHeader(oTable)) {
80
- rm.class("sapUiTableRowSelectors"); // show row selectors
124
+ rm.class("sapUiTableRowSelectors");
81
125
  }
82
126
  if (TableUtils.hasRowHighlights(oTable)) {
83
- rm.class("sapUiTableRowHighlights"); // show row highlights
127
+ rm.class("sapUiTableRowHighlights");
84
128
  }
129
+ if (TableUtils.isNoDataVisible(oTable) && !oTable._isWaitingForData()) {
130
+ rm.class("sapUiTableEmpty");
131
+ }
132
+ if (oTable.getShowOverlay()) {
133
+ rm.class("sapUiTableOverlay");
134
+ }
135
+
136
+ const oScrollExtension = oTable._getScrollExtension();
137
+ if (oScrollExtension.isVerticalScrollbarRequired() && !oScrollExtension.isVerticalScrollbarExternal()) {
138
+ rm.class("sapUiTableVScr");
139
+ }
140
+
141
+ this._addRowActionClasses(rm, oTable);
142
+
143
+ const sModeClass = TableUtils.Grouping.getModeCssClass(oTable);
144
+ if (sModeClass) {
145
+ rm.class(sModeClass);
146
+ }
147
+ };
85
148
 
149
+ /**
150
+ * Adds CSS classes indicating available row actions or navigation indicators.
151
+ *
152
+ * @param {sap.ui.core.RenderManager} rm RenderManager instance
153
+ * @param {sap.ui.table.Table} oTable Table instance
154
+ * @private
155
+ */
156
+ TableRenderer._addRowActionClasses = function(rm, oTable) {
157
+ if (TableUtils.hasRowActions(oTable)) {
158
+ rm.class("sapUiTableRAct");
159
+ switch (oTable.getRowActionCount()) {
160
+ case 1:
161
+ rm.class("sapUiTableRActS");
162
+ break;
163
+ case 2:
164
+ rm.class("sapUiTableRActM");
165
+ break;
166
+ default:
167
+ rm.class("sapUiTableRActL");
168
+ }
169
+ }
170
+
171
+ if (TableUtils.hasRowNavigationIndicators(oTable)) {
172
+ rm.class("sapUiTableRowNavIndicator");
173
+ }
174
+ };
175
+
176
+ /**
177
+ * Adds deprecated CSS classes for backward compatibility.
178
+ *
179
+ * @param {sap.ui.core.RenderManager} rm RenderManager instance
180
+ * @param {sap.ui.table.Table} oTable Table instance
181
+ * @private
182
+ * @deprecated As of version 1.118
183
+ */
184
+ TableRenderer._addDeprecatedClasses = function(rm, oTable) {
86
185
  /**
87
186
  * @deprecated As of version 1.118
88
187
  */
89
188
  try {
90
- // This class flags whether the sap.m. library is loaded or not.
91
189
  const sSapMTableClass = TableUtils._getTableTemplateHelper(true).addTableClass();
92
190
  if (sSapMTableClass) {
93
191
  rm.class(sSapMTableClass);
@@ -96,108 +194,67 @@ sap.ui.define([
96
194
  // ignore
97
195
  }
98
196
 
99
- const oScrollExtension = oTable._getScrollExtension();
100
- const oAccRenderExtension = oTable._getAccRenderExtension();
101
- if (oScrollExtension.isVerticalScrollbarRequired() && !oScrollExtension.isVerticalScrollbarExternal()) {
102
- rm.class("sapUiTableVScr"); // show vertical scrollbar
103
- }
104
197
  /**
105
198
  * @deprecated As of Version 1.115
106
199
  */
107
200
  if (oTable.getEditable && oTable.getEditable()) {
108
- rm.class("sapUiTableEdt"); // editable (background color)
109
- }
110
-
111
- if (TableUtils.hasRowActions(oTable)) {
112
- rm.class("sapUiTableRAct");
113
- const iRowActionCount = oTable.getRowActionCount();
114
- if (iRowActionCount === 1) {
115
- rm.class("sapUiTableRActS");
116
- } else if (iRowActionCount === 2) {
117
- rm.class("sapUiTableRActM");
118
- } else {
119
- rm.class("sapUiTableRActL");
120
- }
121
- } else if (TableUtils.hasRowNavigationIndicators(oTable)) {
122
- rm.class("sapUiTableRowNavIndicator");
123
- }
124
-
125
- if (TableUtils.isNoDataVisible(oTable) && !oTable._isWaitingForData()) {
126
- rm.class("sapUiTableEmpty"); // no data!
127
- }
128
-
129
- if (oTable.getShowOverlay()) {
130
- rm.class("sapUiTableOverlay");
131
- }
132
-
133
- const sModeClass = TableUtils.Grouping.getModeCssClass(oTable);
134
- if (sModeClass) {
135
- rm.class(sModeClass);
136
- }
137
-
138
- rm.style("width", oTable.getWidth());
139
-
140
- TableUtils.Hook.call(oTable, Hook.RenderTableStyles, rm);
141
-
142
- if (oTable._bFirstRendering) {
143
- // This class hides the table by setting opacity to 0. It will be removed in Table#_updateTableSizes.
144
- // Makes initial asynchronous renderings a bit nicer, because the table only shows up after everything is done.
145
- rm.class("sapUiTableNoOpacity");
201
+ rm.class("sapUiTableEdt");
146
202
  }
203
+ };
147
204
 
148
- rm.openEnd();
149
-
150
- this.renderTabElement(rm, "sapUiTableOuterBefore");
151
-
205
+ /**
206
+ * Renders the top area containing, for example, extensions.
207
+ *
208
+ * @param {sap.ui.core.RenderManager} rm RenderManager instance
209
+ * @param {sap.ui.table.Table} oTable Table instance
210
+ * @private
211
+ */
212
+ TableRenderer._renderTopSection = function(rm, oTable) {
152
213
  rm.openStart("div", oTable.getId() + "-before");
153
214
  rm.class("sapUiTableBefore");
154
215
  rm.openEnd();
155
-
156
216
  rm.renderControl(oTable.getAggregation("_messageStrip"));
157
-
158
- if (oTable.getTitle()) {
159
- this.renderHeader(rm, oTable, oTable.getTitle());
160
- }
161
-
162
- if (oTable.getToolbar()) {
163
- this.renderToolbar(rm, oTable, oTable.getToolbar());
164
- }
165
-
166
- if (oTable.getExtension() && oTable.getExtension().length > 0) {
167
- this.renderExtensions(rm, oTable, oTable.getExtension());
168
- }
169
-
217
+ /** @deprecated As of version 1.72 */
218
+ this.renderHeader(rm, oTable);
219
+ /** @deprecated As of version 1.38 */
220
+ this.renderToolbar(rm, oTable);
221
+ this.renderExtensions(rm, oTable);
170
222
  rm.close("div");
223
+ };
224
+
225
+ /**
226
+ * Renders the main content area containing the actual table.
227
+ *
228
+ * @param {sap.ui.core.RenderManager} rm RenderManager instance
229
+ * @param {sap.ui.table.Table} oTable Table instance
230
+ * @private
231
+ */
232
+ TableRenderer._renderMainSection = function(rm, oTable) {
233
+ const oAccRenderExtension = oTable._getAccRenderExtension();
234
+ const bHasFocusableContent = oTable.getRows().length || oTable.getColumnHeaderVisible();
171
235
 
172
236
  rm.openStart("div", oTable.getId() + "-sapUiTableCnt");
173
237
  rm.class("sapUiTableCnt");
174
-
175
- // Define group for F6 handling
176
238
  rm.attr("data-sap-ui-fastnavgroup", "true");
177
- // Define the paste region for the paste event
178
239
  rm.attr("data-sap-ui-pasteregion", "true");
179
-
180
240
  rm.openEnd();
181
241
 
182
242
  if (!oTable._getScrollExtension().isVerticalScrollbarExternal()) {
183
243
  this.renderVSb(rm, oTable);
184
244
  }
185
245
 
186
- const bDummyTabbable = oTable.getRows().length || oTable.getColumnHeaderVisible();
187
- this.renderTabElement(rm, "sapUiTableCtrlBefore", bDummyTabbable ? "0" : "-1");
246
+ this.renderTabElement(rm, {className: "sapUiTableCtrlBefore", tabIndex: bHasFocusableContent ? "0" : "-1"});
188
247
 
189
248
  rm.openStart("div", oTable.getId() + "-sapUiTableGridCnt");
190
249
  oAccRenderExtension.writeAriaAttributesFor(rm, oTable, "Content");
191
250
  rm.openEnd();
192
-
193
- this.renderColRsz(rm, oTable);
194
- this.renderColHdr(rm, oTable);
251
+ this.renderColumnResizer(rm, oTable);
252
+ this.renderColumnHeader(rm, oTable);
195
253
  this.renderTable(rm, oTable);
196
-
197
254
  rm.close("div");
198
255
 
199
- this.renderTabElement(rm, "sapUiTableCtrlAfter", bDummyTabbable ? "0" : "-1");
200
- this.renderTabElement(rm, null, "-1", oTable.getId() + "-focusDummy");
256
+ this.renderTabElement(rm, {className: "sapUiTableCtrlAfter", tabIndex: bHasFocusableContent ? "0" : "-1"});
257
+ this.renderTabElement(rm, {tabIndex: "-1", id: oTable.getId() + "-focusDummy"});
201
258
 
202
259
  const oCreationRow = oTable.getCreationRow();
203
260
  if (oCreationRow && oCreationRow.getVisible()) {
@@ -206,50 +263,119 @@ sap.ui.define([
206
263
 
207
264
  this.renderHSbBackground(rm, oTable);
208
265
  this.renderHSb(rm, oTable);
209
-
266
+ this._renderOverlay(rm, oTable);
210
267
  oAccRenderExtension.writeHiddenAccTexts(rm, oTable);
211
268
 
269
+ rm.close("div");
270
+ };
271
+
272
+ /**
273
+ * Renders the column resize handle.
274
+ *
275
+ * @param {sap.ui.core.RenderManager} rm RenderManager instance
276
+ * @param {sap.ui.table.Table} oTable Table instance
277
+ * @private
278
+ */
279
+ TableRenderer.renderColumnResizer = function(rm, oTable) {
280
+ rm.openStart("div", oTable.getId() + "-rsz");
281
+ rm.class("sapUiTableColRsz");
282
+ rm.openEnd();
283
+ rm.close("div");
284
+ };
285
+
286
+ /**
287
+ * Renders the column header rows.
288
+ *
289
+ * @param {sap.ui.core.RenderManager} rm RenderManager instance
290
+ * @param {sap.ui.table.Table} oTable Table instance
291
+ * @private
292
+ */
293
+ TableRenderer.renderColumnHeader = function(rm, oTable) {
294
+ const iHeaderRowCount = TableUtils.getHeaderRowCount(oTable);
295
+ const iFixedColumnCount = oTable.getComputedFixedColumnCount();
296
+
297
+ rm.openStart("div", oTable.getId() + "-sapUiTableColHdrCnt");
298
+ rm.class("sapUiTableColHdrCnt");
299
+ rm.openEnd();
300
+ this._renderSelectionHeader(rm, oTable);
301
+ this._renderFixedColumnHeader(rm, oTable, {
302
+ fixedColumnCount: iFixedColumnCount,
303
+ headerRowCount: iHeaderRowCount
304
+ });
305
+ this._renderScrollableColumnHeader(rm, oTable, {
306
+ fixedColumnCount: iFixedColumnCount,
307
+ headerRowCount: iHeaderRowCount
308
+ });
309
+ this._renderRowActionHeader(rm, oTable);
310
+ this._renderVSbHeader(rm);
311
+ rm.close("div");
312
+ };
313
+
314
+ /**
315
+ * Renders the overlay area.
316
+ *
317
+ * @param {sap.ui.core.RenderManager} rm RenderManager instance
318
+ * @param {sap.ui.table.Table} oTable Table instance
319
+ * @private
320
+ */
321
+ TableRenderer._renderOverlay = function(rm, oTable) {
212
322
  rm.openStart("div", oTable.getId() + "-overlay");
213
323
  rm.class("sapUiTableOverlayArea");
214
324
  rm.attr("tabindex", "0");
215
- oAccRenderExtension.writeAriaAttributesFor(rm, oTable, "Overlay");
325
+ oTable._getAccRenderExtension().writeAriaAttributesFor(rm, oTable, "Overlay");
216
326
  rm.openEnd();
217
327
  rm.close("div");
328
+ };
218
329
 
219
- rm.close("div");
220
-
330
+ /**
331
+ * Renders the bottom area containing, for example, the footer.
332
+ *
333
+ * @param {sap.ui.core.RenderManager} rm RenderManager instance
334
+ * @param {sap.ui.table.Table} oTable Table instance
335
+ * @private
336
+ */
337
+ TableRenderer._renderBottomSection = function(rm, oTable) {
221
338
  rm.openStart("div", oTable.getId() + "-after");
222
339
  rm.openEnd();
223
-
224
- if (oTable.getFooter()) {
225
- this.renderFooter(rm, oTable, oTable.getFooter());
226
- }
227
-
340
+ this.renderFooter(rm, oTable);
228
341
  TableUtils.Hook.call(oTable, Hook.RenderInTableBottomArea, rm);
229
-
230
- rm.close("div");
231
-
232
- this.renderTabElement(rm, "sapUiTableOuterAfter");
233
342
  rm.close("div");
234
343
  };
235
344
 
236
- // =============================================================================
237
- // BASIC AREAS OF THE TABLE
238
- // =============================================================================
345
+ /**
346
+ * Renders the table header container.
347
+ *
348
+ * @param {sap.ui.core.RenderManager} rm RenderManager instance
349
+ * @param {sap.ui.table.Table} oTable Table instance
350
+ * @deprecated As of version 1.72
351
+ * @private
352
+ */
353
+ TableRenderer.renderHeader = function(rm, oTable) {
354
+ const oTitle = oTable.getTitle();
355
+
356
+ if (!oTitle) {
357
+ return;
358
+ }
239
359
 
240
- /** @deprecated As of version 1.72 */
241
- TableRenderer.renderHeader = function(rm, oTable, oTitle) {
242
360
  rm.openStart("div");
243
361
  rm.class("sapUiTableHdr");
244
362
  oTable._getAccRenderExtension().writeAriaAttributesFor(rm, oTable, "TableHeader");
245
363
  rm.openEnd();
246
-
247
364
  rm.renderControl(oTitle);
248
-
249
365
  rm.close("div");
250
366
  };
251
367
 
252
- TableRenderer.renderToolbar = function(rm, oTable, oToolbar) {
368
+ /**
369
+ * Renders the toolbar of the table.
370
+ *
371
+ * @param {sap.ui.core.RenderManager} rm RenderManager instance
372
+ * @param {sap.ui.table.Table} oTable Table instance
373
+ * @deprecated As of version 1.38
374
+ * @private
375
+ */
376
+ TableRenderer.renderToolbar = function(rm, oTable) {
377
+ const oToolbar = oTable.getToolbar();
378
+
253
379
  if (!TableUtils.isA(oToolbar, "sap.ui.core.Toolbar")) {
254
380
  return;
255
381
  }
@@ -257,7 +383,6 @@ sap.ui.define([
257
383
  rm.openStart("div");
258
384
  rm.class("sapUiTableTbr");
259
385
 
260
- // toolbar has to be embedded (not standalone)!
261
386
  if (typeof oToolbar.getStandalone === "function" && oToolbar.getStandalone()) {
262
387
  oToolbar.setStandalone(false);
263
388
  }
@@ -275,38 +400,96 @@ sap.ui.define([
275
400
  rm.close("div");
276
401
  };
277
402
 
278
- TableRenderer.renderExtensions = function(rm, oTable, aExtensions) {
279
- for (let i = 0, l = aExtensions.length; i < l; i++) {
280
- this.renderExtension(rm, oTable, aExtensions[i]);
403
+ /**
404
+ * Renders all extension controls of the table.
405
+ *
406
+ * @param {sap.ui.core.RenderManager} rm RenderManager instance
407
+ * @param {sap.ui.table.Table} oTable Table instance providing the extensions
408
+ * @private
409
+ */
410
+ TableRenderer.renderExtensions = function(rm, oTable) {
411
+ for (const oExtension of oTable.getExtension() ?? []) {
412
+ this.renderExtension(rm, oTable, oExtension);
281
413
  }
282
414
  };
283
415
 
416
+ /**
417
+ * Renders one extension control.
418
+ *
419
+ * @param {sap.ui.core.RenderManager} rm RenderManager instance
420
+ * @param {sap.ui.table.Table} oTable Table instance
421
+ * @param {sap.ui.core.Control} oExtension Extension control
422
+ * @private
423
+ */
284
424
  TableRenderer.renderExtension = function(rm, oTable, oExtension) {
285
425
  rm.openStart("div");
286
426
  rm.class("sapUiTableExt");
287
427
  oTable._getAccRenderExtension().writeAriaAttributesFor(rm, oTable, "TableSubHeader");
288
428
  rm.openEnd();
289
-
290
429
  rm.renderControl(oExtension);
430
+ rm.close("div");
431
+ };
432
+
433
+ /**
434
+ * Renders the footer of the table.
435
+ *
436
+ * @param {sap.ui.core.RenderManager} rm RenderManager instance
437
+ * @param {sap.ui.table.Table} oTable Table instance
438
+ * @private
439
+ */
440
+ TableRenderer.renderFooter = function(rm, oTable) {
441
+ const oFooter = oTable.getFooter();
442
+
443
+ if (!oFooter) {
444
+ return;
445
+ }
291
446
 
447
+ rm.openStart("div");
448
+ rm.class("sapUiTableFtr");
449
+ oTable._getAccRenderExtension().writeAriaAttributesFor(rm, oTable, "TableFooter");
450
+ rm.openEnd();
451
+ rm.renderControl(oFooter);
292
452
  rm.close("div");
293
453
  };
294
454
 
455
+ /**
456
+ * Renders the area containing the content rows.
457
+ *
458
+ * @param {sap.ui.core.RenderManager} rm RenderManager instance
459
+ * @param {sap.ui.table.Table} oTable Table instance
460
+ * @private
461
+ */
295
462
  TableRenderer.renderTable = function(rm, oTable) {
296
463
  rm.openStart("div", oTable.getId() + "-tableCCnt");
297
464
  TableUtils.Hook.call(oTable, Hook.RenderRowContainerStyles, rm);
298
465
  rm.class("sapUiTableCCnt");
299
466
  rm.openEnd();
300
-
301
467
  this.renderTableCCnt(rm, oTable);
302
468
  rm.close("div");
303
469
  };
304
470
 
471
+ /**
472
+ * Renders the table content components.
473
+ *
474
+ * @param {sap.ui.core.RenderManager} rm RenderManager instance
475
+ * @param {sap.ui.table.Table} oTable Table instance
476
+ * @private
477
+ */
305
478
  TableRenderer.renderTableCCnt = function(rm, oTable) {
306
479
  this.renderTableCtrl(rm, oTable);
307
- this.renderRowHdr(rm, oTable);
480
+ this.renderRowHeader(rm, oTable);
308
481
  this.renderRowActions(rm, oTable);
482
+ this._renderNoData(rm, oTable);
483
+ };
309
484
 
485
+ /**
486
+ * Renders the NoData element.
487
+ *
488
+ * @param {sap.ui.core.RenderManager} rm RenderManager instance
489
+ * @param {sap.ui.table.Table} oTable Table instance
490
+ * @private
491
+ */
492
+ TableRenderer._renderNoData = function(rm, oTable) {
310
493
  rm.openStart("div", oTable.getId() + "-noDataCnt");
311
494
  rm.class("sapUiTableCtrlEmpty");
312
495
  rm.attr("tabindex", "0");
@@ -328,94 +511,126 @@ sap.ui.define([
328
511
  rm.close("div");
329
512
  };
330
513
 
331
- TableRenderer.renderFooter = function(rm, oTable, oFooter) {
514
+ /**
515
+ * Renders the fixed columns portion of the column header if there are fixed columns.
516
+ *
517
+ * @param {sap.ui.core.RenderManager} rm RenderManager instance
518
+ * @param {sap.ui.table.Table} oTable Table instance
519
+ * @param {object} mConfig Configuration object
520
+ * @param {int} mConfig.fixedColumnCount Number of fixed columns
521
+ * @param {int} mConfig.headerRowCount Number of header rows
522
+ * @private
523
+ */
524
+ TableRenderer._renderFixedColumnHeader = function(rm, oTable, mConfig) {
525
+ if (mConfig.fixedColumnCount === 0) {
526
+ return;
527
+ }
528
+
332
529
  rm.openStart("div");
333
- rm.class("sapUiTableFtr");
334
- oTable._getAccRenderExtension().writeAriaAttributesFor(rm, oTable, "TableFooter");
530
+ rm.class("sapUiTableCHA"); // marker for the column header area
531
+ rm.class("sapUiTableCtrlScrFixed");
532
+ rm.class("sapUiTableNoOpacity");
335
533
  rm.openEnd();
336
-
337
- rm.renderControl(oFooter);
338
-
534
+ this.renderTableElement(rm, oTable, {
535
+ fixedColumns: true,
536
+ startColumnIndex: 0,
537
+ endColumnIndex: mConfig.fixedColumnCount,
538
+ fixedTopRows: true,
539
+ fixedBottomRows: false,
540
+ startRowIndex: 0,
541
+ endRowIndex: mConfig.headerRowCount,
542
+ header: true
543
+ });
339
544
  rm.close("div");
340
545
  };
341
546
 
342
- // =============================================================================
343
- // COLUMN HEADER OF THE TABLE
344
- // =============================================================================
345
-
346
- TableRenderer.renderColHdr = function(rm, oTable) {
347
- const nRows = TableUtils.getHeaderRowCount(oTable);
348
- const aCols = oTable.getColumns();
349
- const iFixedColumnCount = oTable.getComputedFixedColumnCount();
350
-
351
- rm.openStart("div", oTable.getId() + "-sapUiTableColHdrCnt");
352
- rm.class("sapUiTableColHdrCnt");
353
- rm.openEnd();
354
-
355
- this.renderColRowHdr(rm, oTable);
356
-
357
- if (iFixedColumnCount > 0) {
358
- rm.openStart("div");
359
- rm.class("sapUiTableCHA"); // marker for the column header area
360
- rm.class("sapUiTableCtrlScrFixed");
361
- rm.class("sapUiTableNoOpacity");
362
- rm.openEnd();
363
-
364
- //
365
- // write fixed table here
366
- //
367
- this.renderTableControlCnt(rm, oTable, true, 0, iFixedColumnCount, true, false, 0, nRows, true);
368
- rm.close("div");
369
- }
547
+ /**
548
+ * Renders the scrollable portion of the column header.
549
+ *
550
+ * @param {sap.ui.core.RenderManager} rm RenderManager instance
551
+ * @param {sap.ui.table.Table} oTable Table instance
552
+ * @param {object} mConfig Configuration object
553
+ * @param {int} mConfig.fixedColumnCount Number of fixed columns
554
+ * @param {int} mConfig.headerRowCount Number of header rows
555
+ * @private
556
+ */
557
+ TableRenderer._renderScrollableColumnHeader = function(rm, oTable, mConfig) {
558
+ const aColumns = oTable.getColumns();
370
559
 
371
560
  rm.openStart("div", oTable.getId() + "-sapUiTableColHdrScr");
372
561
  rm.class("sapUiTableCHA"); // marker for the column header area
373
562
  rm.class("sapUiTableCtrlScr");
374
- if (aCols.length === 0) {
563
+
564
+ if (aColumns.length === 0) {
375
565
  rm.class("sapUiTableHasNoColumns");
376
566
  }
377
- if (iFixedColumnCount > 0) {
567
+
568
+ if (mConfig.fixedColumnCount > 0) {
378
569
  if (oTable._bRtlMode) {
379
570
  rm.style("margin-right", "0");
380
571
  } else {
381
572
  rm.style("margin-left", "0");
382
573
  }
383
574
  }
384
- rm.openEnd();
385
-
386
- //
387
- // write scrollable table here
388
- //
389
- this.renderTableControlCnt(rm, oTable, false, iFixedColumnCount, aCols.length, false, false, 0, nRows, true);
390
575
 
576
+ rm.openEnd();
577
+ this.renderTableElement(rm, oTable, {
578
+ fixedColumns: false,
579
+ startColumnIndex: mConfig.fixedColumnCount,
580
+ endColumnIndex: aColumns.length,
581
+ fixedTopRows: false,
582
+ fixedBottomRows: false,
583
+ startRowIndex: 0,
584
+ endRowIndex: mConfig.headerRowCount,
585
+ header: true
586
+ });
391
587
  rm.close("div");
588
+ };
392
589
 
393
- if (TableUtils.hasRowActions(oTable)) {
394
- rm.openStart("div", oTable.getId() + "-rowacthdr");
395
- oTable._getAccRenderExtension().writeAriaAttributesFor(rm, oTable, "RowActionHeader");
396
-
397
- rm.class("sapUiTableCell");
398
- rm.class("sapUiTableHeaderCell");
399
- rm.class("sapUiTableRowActionHeaderCell");
400
- rm.attr("tabindex", "-1");
401
- rm.attr("aria-label", TableUtils.getResourceText("TBL_ROW_ACTION_COLUMN_LABEL"));
402
- rm.openEnd();
403
-
404
- rm.close("div");
590
+ /**
591
+ * Renders the row action header cell when row actions are enabled.
592
+ *
593
+ * @param {sap.ui.core.RenderManager} rm RenderManager instance
594
+ * @param {sap.ui.table.Table} oTable Table instance
595
+ * @private
596
+ */
597
+ TableRenderer._renderRowActionHeader = function(rm, oTable) {
598
+ if (!TableUtils.hasRowActions(oTable)) {
599
+ return;
405
600
  }
406
601
 
407
- rm.openStart("div");
408
- rm.class("sapUiTableVSbHeader");
602
+ rm.openStart("div", oTable.getId() + "-rowacthdr");
603
+ oTable._getAccRenderExtension().writeAriaAttributesFor(rm, oTable, "RowActionHeader");
604
+ rm.class("sapUiTableCell");
605
+ rm.class("sapUiTableHeaderCell");
606
+ rm.class("sapUiTableRowActionHeaderCell");
607
+ rm.attr("tabindex", "-1");
608
+ rm.attr("aria-label", TableUtils.getResourceText("TBL_ROW_ACTION_COLUMN_LABEL"));
409
609
  rm.openEnd();
410
610
  rm.close("div");
611
+ };
411
612
 
613
+ /**
614
+ * Renders a placeholder header cell for the internal vertical scrollbar.
615
+ *
616
+ * @param {sap.ui.core.RenderManager} rm RenderManager instance
617
+ * @private
618
+ */
619
+ TableRenderer._renderVSbHeader = function(rm) {
620
+ rm.openStart("div");
621
+ rm.class("sapUiTableVSbHeader");
622
+ rm.openEnd();
412
623
  rm.close("div");
413
624
  };
414
625
 
415
- TableRenderer.renderColRowHdr = function(rm, oTable) {
416
- let bEnabled = false;
417
- let bSelAll = false;
418
- const mRenderConfig = oTable._getSelectionPlugin().getRenderConfig();
626
+ /**
627
+ * Renders the row selection header area.
628
+ *
629
+ * @param {sap.ui.core.RenderManager} rm RenderManager instance
630
+ * @param {sap.ui.table.Table} oTable Table instance
631
+ * @private
632
+ */
633
+ TableRenderer._renderSelectionHeader = function(rm, oTable) {
419
634
  const oAccRenderExtension = oTable._getAccRenderExtension();
420
635
 
421
636
  rm.openStart("div");
@@ -439,204 +654,22 @@ sap.ui.define([
439
654
 
440
655
  oAccRenderExtension.writeAriaAttributesFor(rm, oTable, "ColumnRowHeaderCell", {bLabel: true});
441
656
  rm.openEnd();
442
- rm.openStart("div", oTable.getId() + "-selall");
443
-
444
- rm.class("sapUiTableCell");
445
- rm.class("sapUiTableHeaderCell");
446
- rm.class("sapUiTableRowSelectionHeaderCell");
447
-
448
- if (mRenderConfig.headerSelector.visible) {
449
- const bAllRowsSelected = mRenderConfig.headerSelector.selected;
450
-
451
- if (mRenderConfig.headerSelector.type === "toggle") {
452
- rm.attr("title", TableUtils.getResourceText("TBL_SELECT_ALL"));
453
- } else if (mRenderConfig.headerSelector.type === "custom") {
454
- const sTitle = mRenderConfig.headerSelector.tooltip;
455
- rm.attr("title", sTitle);
456
-
457
- if (!mRenderConfig.headerSelector.enabled) {
458
- rm.class("sapUiTableSelAllDisabled");
459
- rm.attr("aria-disabled", "true");
460
- }
461
- }
462
-
463
- if (!bAllRowsSelected) {
464
- rm.class("sapUiTableSelAll");
465
- } else {
466
- bSelAll = true;
467
- }
468
- rm.class("sapUiTableSelAllVisible");
469
- bEnabled = true;
470
- }
471
-
472
- rm.attr("tabindex", "-1");
473
-
474
- const oParams = {
475
- enabled: bEnabled,
476
- checked: bSelAll
477
- };
478
- oAccRenderExtension.writeAriaAttributesFor(rm, oTable, "ColumnRowHeader", oParams);
479
-
480
- rm.openEnd();
481
-
482
- if (mRenderConfig.headerSelector.visible) {
483
- if (mRenderConfig.headerSelector.type === "custom" && mRenderConfig.headerSelector.icon) {
484
- rm.renderControl(mRenderConfig.headerSelector.icon);
485
- } else {
486
- rm.openStart("div");
487
- rm.class("sapUiTableSelectAllCheckBox");
488
- rm.openEnd();
489
- rm.close("div");
490
- }
491
- }
492
-
493
- rm.close("div").close("div").close("div");
494
- };
495
-
496
- TableRenderer.renderCol = function(rm, oTable, oColumn, iHeader, nSpan, bIsFirstColumn, bIsLastFixedColumn, bIsLastColumn, bRenderIcons) {
497
- let oLabel;
498
- const bInvisible = !nSpan;
499
- const iIndex = oColumn.getIndex();
500
- const aLabels = oColumn.getMultiLabels();
501
-
502
- if (aLabels.length > 0) {
503
- oLabel = aLabels[iHeader];
504
- } else if (iHeader === 0) {
505
- oLabel = oColumn.getLabel();
506
- }
507
-
508
- let sHeaderId = oColumn.getId();
509
- if (iHeader === 0) {
510
- rm.openStart("td", oColumn);
511
- } else {
512
- sHeaderId = sHeaderId + "_" + iHeader;
513
- rm.openStart("td", sHeaderId);
514
- }
515
- rm.attr('data-sap-ui-related', oColumn.getId());
516
- rm.attr('data-sap-ui-colid', oColumn.getId());
517
- rm.attr("data-sap-ui-colindex", iIndex);
518
-
519
- rm.attr("tabindex", "-1");
520
-
521
- const mAccParams = {
522
- column: oColumn,
523
- headerId: sHeaderId
524
- };
525
-
526
- if (nSpan > 1) {
527
- rm.attr("colspan", nSpan);
528
- mAccParams.colspan = true;
529
- }
530
-
531
- if (bRenderIcons) {
532
- const bFiltered = oColumn.getFiltered();
533
- let bSorted = oColumn.getSortOrder() !== SortOrder.None;
534
-
535
- /** @deprecated As of version 1.120 */
536
- if (!oColumn.getSorted()) {
537
- bSorted = false;
538
- }
539
-
540
- if (bFiltered) {
541
- rm.class("sapUiTableColFiltered");
542
- }
543
-
544
- if (bSorted) {
545
- rm.class("sapUiTableColSorted");
546
-
547
- if (oColumn.getSortOrder() === SortOrder.Descending) {
548
- rm.class("sapUiTableColSortedD");
549
- }
550
- }
551
- }
552
-
553
- oTable._getAccRenderExtension().writeAriaAttributesFor(rm, oTable, "ColumnHeader", mAccParams);
554
-
555
- rm.class("sapUiTableCell");
556
- rm.class("sapUiTableHeaderCell");
557
- rm.class("sapUiTableHeaderDataCell");
558
-
559
- const oColumnHeaderMenu = oColumn.getHeaderMenuInstance();
560
- if (oTable.getEnableColumnReordering() || oColumnHeaderMenu && oColumnHeaderMenu.getAriaHasPopupType() !== "None") {
561
- rm.class("sapUiTableHeaderCellActive");
562
- }
563
- /**
564
- * @deprecated As of Version 1.117
565
- */
566
- if (!oTable.getEnableColumnReordering() && !oTable.hasListeners("columnSelect") && !oColumnHeaderMenu && oColumn._menuHasItems()) {
567
- rm.class("sapUiTableHeaderCellActive");
568
- }
569
- if (bIsFirstColumn) {
570
- rm.class("sapUiTableCellFirst");
571
- }
572
- if (bIsLastFixedColumn) {
573
- rm.class("sapUiTableCellLastFixed");
574
- }
575
- if (bIsLastColumn) {
576
- rm.class("sapUiTableCellLast");
577
- }
578
- if (bInvisible) {
579
- rm.class("sapUiTableHidden");
580
- }
581
-
582
- if (oTable.getColumnHeaderHeight() > 0) {
583
- rm.style("height", oTable.getColumnHeaderHeight() + "px");
584
- }
585
- const sTooltip = oColumn.getTooltip_AsString();
586
- if (sTooltip) {
587
- rm.attr("title", sTooltip);
588
- }
589
- rm.openEnd();
590
-
591
- rm.openStart("div", sHeaderId + "-inner");
592
- rm.class("sapUiTableCellInner");
593
-
594
- if (!TableUtils.hasRowHeader(oTable) && bIsFirstColumn && !TableUtils.hasRowHighlights(oTable) && !TableUtils.Grouping.isInTreeMode(oTable)) {
595
- rm.class("sapUiTableFirstColumnCell");
596
- }
597
-
598
- const sHAlign = oColumn.getHAlign();
599
- const sTextAlign = Renderer.getTextAlign(sHAlign);
600
-
601
- if (sTextAlign) {
602
- rm.style("text-align", sTextAlign);
603
- }
604
-
605
- rm.openEnd();
606
-
607
- rm.openStart("div");
608
- rm.style("justify-content", mFlexCellContentAlignment[sHAlign]);
609
- rm.openEnd();
610
-
611
- const oAction = oColumn.getAggregation("_action");
612
- if (oAction && iHeader === 0) {
613
- if (oColumn.getMultiLabels().length > 0) {
614
- Log.error(`${oColumn}: ColumnAIAction is not compatible with multi labels`);
615
- } else {
616
- rm.renderControl(oAction);
617
- }
618
- }
619
- rm.renderControl(oLabel);
620
-
621
- rm.close("div");
622
-
657
+ rm.renderControl(oTable._getHeaderSelector());
623
658
  rm.close("div");
624
- rm.close("td");
625
- };
626
-
627
- TableRenderer.renderColRsz = function(rm, oTable) {
628
- rm.openStart("div", oTable.getId() + "-rsz");
629
- rm.class("sapUiTableColRsz");
630
- rm.openEnd();
631
659
  rm.close("div");
632
660
  };
633
661
 
634
- // =============================================================================
635
- // CONTENT AREA OF THE TABLE
636
- // =============================================================================
637
-
638
- TableRenderer.renderRowHdr = function(rm, oTable) {
662
+ /**
663
+ * Renders the row header area containing row header cells for each data row.
664
+ *
665
+ * @param {sap.ui.core.RenderManager} rm RenderManager instance
666
+ * @param {sap.ui.table.Table} oTable Table instance
667
+ * @private
668
+ */
669
+ TableRenderer.renderRowHeader = function(rm, oTable) {
639
670
  const oAccRenderExtension = oTable._getAccRenderExtension();
671
+ const aRows = oTable.getRows();
672
+
640
673
  rm.openStart("div", oTable.getId() + "-sapUiTableRowHdrScr");
641
674
  oAccRenderExtension.writeAriaAttributesFor(rm, oTable, "Presentation");
642
675
  rm.class("sapUiTableRowHdrScr");
@@ -644,67 +677,63 @@ sap.ui.define([
644
677
  oAccRenderExtension.writeAriaAttributesFor(rm, oTable, "RowHeaderCol");
645
678
  rm.openEnd();
646
679
 
647
- // start with the first current top visible row
648
- for (let row = 0, count = oTable.getRows().length; row < count; row++) {
649
- this.renderRowAddon(rm, oTable, oTable.getRows()[row], row, true);
680
+ for (let iRowIndex = 0, iRowCount = aRows.length; iRowIndex < iRowCount; iRowIndex++) {
681
+ this.renderRowAddon(rm, oTable, aRows[iRowIndex], {rowIndex: iRowIndex, isRowHeader: true});
650
682
  }
651
683
 
652
684
  rm.close("div");
653
685
  };
654
686
 
687
+ /**
688
+ * Renders the row action area containing row action cells for each data row.
689
+ *
690
+ * @param {sap.ui.core.RenderManager} rm RenderManager instance
691
+ * @param {sap.ui.table.Table} oTable Table instance
692
+ * @private
693
+ */
655
694
  TableRenderer.renderRowActions = function(rm, oTable) {
656
695
  if (!TableUtils.hasRowActions(oTable) && !TableUtils.hasRowNavigationIndicators(oTable)) {
657
696
  return;
658
697
  }
698
+
699
+ const aRows = oTable.getRows();
700
+
659
701
  rm.openStart("div", oTable.getId() + "-sapUiTableRowActionScr");
660
702
  oTable._getAccRenderExtension().writeAriaAttributesFor(rm, oTable, "Presentation");
661
- TableUtils.hasRowActions(oTable) ? rm.class("sapUiTableRowWithAction") : rm.class("sapUiTableRowActionScr");
703
+ if (TableUtils.hasRowActions(oTable)) {
704
+ rm.class("sapUiTableRowWithAction");
705
+ } else {
706
+ rm.class("sapUiTableRowActionScr");
707
+ }
662
708
  rm.class("sapUiTableNoOpacity");
663
709
  rm.openEnd();
664
710
 
665
- // start with the first current top visible row
666
- for (let row = 0, count = oTable.getRows().length; row < count; row++) {
667
- this.renderRowAddon(rm, oTable, oTable.getRows()[row], row, false);
711
+ for (let iRowIndex = 0, iRowCount = aRows.length; iRowIndex < iRowCount; iRowIndex++) {
712
+ this.renderRowAddon(rm, oTable, aRows[iRowIndex], {rowIndex: iRowIndex, isRowHeader: false});
668
713
  }
669
714
 
670
715
  rm.close("div");
671
716
  };
672
717
 
673
- TableRenderer.addRowCSSClasses = function(rm, oTable, iIndex) {
674
- const mRowCounts = oTable._getRowCounts();
675
- const iFirstFixedBottomRowIndex = TableUtils.getFirstFixedBottomRowIndex(oTable);
676
-
677
- if (iIndex === 0) {
678
- rm.class("sapUiTableFirstRow");
679
- } else if (iIndex === oTable.getRows().length - 1) {
680
- rm.class("sapUiTableLastRow");
681
- }
682
-
683
- if (mRowCounts.fixedTop > 0) {
684
- if (iIndex === mRowCounts.fixedTop - 1) {
685
- rm.class("sapUiTableRowLastFixedTop");
686
- }
687
- if (iIndex === mRowCounts.fixedTop) {
688
- rm.class("sapUiTableRowFirstScrollable");
689
- }
690
- }
691
-
692
- if (iFirstFixedBottomRowIndex >= 0 && iFirstFixedBottomRowIndex === iIndex) {
693
- rm.class("sapUiTableRowFirstFixedBottom");
694
- } else if (iFirstFixedBottomRowIndex >= 1 && iFirstFixedBottomRowIndex - 1 === iIndex) {
695
- rm.class("sapUiTableRowLastScrollable");
696
- }
697
- };
698
-
699
- TableRenderer.renderRowAddon = function(rm, oTable, oRow, iRowIndex, bHeader) {
718
+ /**
719
+ * Renders a row addon entry for either the row header or the row action area.
720
+ *
721
+ * @param {sap.ui.core.RenderManager} rm RenderManager instance
722
+ * @param {sap.ui.table.Table} oTable Table instance
723
+ * @param {sap.ui.table.Row} oRow Row instance
724
+ * @param {object} mConfig Configuration object
725
+ * @param {int} mConfig.rowIndex Index of the row in the aggregation
726
+ * @param {boolean} mConfig.isRowHeader True for row header area; false for action area
727
+ * @private
728
+ */
729
+ TableRenderer.renderRowAddon = function(rm, oTable, oRow, mConfig) {
700
730
  const bRowSelected = oRow._isSelected();
701
731
  const oAccRenderExtension = oTable._getAccRenderExtension();
702
732
 
703
733
  rm.openStart("div");
704
734
  oAccRenderExtension.writeAriaAttributesFor(rm, oTable, "RowAddon");
705
-
706
735
  rm.attr("data-sap-ui-related", oRow.getId());
707
- rm.attr("data-sap-ui-rowindex", iRowIndex);
736
+ rm.attr("data-sap-ui-rowindex", mConfig.rowIndex);
708
737
 
709
738
  rm.class("sapUiTableRow");
710
739
  rm.class("sapUiTableContentRow");
@@ -715,53 +744,56 @@ sap.ui.define([
715
744
  rm.class("sapUiTableRowSel");
716
745
  }
717
746
 
718
- if (iRowIndex % 2 !== 0 && oTable.getAlternateRowColors() && !TableUtils.Grouping.isInTreeMode(oTable)) {
747
+ if (mConfig.rowIndex % 2 !== 0 && oTable.getAlternateRowColors() && !TableUtils.Grouping.isInTreeMode(oTable)) {
719
748
  rm.class("sapUiTableRowAlternate");
720
749
  }
721
750
 
722
- this.addRowCSSClasses(rm, oTable, iRowIndex);
751
+ this.addRowClasses(rm, oTable, mConfig.rowIndex);
723
752
 
724
753
  rm.openEnd();
725
-
726
- rm.openStart("div", oTable.getId() + (bHeader ? "-rowsel" : "-rowact") + iRowIndex);
754
+ rm.openStart("div", oTable.getId() + (mConfig.isRowHeader ? "-rowsel" : "-rowact") + mConfig.rowIndex);
727
755
  rm.class("sapUiTableCell");
728
756
  rm.class("sapUiTableContentCell");
729
- rm.class(bHeader ? "sapUiTableRowSelectionCell" : "sapUiTableRowActionCell");
757
+ rm.class(mConfig.isRowHeader ? "sapUiTableRowSelectionCell" : "sapUiTableRowActionCell");
730
758
 
731
759
  TableUtils.Hook.call(oTable, Hook.RenderRowStyles, rm);
732
760
 
733
761
  rm.attr("tabindex", "-1");
734
762
 
735
- const oParams = {
763
+ oAccRenderExtension.writeAriaAttributesFor(rm, oTable, mConfig.isRowHeader ? "RowHeader" : "RowAction", {
736
764
  rowSelected: bRowSelected,
737
765
  rowHidden: oRow.isEmpty()
738
- };
739
- oAccRenderExtension.writeAriaAttributesFor(rm, oTable, bHeader ? "RowHeader" : "RowAction", oParams);
766
+ });
740
767
 
741
768
  rm.openEnd();
742
- if (bHeader) {
743
- this.writeRowHighlightContent(rm, oTable, oRow, iRowIndex);
769
+ if (mConfig.isRowHeader) {
770
+ this.writeRowHighlightContent(rm, oTable, oRow);
744
771
  this.writeRowSelectorContent(rm, oTable, oRow);
745
772
  } else {
746
773
  const oAction = oRow.getRowAction();
747
774
  if (oAction) {
748
775
  rm.renderControl(oAction);
749
776
  }
750
- this.writeRowNavigationContent(rm, oTable, oRow, iRowIndex);
777
+ this.writeRowNavigationContent(rm, oTable, oRow);
751
778
  }
752
779
  rm.close("div");
753
780
 
754
781
  rm.close("div");
755
782
  };
756
783
 
784
+ /**
785
+ * Renders the table control area containing fixed and scrollable data sections.
786
+ *
787
+ * @param {sap.ui.core.RenderManager} rm RenderManager instance
788
+ * @param {sap.ui.table.Table} oTable Table instance
789
+ * @private
790
+ */
757
791
  TableRenderer.renderTableCtrl = function(rm, oTable) {
758
792
  if (oTable.getComputedFixedColumnCount() > 0) {
759
793
  rm.openStart("div", oTable.getId() + "-sapUiTableCtrlScrFixed");
760
794
  rm.class("sapUiTableCtrlScrFixed");
761
795
  rm.openEnd();
762
-
763
- this.renderTableControl(rm, oTable, true);
764
-
796
+ this.renderTableControl(rm, oTable, {fixedColumns: true});
765
797
  rm.close("div");
766
798
  }
767
799
 
@@ -779,110 +811,255 @@ sap.ui.define([
779
811
  rm.openStart("div", oTable.getId() + "-tableCtrlCnt");
780
812
  rm.class("sapUiTableCtrlCnt");
781
813
  rm.openEnd();
782
-
783
- this.renderTableControl(rm, oTable, false);
784
-
814
+ this.renderTableControl(rm, oTable, {fixedColumns: false});
785
815
  rm.close("div");
816
+
786
817
  rm.close("div");
787
818
  };
788
819
 
789
- TableRenderer.renderTableControl = function(rm, oTable, bFixedTable) {
790
- let iStartColumn; let iEndColumn;
820
+ /**
821
+ * Renders a table control section (either fixed columns or scrollable columns).
822
+ *
823
+ * @param {sap.ui.core.RenderManager} rm RenderManager instance
824
+ * @param {sap.ui.table.Table} oTable Table instance
825
+ * @param {object} mConfig Configuration object
826
+ * @param {boolean} mConfig.fixedColumns True if fixed columns area
827
+ * @private
828
+ */
829
+ TableRenderer.renderTableControl = function(rm, oTable, mConfig) {
830
+ const mRowCounts = oTable._getRowCounts();
831
+ const aRows = oTable.getRows();
832
+ let iStartColumnIndex;
833
+ let iEndColumnIndex;
791
834
 
792
- if (bFixedTable) {
793
- iStartColumn = 0;
794
- iEndColumn = oTable.getComputedFixedColumnCount();
835
+ if (mConfig.fixedColumns) {
836
+ iStartColumnIndex = 0;
837
+ iEndColumnIndex = oTable.getComputedFixedColumnCount();
795
838
  } else {
796
- iStartColumn = oTable.getComputedFixedColumnCount();
797
- iEndColumn = oTable.getColumns().length;
839
+ iStartColumnIndex = oTable.getComputedFixedColumnCount();
840
+ iEndColumnIndex = oTable.getColumns().length;
798
841
  }
799
842
 
800
- const mRowCounts = oTable._getRowCounts();
801
- const aRows = oTable.getRows();
802
-
803
843
  if (mRowCounts.fixedTop > 0) {
804
- this.renderTableControlCnt(rm, oTable, bFixedTable, iStartColumn, iEndColumn, true, false, 0, mRowCounts.fixedTop);
844
+ this.renderTableElement(rm, oTable, {
845
+ fixedColumns: mConfig.fixedColumns,
846
+ startColumnIndex: iStartColumnIndex,
847
+ endColumnIndex: iEndColumnIndex,
848
+ fixedTopRows: true,
849
+ fixedBottomRows: false,
850
+ startRowIndex: 0,
851
+ endRowIndex: mRowCounts.fixedTop,
852
+ header: false
853
+ });
805
854
  }
806
- this.renderTableControlCnt(rm, oTable, bFixedTable, iStartColumn, iEndColumn, false, false, mRowCounts.fixedTop, aRows.length - mRowCounts.fixedBottom);
855
+
856
+ this.renderTableElement(rm, oTable, {
857
+ fixedColumns: mConfig.fixedColumns,
858
+ startColumnIndex: iStartColumnIndex,
859
+ endColumnIndex: iEndColumnIndex,
860
+ fixedTopRows: false,
861
+ fixedBottomRows: false,
862
+ startRowIndex: mRowCounts.fixedTop,
863
+ endRowIndex: aRows.length - mRowCounts.fixedBottom,
864
+ header: false
865
+ });
866
+
807
867
  if (mRowCounts.fixedBottom > 0 && aRows.length > 0) {
808
- this.renderTableControlCnt(rm, oTable, bFixedTable, iStartColumn, iEndColumn, false, true, aRows.length - mRowCounts.fixedBottom, aRows.length);
868
+ this.renderTableElement(rm, oTable, {
869
+ fixedColumns: mConfig.fixedColumns,
870
+ startColumnIndex: iStartColumnIndex,
871
+ endColumnIndex: iEndColumnIndex,
872
+ fixedTopRows: false,
873
+ fixedBottomRows: true,
874
+ startRowIndex: aRows.length - mRowCounts.fixedBottom,
875
+ endRowIndex: aRows.length,
876
+ header: false
877
+ });
809
878
  }
810
879
  };
811
880
 
812
- TableRenderer.renderTableControlCnt = function(rm, oTable, bFixedTable, iStartColumn, iEndColumn, bFixedRow, bFixedBottomRow, iStartRow, iEndRow, bHeader) {
813
- let sSuffix = bHeader ? "-header" : "-table";
814
- let sId = oTable.getId() + sSuffix;
815
- const sClasses = [];
816
-
817
- if (bFixedTable) {
818
- sId += "-fixed";
819
- sClasses.push("sapUiTableCtrlFixed");
820
- } else {
821
- sClasses.push("sapUiTableCtrlScroll");
822
- }
823
- if (bFixedRow) {
824
- sId += "-fixrow";
825
- sClasses.push("sapUiTableCtrlRowFixed");
826
- } else if (bFixedBottomRow) {
827
- sId += "-fixrow-bottom";
828
- sClasses.push("sapUiTableCtrlRowFixedBottom");
829
- } else {
830
- sClasses.push("sapUiTableCtrlRowScroll");
831
- }
881
+ /**
882
+ * Renders an table element covering a defined column and row slice.
883
+ *
884
+ * @param {sap.ui.core.RenderManager} rm RenderManager instance
885
+ * @param {sap.ui.table.Table} oTable Table instance
886
+ * @param {object} mConfig Configuration object
887
+ * @param {boolean} mConfig.fixedColumns True if segment is in fixed columns area
888
+ * @param {boolean} mConfig.fixedTopRows True if segment shows fixed top rows
889
+ * @param {boolean} mConfig.fixedBottomRows True if segment shows fixed bottom rows
890
+ * @param {int} mConfig.startColumnIndex Start column index (inclusive)
891
+ * @param {int} mConfig.endColumnIndex End column index (exclusive)
892
+ * @param {int} mConfig.startRowIndex Start row index (inclusive)
893
+ * @param {int} mConfig.endRowIndex End row index (exclusive)
894
+ * @param {boolean} mConfig.header True if header segment
895
+ * @private
896
+ */
897
+ TableRenderer.renderTableElement = function(rm, oTable, mConfig) {
898
+ const {fixedColumns, startColumnIndex, endColumnIndex, fixedTopRows, fixedBottomRows, startRowIndex, endRowIndex, header} = mConfig;
899
+ const sId = this._buildTableSectionId(oTable, {fixedColumns, fixedTopRows, fixedBottomRows, header});
832
900
 
833
901
  rm.openStart("table", sId);
834
- sClasses.forEach(function(sClass) {
835
- rm.class(sClass);
836
- });
902
+ this._decorateTableElement(rm, oTable, {fixedColumns, fixedTopRows, fixedBottomRows, startColumnIndex, endColumnIndex, header});
903
+ rm.openEnd();
904
+ this._renderTableHead(rm, oTable, {fixedColumns, startColumnIndex, endColumnIndex, startRowIndex, header});
905
+ this._renderTableBody(rm, oTable, {fixedColumns, startColumnIndex, endColumnIndex, startRowIndex, endRowIndex, header});
906
+ rm.close("table");
907
+ };
837
908
 
838
- const oAccRenderExtension = oTable._getAccRenderExtension();
839
- oAccRenderExtension.writeAriaAttributesFor(rm, oTable, bHeader ? "Presentation" : "Table");
909
+ /**
910
+ * Builds the table section ID.
911
+ *
912
+ * @param {sap.ui.table.Table} oTable Table instance
913
+ * @param {object} mConfig Configuration object
914
+ * @param {boolean} mConfig.fixedColumns True if fixed columns area
915
+ * @param {boolean} mConfig.fixedTopRows True if fixed top rows area
916
+ * @param {boolean} mConfig.fixedBottomRows True if fixed bottom rows area
917
+ * @param {boolean} mConfig.header True if header section
918
+ * @returns {string} Table section ID
919
+ * @private
920
+ */
921
+ TableRenderer._buildTableSectionId = function(oTable, mConfig) {
922
+ const {fixedColumns, fixedTopRows, fixedBottomRows, header} = mConfig;
923
+ const suffix = header ? "-header" : "-table";
924
+ let id = oTable.getId() + suffix;
840
925
 
841
- rm.class("sapUiTableCtrl");
842
- if (bHeader) {
843
- rm.class("sapUiTableCHT"); // marker for the column header table
926
+ if (fixedColumns) {
927
+ id += "-fixed";
844
928
  }
845
929
 
846
- rm.style(bFixedTable ? "width" : "min-width", oTable._getColumnsWidth(iStartColumn, iEndColumn) + "px");
930
+ if (fixedTopRows) {
931
+ id += "-fixrow";
932
+ } else if (fixedBottomRows) {
933
+ id += "-fixrow-bottom";
934
+ }
847
935
 
848
- rm.openEnd();
936
+ return id;
937
+ };
849
938
 
850
- rm.openStart("thead").openEnd();
939
+ /**
940
+ * Decorates the table element with attributes, styles and CSS classes.
941
+ *
942
+ * @param {sap.ui.core.RenderManager} rm RenderManager instance
943
+ * @param {sap.ui.table.Table} oTable Table instance
944
+ * @param {object} mConfig Configuration object
945
+ * @param {boolean} mConfig.fixedColumns True if fixed columns area
946
+ * @param {boolean} mConfig.fixedTopRows True if fixed top rows area
947
+ * @param {boolean} mConfig.fixedBottomRows True if fixed bottom rows area
948
+ * @param {int} mConfig.startColumnIndex Start column index (inclusive)
949
+ * @param {int} mConfig.endColumnIndex End column index (exclusive)
950
+ * @param {boolean} mConfig.header True if header table
951
+ * @private
952
+ */
953
+ TableRenderer._decorateTableElement = function(rm, oTable, mConfig) {
954
+ rm.class(mConfig.fixedColumns ? "sapUiTableCtrlFixed" : "sapUiTableCtrlScroll");
851
955
 
852
- rm.openStart("tr");
853
- rm.class("sapUiTableCtrlCol");
854
- if (iStartRow === 0) {
956
+ if (mConfig.fixedTopRows) {
957
+ rm.class("sapUiTableCtrlRowFixed");
958
+ } else if (mConfig.fixedBottomRows) {
959
+ rm.class("sapUiTableCtrlRowFixedBottom");
960
+ } else {
961
+ rm.class("sapUiTableCtrlRowScroll");
962
+ }
963
+
964
+ if (mConfig.header) {
965
+ rm.class("sapUiTableCHT");
966
+ }
967
+
968
+ rm.class("sapUiTableCtrl");
969
+ oTable._getAccRenderExtension().writeAriaAttributesFor(rm, oTable, mConfig.header ? "Presentation" : "Table");
970
+ rm.style(mConfig.fixedColumns ? "width" : "min-width", oTable._getColumnsWidth(mConfig.startColumnIndex, mConfig.endColumnIndex) + "px");
971
+ };
972
+
973
+ /**
974
+ * Renders the table head section.
975
+ *
976
+ * @param {sap.ui.core.RenderManager} rm RenderManager instance
977
+ * @param {sap.ui.table.Table} oTable Table instance
978
+ * @param {object} mConfig Configuration object
979
+ * @param {boolean} mConfig.fixedColumns True if fixed columns area
980
+ * @param {int} mConfig.startColumnIndex Start column index (inclusive)
981
+ * @param {int} mConfig.endColumnIndex End column index (exclusive)
982
+ * @param {int} mConfig.startRowIndex Start row index (inclusive)
983
+ * @param {boolean} mConfig.header True if header table
984
+ * @private
985
+ */
986
+ TableRenderer._renderTableHead = function(rm, oTable, mConfig) {
987
+ rm.openStart("thead").openEnd();
988
+ const {fixedColumns, startColumnIndex, endColumnIndex, startRowIndex, header} = mConfig;
989
+ this._renderTableHeaderRow(rm, oTable, {fixedColumns, startColumnIndex, endColumnIndex, startRowIndex, header});
990
+ rm.close("thead");
991
+ };
992
+
993
+ /**
994
+ * Renders the table header row.
995
+ *
996
+ * @param {sap.ui.core.RenderManager} rm RenderManager instance
997
+ * @param {sap.ui.table.Table} oTable Table instance
998
+ * @param {object} mConfig Configuration object
999
+ * @param {boolean} mConfig.fixedColumns True if fixed columns area
1000
+ * @param {int} mConfig.startColumnIndex Start column index (inclusive)
1001
+ * @param {int} mConfig.endColumnIndex End column index (exclusive)
1002
+ * @param {int} mConfig.startRowIndex Start row index (inclusive)
1003
+ * @param {boolean} mConfig.header True if header table
1004
+ * @private
1005
+ */
1006
+ TableRenderer._renderTableHeaderRow = function(rm, oTable, mConfig) {
1007
+ rm.openStart("tr");
1008
+ rm.class("sapUiTableCtrlCol");
1009
+ if (mConfig.startRowIndex === 0) {
855
1010
  rm.class("sapUiTableCtrlFirstCol");
856
1011
  }
857
- if (bHeader) {
858
- rm.class("sapUiTableCHTHR"); // marker for the column header row
1012
+ if (mConfig.header) {
1013
+ rm.class("sapUiTableCHTHR");
859
1014
  }
860
1015
  rm.openEnd();
861
1016
 
1017
+ const {fixedColumns, startColumnIndex, endColumnIndex, startRowIndex, header} = mConfig;
1018
+ const mColumnData = this._prepareColumnData(oTable, {fixedColumns, startColumnIndex, endColumnIndex});
1019
+ this._renderTableColumns(rm, oTable, {columnData: mColumnData, startColumnIndex, endColumnIndex, startRowIndex, header});
1020
+
1021
+ if (mColumnData.bRenderDummyColumn) {
1022
+ this._renderDummyColumnHeaderCell(rm, oTable, {header});
1023
+ }
1024
+
1025
+ rm.close("tr");
1026
+ };
1027
+
1028
+ /**
1029
+ * Prepares per-column metadata needed for rendering.
1030
+ *
1031
+ * @param {sap.ui.table.Table} oTable Table instance
1032
+ * @param {object} mConfig Configuration object
1033
+ * @param {boolean} mConfig.fixedColumns True if preparing data for the fixed columns area
1034
+ * @param {int} mConfig.startColumnIndex Start column index (inclusive)
1035
+ * @param {int} mConfig.endColumnIndex End column index (exclusive)
1036
+ * @returns {object} Object containing:
1037
+ * {sap.ui.table.Column[]} aCols All columns of the table
1038
+ * {object[]} aColParams Per-column params with properties {shouldRender:boolean, width:string|undefined}
1039
+ * {boolean} bRenderDummyColumn True if dummy column should be rendered for variable-width balancing
1040
+ * {sap.ui.table.Column[]} aVisibleColumns Currently visible columns
1041
+ * @private
1042
+ */
1043
+ TableRenderer._prepareColumnData = function(oTable, mConfig) {
862
1044
  const aCols = oTable.getColumns();
863
- const aColParams = new Array(iEndColumn);
864
- let iCol;
865
- let oColumn;
866
- let bRenderDummyColumn = !bFixedTable && iEndColumn > iStartColumn;
867
- const aVisibleColumns = oTable._getVisibleColumns();
868
-
869
- for (iCol = iStartColumn; iCol < iEndColumn; iCol++) {
870
- oColumn = aCols[iCol];
1045
+ const aColParams = new Array(mConfig.endColumnIndex);
1046
+ let bRenderDummyColumn = !mConfig.fixedColumns && mConfig.endColumnIndex > mConfig.startColumnIndex;
1047
+
1048
+ for (let iCol = mConfig.startColumnIndex; iCol < mConfig.endColumnIndex; iCol++) {
1049
+ const oColumn = aCols[iCol];
871
1050
  const oColParam = {
872
1051
  shouldRender: !!(oColumn && oColumn.shouldRender())
873
1052
  };
1053
+
874
1054
  if (oColParam.shouldRender) {
875
1055
  let sWidth = oColumn.getWidth();
876
1056
  if (TableUtils.isVariableWidth(sWidth)) {
877
- // if some of the columns have variable width, they serve as the dummy column
878
- // and take available place. Do not render a dummy column in this case.
879
1057
  bRenderDummyColumn = false;
880
- // in fixed area, use stored fixed width or 10rem:
881
- if (bFixedTable) {
1058
+ if (mConfig.fixedColumns) {
882
1059
  oColumn._iFixWidth = oColumn._iFixWidth || 160;
883
1060
  sWidth = oColumn._iFixWidth + "px";
884
1061
  }
885
- } else if (bFixedTable) {
1062
+ } else if (mConfig.fixedColumns) {
886
1063
  delete oColumn._iFixWidth;
887
1064
  }
888
1065
  oColParam.width = sWidth;
@@ -890,77 +1067,210 @@ sap.ui.define([
890
1067
  aColParams[iCol] = oColParam;
891
1068
  }
892
1069
 
1070
+ return {
1071
+ aCols,
1072
+ aColParams,
1073
+ bRenderDummyColumn,
1074
+ aVisibleColumns: oTable._getVisibleColumns()
1075
+ };
1076
+ };
1077
+
1078
+ /**
1079
+ * Renders table columns.
1080
+ *
1081
+ * @param {sap.ui.core.RenderManager} rm RenderManager instance
1082
+ * @param {sap.ui.table.Table} oTable Table instance
1083
+ * @param {object} mConfig Configuration object
1084
+ * @param {object} mConfig.columnData Prepared column data
1085
+ * @param {int} mConfig.startColumnIndex Start column index (inclusive)
1086
+ * @param {int} mConfig.endColumnIndex End column index (exclusive)
1087
+ * @param {int} mConfig.startRowIndex Start row index (inclusive)
1088
+ * @param {boolean} mConfig.header True if header table
1089
+ * @private
1090
+ */
1091
+ TableRenderer._renderTableColumns = function(rm, oTable, mConfig) {
1092
+ const {columnData, startColumnIndex, endColumnIndex, startRowIndex, header} = mConfig;
1093
+ const {aCols, aColParams, aVisibleColumns} = columnData;
1094
+ const oAccRenderExtension = oTable._getAccRenderExtension();
1095
+
893
1096
  if (aCols.length === 0) {
894
1097
  rm.openStart("th").openEnd().close("th");
1098
+ return;
895
1099
  }
896
1100
 
897
- for (iCol = iStartColumn; iCol < iEndColumn; iCol++) {
898
- sSuffix = bHeader ? "_hdr" : "_col";
899
- oColumn = aCols[iCol];
1101
+ for (let iCol = startColumnIndex; iCol < endColumnIndex; iCol++) {
1102
+ const sSuffix = header ? "_hdr" : "_col";
1103
+ const oColumn = aCols[iCol];
900
1104
  const oColParam = aColParams[iCol];
901
1105
 
902
1106
  if (oColParam.shouldRender) {
903
- if (iStartRow === 0) {
1107
+ if (startRowIndex === 0) {
904
1108
  rm.openStart("th", oTable.getId() + sSuffix + iCol);
905
1109
  oAccRenderExtension.writeAriaAttributesFor(rm, oTable, "Th", {column: oColumn});
906
1110
  } else {
907
1111
  rm.openStart("th");
908
1112
  }
1113
+
909
1114
  rm.style("width", oColParam.width);
910
1115
  rm.attr("data-sap-ui-headcolindex", iCol);
911
1116
  rm.attr("data-sap-ui-colid", oColumn.getId());
1117
+
912
1118
  if (oColumn === aVisibleColumns[0]) {
913
1119
  rm.class("sapUiTableFirstVisibleColumnTH");
914
1120
  }
1121
+
915
1122
  rm.openEnd();
916
- if (iStartRow === 0 && TableUtils.getHeaderRowCount(oTable) === 0 && !bHeader) {
1123
+
1124
+ if (startRowIndex === 0 && TableUtils.getHeaderRowCount(oTable) === 0 && !header) {
917
1125
  if (oColumn.getMultiLabels().length > 0) {
918
1126
  rm.renderControl(oColumn.getMultiLabels()[0]);
919
1127
  } else {
920
1128
  rm.renderControl(oColumn.getLabel());
921
1129
  }
922
1130
  }
1131
+
923
1132
  rm.close("th");
924
1133
  }
925
1134
  }
1135
+ };
926
1136
 
927
- // dummy column to fill the table width
928
- if (bRenderDummyColumn) {
929
- rm.openStart("th", bHeader && oTable.getId() + "-dummycolhdr");
930
- oAccRenderExtension.writeAriaAttributesFor(rm, oTable, "Presentation");
931
- rm.openEnd().close("th");
932
- }
1137
+ /**
1138
+ * Renders the header cell of the dummy column.
1139
+ *
1140
+ * @param {sap.ui.core.RenderManager} rm RenderManager instance
1141
+ * @param {sap.ui.table.Table} oTable Table instance
1142
+ * @param {object} mConfig Configuration object
1143
+ * @param {boolean} mConfig.header True if header table
1144
+ * @private
1145
+ */
1146
+ TableRenderer._renderDummyColumnHeaderCell = function(rm, oTable, mConfig) {
1147
+ rm.openStart("th", mConfig.header && oTable.getId() + "-dummycolhdr");
1148
+ oTable._getAccRenderExtension().writeAriaAttributesFor(rm, oTable, "Presentation");
1149
+ rm.openEnd();
1150
+ rm.close("th");
1151
+ };
933
1152
 
934
- rm.close("tr");
935
- rm.close("thead");
1153
+ /**
1154
+ * Renders the body rows (either header rows for a header segment or data rows for a data segment).
1155
+ *
1156
+ * @param {sap.ui.core.RenderManager} rm RenderManager instance
1157
+ * @param {sap.ui.table.Table} oTable Table instance
1158
+ * @param {object} mConfig Configuration object
1159
+ * @param {boolean} mConfig.fixedColumns True if fixed columns area
1160
+ * @param {int} mConfig.startColumnIndex Start column index (inclusive)
1161
+ * @param {int} mConfig.endColumnIndex End column index (exclusive)
1162
+ * @param {int} mConfig.startRowIndex Start row index (inclusive)
1163
+ * @param {int} mConfig.endRowIndex End row index (exclusive)
1164
+ * @param {boolean} mConfig.header True if rendering a header segment
1165
+ * @private
1166
+ */
1167
+ TableRenderer._renderTableBody = function(rm, oTable, mConfig) {
1168
+ const {fixedColumns, startColumnIndex, endColumnIndex, startRowIndex, endRowIndex} = mConfig;
1169
+ const mColumnData = this._prepareColumnData(oTable, {fixedColumns, startColumnIndex, endColumnIndex});
936
1170
 
937
- rm.openStart("tbody").openEnd();
1171
+ rm.openStart("tbody");
1172
+ rm.openEnd();
938
1173
 
939
- // render the table rows
940
- const aRows = oTable.getRows();
941
- let row;
942
- let count;
943
- if (bHeader) {
944
- for (row = iStartRow, count = iEndRow; row < count; row++) {
945
- this.renderColumnHeaderRow(rm, oTable, row, bFixedTable, iStartColumn, iEndColumn, bRenderDummyColumn, row === count - 1);
946
- }
1174
+ if (mConfig.header) {
1175
+ this._renderHeaderRows(rm, oTable, {
1176
+ fixedColumns,
1177
+ startColumnIndex,
1178
+ endColumnIndex,
1179
+ startRowIndex,
1180
+ endRowIndex,
1181
+ renderDummyColumn: mColumnData.bRenderDummyColumn
1182
+ });
947
1183
  } else {
948
- // check whether the row can be clicked to change the selection
949
- const bSelectOnCellsAllowed = TableUtils.isRowSelectionAllowed(oTable);
950
- const bRowsDraggable = oTable.getDragDropConfig().some(function(oDragDropInfo) {
951
- return oDragDropInfo.isDraggable(oTable, "rows");
1184
+ this._renderDataRows(rm, oTable, {
1185
+ fixedColumns,
1186
+ startColumnIndex,
1187
+ endColumnIndex,
1188
+ startRowIndex,
1189
+ endRowIndex,
1190
+ visibleColumns: mColumnData.aVisibleColumns,
1191
+ renderDummyColumn: mColumnData.bRenderDummyColumn
952
1192
  });
1193
+ }
953
1194
 
954
- const iLastFixedColumnIndex = this.getLastFixedColumnIndex(oTable);
1195
+ rm.close("tbody");
1196
+ };
955
1197
 
956
- for (row = iStartRow, count = iEndRow; row < count; row++) {
957
- this.renderTableRow(rm, oTable, aRows[row], row, bFixedTable, iStartColumn, iEndColumn, false, aVisibleColumns, iLastFixedColumnIndex, bRenderDummyColumn, bSelectOnCellsAllowed, bRowsDraggable);
958
- }
1198
+ /**
1199
+ * Renders all header rows for a header table segment.
1200
+ *
1201
+ * @param {sap.ui.core.RenderManager} rm RenderManager instance
1202
+ * @param {sap.ui.table.Table} oTable Table instance
1203
+ * @param {object} mConfig Configuration object
1204
+ * @param {boolean} mConfig.fixedColumns True if fixed columns area
1205
+ * @param {int} mConfig.startColumnIndex Start column index (inclusive)
1206
+ * @param {int} mConfig.endColumnIndex End column index (exclusive)
1207
+ * @param {int} mConfig.startRowIndex First header row index (inclusive)
1208
+ * @param {int} mConfig.endRowIndex One past last header row index (exclusive)
1209
+ * @param {boolean} mConfig.renderDummyColumn True if dummy column should be rendered
1210
+ * @private
1211
+ */
1212
+ TableRenderer._renderHeaderRows = function(rm, oTable, mConfig) {
1213
+ const {fixedColumns, startColumnIndex, endColumnIndex, renderDummyColumn} = mConfig;
1214
+ for (let iRowIndex = mConfig.startRowIndex; iRowIndex < mConfig.endRowIndex; iRowIndex++) {
1215
+ this.renderColumnHeaderRow(rm, oTable, {
1216
+ rowIndex: iRowIndex,
1217
+ fixedColumns,
1218
+ startColumnIndex,
1219
+ endColumnIndex,
1220
+ renderDummyColumn,
1221
+ isLastRow: iRowIndex === mConfig.endRowIndex - 1
1222
+ });
959
1223
  }
960
- rm.close("tbody");
961
- rm.close("table");
962
1224
  };
1225
+ /**
1226
+ * Renders data rows for a data table segment.
1227
+ *
1228
+ * @param {sap.ui.core.RenderManager} rm RenderManager instance
1229
+ * @param {sap.ui.table.Table} oTable Table instance
1230
+ * @param {object} mConfig Configuration object
1231
+ * @param {boolean} mConfig.fixedColumns True if fixed columns area
1232
+ * @param {int} mConfig.startColumnIndex Start column index (inclusive)
1233
+ * @param {int} mConfig.endColumnIndex End column index (exclusive)
1234
+ * @param {int} mConfig.startRowIndex Start row index (inclusive)
1235
+ * @param {int} mConfig.endRowIndex End row index (exclusive)
1236
+ * @param {sap.ui.table.Column[]} mConfig.visibleColumns Visible columns
1237
+ * @param {boolean} mConfig.renderDummyColumn True if dummy column should be rendered
1238
+ * @private
1239
+ */
1240
+ TableRenderer._renderDataRows = function(rm, oTable, mConfig) {
1241
+ const {fixedColumns, startColumnIndex, endColumnIndex, visibleColumns, renderDummyColumn} = mConfig;
1242
+ const aRows = oTable.getRows();
963
1243
 
1244
+ if (aRows.length === 0) {
1245
+ return;
1246
+ }
1247
+
1248
+ const bRowsDraggable = oTable.getDragDropConfig().some(function(oDragDropInfo) {
1249
+ return oDragDropInfo.isDraggable(oTable, "rows");
1250
+ });
1251
+ const iLastFixedColumnIndex = this.getLastFixedColumnIndex(oTable);
1252
+
1253
+ for (let iRowIndex = mConfig.startRowIndex; iRowIndex < mConfig.endRowIndex; iRowIndex++) {
1254
+ this.renderDataRow(rm, oTable, aRows[iRowIndex], {
1255
+ rowIndex: iRowIndex,
1256
+ fixedColumns,
1257
+ startColumnIndex: startColumnIndex,
1258
+ endColumnIndex: endColumnIndex,
1259
+ visibleColumns,
1260
+ lastFixedColumnIndex: iLastFixedColumnIndex,
1261
+ renderDummyColumn,
1262
+ draggable: bRowsDraggable
1263
+ });
1264
+ }
1265
+ };
1266
+
1267
+ /**
1268
+ * Writes the content of a row selector cell including group icons and accessibility text.
1269
+ *
1270
+ * @param {sap.ui.core.RenderManager} rm RenderManager instance
1271
+ * @param {sap.ui.table.Table} oTable Table instance
1272
+ * @param {sap.ui.table.Row} oRow Row instance
1273
+ */
964
1274
  TableRenderer.writeRowSelectorContent = function(rm, oTable, oRow) {
965
1275
  oTable._getAccRenderExtension().writeAccRowSelectorText(rm, oTable, oRow);
966
1276
 
@@ -979,12 +1289,11 @@ sap.ui.define([
979
1289
  /**
980
1290
  * Writes the row highlight element (including the accessibility text element) to the render manager.
981
1291
  *
982
- * @param {sap.ui.core.RenderManager} rm The render manager to write to
983
- * @param {sap.ui.table.Table} oTable Instance of the table
984
- * @param {sap.ui.table.Row} oRow Instance of the row
985
- * @param {int} iRowIndex Index of the row
1292
+ * @param {sap.ui.core.RenderManager} rm RenderManager instance
1293
+ * @param {sap.ui.table.Table} oTable Table instance
1294
+ * @param {sap.ui.table.Row} oRow Row instance
986
1295
  */
987
- TableRenderer.writeRowHighlightContent = function(rm, oTable, oRow, iRowIndex) {
1296
+ TableRenderer.writeRowHighlightContent = function(rm, oTable, oRow) {
988
1297
  if (!TableUtils.hasRowHighlights(oTable)) {
989
1298
  return;
990
1299
  }
@@ -996,224 +1305,779 @@ sap.ui.define([
996
1305
  rm.class("sapUiTableRowHighlight");
997
1306
  rm.class(sHighlightClass);
998
1307
  rm.openEnd();
999
- oTable._getAccRenderExtension().writeAccRowHighlightText(rm, oTable, oRow, iRowIndex);
1308
+ oTable._getAccRenderExtension().writeAccRowHighlightText(rm, oTable, oRow);
1309
+ rm.close("div");
1310
+ };
1311
+
1312
+ /**
1313
+ * Writes the navigation indicator for a row (including the accessibility text element) to the render manager.
1314
+ *
1315
+ * @param {sap.ui.core.RenderManager} rm RenderManager instance
1316
+ * @param {sap.ui.table.Table} oTable Table instance
1317
+ * @param {sap.ui.table.Row} oRow Row instance
1318
+ */
1319
+ TableRenderer.writeRowNavigationContent = function(rm, oTable, oRow) {
1320
+ if (!TableUtils.hasRowNavigationIndicators(oTable)) {
1321
+ return;
1322
+ }
1323
+
1324
+ const oRowSettings = oRow.getAggregation("_settings");
1325
+
1326
+ rm.openStart("div", oRow.getId() + "-navIndicator");
1327
+ if (oRowSettings.getNavigated()) {
1328
+ rm.class("sapUiTableRowNavigated");
1329
+ }
1330
+ rm.openEnd();
1000
1331
  rm.close("div");
1001
1332
  };
1002
1333
 
1003
1334
  /**
1004
- * Writes the navigation indicator for a row (including the accessibility text element) to the render manager.
1335
+ * Renders a column header row.
1336
+ *
1337
+ * @param {sap.ui.core.RenderManager} rm RenderManager instance
1338
+ * @param {sap.ui.table.Table} oTable Table instance
1339
+ * @param {object} mConfig Configuration object
1340
+ * @param {boolean} mConfig.fixedColumns True if fixed columns area
1341
+ * @param {int} mConfig.startColumnIndex Start column index (inclusive)
1342
+ * @param {int} mConfig.endColumnIndex End column index (exclusive)
1343
+ * @param {boolean} mConfig.renderDummyColumn True if only fixed columns are present
1344
+ * @param {boolean} mConfig.isLastRow True if last header row
1345
+ * @private
1346
+ */
1347
+ TableRenderer.renderColumnHeaderRow = function(rm, oTable, mConfig) {
1348
+ const {rowIndex, fixedColumns, startColumnIndex, endColumnIndex, isLastRow} = mConfig;
1349
+ const oAccRenderExtension = oTable._getAccRenderExtension();
1350
+
1351
+ rm.openStart("tr");
1352
+ rm.class("sapUiTableRow");
1353
+ rm.class("sapUiTableHeaderRow");
1354
+ rm.class("sapUiTableColHdrTr");
1355
+ oAccRenderExtension.writeAriaAttributesFor(rm, oTable, "ColumnHeaderRow", {rowIndex, fixedCol: fixedColumns});
1356
+ rm.openEnd();
1357
+
1358
+ const aColumns = this.getColumnsToRender(oTable, startColumnIndex, endColumnIndex);
1359
+ const iLastVisibleColumnIndex = this._collectHeaderSpans(aColumns, rowIndex);
1360
+ this._renderHeaderColumns(rm, oTable, aColumns, {rowIndex, fixedColumns, lastVisibleColumnIndex: iLastVisibleColumnIndex, isLastRow});
1361
+
1362
+ if (!fixedColumns && mConfig.renderDummyColumn && aColumns.length > 0) {
1363
+ this._renderDummyColumnContentCell(rm, oTable);
1364
+ }
1365
+
1366
+ rm.close("tr");
1367
+ };
1368
+
1369
+ /**
1370
+ * Calculates column spans for header cells in multi-label scenarios and returns the index of the last visible column.
1371
+ *
1372
+ * @param {sap.ui.table.Column[]} aColumns Array of columns to process
1373
+ * @param {int} iRowIndex Header row index
1374
+ * @returns {int} Index of the last visible column
1375
+ * @private
1376
+ */
1377
+ TableRenderer._collectHeaderSpans = function(aColumns, iRowIndex) {
1378
+ let nSpan = 0;
1379
+ let iLastVisibleCol = -1;
1380
+
1381
+ aColumns.forEach(function(oColumn, index, aCols) {
1382
+ let colSpan = TableUtils.Column.getHeaderSpan(oColumn, iRowIndex);
1383
+ let iColIndex;
1384
+
1385
+ if (nSpan < 1) {
1386
+ if (colSpan > 1) {
1387
+ // In case when a user makes some of the underlying columns invisible, adjust colspan
1388
+ iColIndex = oColumn.getIndex();
1389
+ colSpan = aCols.slice(index + 1, index + colSpan).reduce(function(span, column) {
1390
+ return column.getIndex() - iColIndex < colSpan ? span + 1 : span;
1391
+ }, 1);
1392
+ }
1393
+
1394
+ oColumn._nSpan = nSpan = colSpan;
1395
+ iLastVisibleCol = index;
1396
+ } else {
1397
+ // Render column header but this is invisible because of the previous span
1398
+ oColumn._nSpan = 0;
1399
+ }
1400
+ nSpan--;
1401
+ });
1402
+
1403
+ return iLastVisibleCol;
1404
+ };
1405
+
1406
+ /**
1407
+ * Renders all column headers in a header row.
1408
+ *
1409
+ * @param {sap.ui.core.RenderManager} rm RenderManager instance
1410
+ * @param {sap.ui.table.Table} oTable Table instance
1411
+ * @param {sap.ui.table.Column[]} aColumns Array of columns to render
1412
+ * @param {object} mConfig Configuration object
1413
+ * @param {int} mConfig.rowIndex Header row index
1414
+ * @param {boolean} mConfig.fixedColumns True if fixed columns area
1415
+ * @param {int} mConfig.lastVisibleColumnIndex Index of the last visible column
1416
+ * @param {boolean} mConfig.isLastRow True if last header row
1417
+ * @private
1418
+ */
1419
+ TableRenderer._renderHeaderColumns = function(rm, oTable, aColumns, mConfig) {
1420
+ aColumns.forEach((oColumn, iIndex) => {
1421
+ this.renderColumnHeaderCell(rm, oTable, oColumn, {
1422
+ rowIndex: mConfig.rowIndex,
1423
+ span: oColumn._nSpan,
1424
+ isFirstColumn: iIndex === 0,
1425
+ isLastFixedColumn: mConfig.fixedColumns && (iIndex === mConfig.lastVisibleColumnIndex),
1426
+ isLastColumn: !mConfig.fixedColumns && (iIndex === mConfig.lastVisibleColumnIndex),
1427
+ renderIcons: oColumn._nSpan === 1 && !oColumn._bIconsRendered
1428
+ });
1429
+ oColumn._bIconsRendered = oColumn._bIconsRendered || oColumn._nSpan === 1;
1430
+ delete oColumn._nSpan;
1431
+
1432
+ if (mConfig.isLastRow) {
1433
+ delete oColumn._bIconsRendered;
1434
+ }
1435
+ });
1436
+ };
1437
+
1438
+ /**
1439
+ * Renders a column header cell.
1440
+ *
1441
+ * @param {sap.ui.core.RenderManager} rm RenderManager instance
1442
+ * @param {sap.ui.table.Table} oTable Table instance
1443
+ * @param {sap.ui.table.Column} oColumn Column instance to render
1444
+ * @param {object} mConfig Configuration object
1445
+ * @param {int} mConfig.rowIndex Header row index
1446
+ * @param {int} mConfig.span Computed column span (0 = hidden in this row)
1447
+ * @param {boolean} mConfig.isFirstColumn True if first visible column in area
1448
+ * @param {boolean} mConfig.isLastFixedColumn True if last visible fixed column
1449
+ * @param {boolean} mConfig.isLastColumn True if last visible column overall
1450
+ * @param {boolean} mConfig.renderIcons True if sort/filter icons should be rendered
1451
+ * @private
1452
+ */
1453
+ TableRenderer.renderColumnHeaderCell = function(rm, oTable, oColumn, mConfig) {
1454
+ const sHeaderId = mConfig.rowIndex === 0 ? oColumn.getId() : `${oColumn.getId()}_${mConfig.rowIndex}`;
1455
+
1456
+ rm.openStart("td", mConfig.rowIndex === 0 ? oColumn : sHeaderId);
1457
+ this._decorateColumnHeaderCell(rm, oTable, oColumn, {
1458
+ span: mConfig.span,
1459
+ isFirstColumn: mConfig.isFirstColumn,
1460
+ isLastFixedColumn: mConfig.isLastFixedColumn,
1461
+ isLastColumn: mConfig.isLastColumn,
1462
+ renderIcons: mConfig.renderIcons,
1463
+ headerId: sHeaderId
1464
+ });
1465
+ rm.openEnd();
1466
+
1467
+ rm.openStart("div", sHeaderId + "-inner");
1468
+ this._decorateColumnHeaderCellInner(rm, oTable, oColumn, {isFirstColumn: mConfig.isFirstColumn});
1469
+ rm.openEnd();
1470
+ rm.openStart("div");
1471
+ rm.style("justify-content", mFlexCellContentAlignment[oColumn.getHAlign()]);
1472
+ rm.openEnd();
1473
+ this._renderColumnHeaderCellContent(rm, oColumn, {rowIndex: mConfig.rowIndex});
1474
+ rm.close("div");
1475
+ rm.close("div");
1476
+
1477
+ rm.close("td");
1478
+ };
1479
+
1480
+ /**
1481
+ * Decorates a column header cell with attributes, styles and CSS classes.
1482
+ *
1483
+ * @param {sap.ui.core.RenderManager} rm RenderManager instance
1484
+ * @param {sap.ui.table.Table} oTable Table instance
1485
+ * @param {sap.ui.table.Column} oColumn Column instance
1486
+ * @param {object} mConfig Configuration object
1487
+ * @param {int} mConfig.span Computed column span (0 = hidden in this row)
1488
+ * @param {boolean} mConfig.isFirstColumn True if first column
1489
+ * @param {boolean} mConfig.isLastFixedColumn True if last fixed column
1490
+ * @param {boolean} mConfig.isLastColumn True if last column
1491
+ * @param {boolean} mConfig.renderIcons True if sort and filter icons should be rendered
1492
+ * @param {string} mConfig.headerId Header ID
1493
+ * @private
1494
+ */
1495
+ TableRenderer._decorateColumnHeaderCell = function(rm, oTable, oColumn, mConfig) {
1496
+ const {span, headerId, isFirstColumn, isLastFixedColumn, isLastColumn, renderIcons} = mConfig;
1497
+
1498
+ this._setColumnHeaderCellAttributes(rm, oTable, oColumn, {span, headerId});
1499
+ this._setColumnHeaderCellStyles(rm, oTable);
1500
+ this._addColumnHeaderCellClasses(rm, oTable, oColumn, {
1501
+ isFirstColumn,
1502
+ isLastFixedColumn,
1503
+ isLastColumn,
1504
+ isHiddenBySpan: !span,
1505
+ renderIcons
1506
+ });
1507
+ };
1508
+
1509
+ /**
1510
+ * Sets column header cell attributes.
1511
+ *
1512
+ * @param {sap.ui.core.RenderManager} rm RenderManager instance
1513
+ * @param {sap.ui.table.Table} oTable Table instance
1514
+ * @param {sap.ui.table.Column} oColumn Column instance
1515
+ * @param {object} mConfig Configuration object
1516
+ * @param {int} mConfig.span Computed column span (0 = hidden in this row)
1517
+ * @param {string} mConfig.headerId Header ID
1518
+ * @private
1519
+ */
1520
+ TableRenderer._setColumnHeaderCellAttributes = function(rm, oTable, oColumn, mConfig) {
1521
+ rm.attr('data-sap-ui-related', oColumn.getId());
1522
+ rm.attr('data-sap-ui-colid', oColumn.getId());
1523
+ rm.attr("data-sap-ui-colindex", oColumn.getIndex());
1524
+ rm.attr("tabindex", "-1");
1525
+
1526
+ if (mConfig.span > 1) {
1527
+ rm.attr("colspan", mConfig.span);
1528
+ }
1529
+
1530
+ const sTooltip = oColumn.getTooltip_AsString();
1531
+ if (sTooltip) {
1532
+ rm.attr("title", sTooltip);
1533
+ }
1534
+
1535
+ oTable._getAccRenderExtension().writeAriaAttributesFor(rm, oTable, "ColumnHeader", {
1536
+ column: oColumn,
1537
+ headerId: mConfig.headerId,
1538
+ colspan: mConfig.span > 1
1539
+ });
1540
+ };
1541
+
1542
+ /**
1543
+ * Sets column header cell styles.
1544
+ *
1545
+ * @param {sap.ui.core.RenderManager} rm RenderManager instance
1546
+ * @param {sap.ui.table.Table} oTable Table instance
1547
+ * @private
1548
+ */
1549
+ TableRenderer._setColumnHeaderCellStyles = function(rm, oTable) {
1550
+ const iColumnHeaderHeight = oTable.getColumnHeaderHeight();
1551
+
1552
+ if (iColumnHeaderHeight > 0) {
1553
+ rm.style("height", iColumnHeaderHeight + "px");
1554
+ }
1555
+ };
1556
+
1557
+ /**
1558
+ * Adds column header cell CSS classes.
1559
+ *
1560
+ * @param {sap.ui.core.RenderManager} rm RenderManager instance
1561
+ * @param {sap.ui.table.Table} oTable Table instance
1562
+ * @param {sap.ui.table.Column} oColumn Column instance
1563
+ * @param {object} mConfig Configuration object
1564
+ * @param {boolean} mConfig.isFirstColumn True if first column
1565
+ * @param {boolean} mConfig.isLastFixedColumn True if last fixed column
1566
+ * @param {boolean} mConfig.isLastColumn True if last column
1567
+ * @param {boolean} mConfig.isHiddenBySpan True if hidden because of span
1568
+ * @param {boolean} mConfig.renderIcons True if sort and filter icons should be rendered
1569
+ * @private
1570
+ */
1571
+ TableRenderer._addColumnHeaderCellClasses = function(rm, oTable, oColumn, mConfig) {
1572
+ rm.class("sapUiTableCell");
1573
+ rm.class("sapUiTableHeaderCell");
1574
+ rm.class("sapUiTableHeaderDataCell");
1575
+
1576
+ const oColumnHeaderMenu = oColumn.getHeaderMenuInstance();
1577
+ if (oTable.getEnableColumnReordering() || oColumnHeaderMenu && oColumnHeaderMenu.getAriaHasPopupType() !== "None") {
1578
+ rm.class("sapUiTableHeaderCellActive");
1579
+ }
1580
+
1581
+ /**
1582
+ * @deprecated As of Version 1.117
1583
+ */
1584
+ if (!oTable.getEnableColumnReordering() && !oTable.hasListeners("columnSelect") &&
1585
+ !oColumnHeaderMenu && oColumn._menuHasItems()) {
1586
+ rm.class("sapUiTableHeaderCellActive");
1587
+ }
1588
+
1589
+ if (mConfig.isHiddenBySpan) {
1590
+ rm.class("sapUiTableHidden");
1591
+ }
1592
+
1593
+ const {isFirstColumn, isLastFixedColumn, isLastColumn} = mConfig;
1594
+ this._addCellPositionClasses(rm, {isFirstColumn, isLastFixedColumn, isLastColumn});
1595
+
1596
+ if (mConfig.renderIcons) {
1597
+ this._addColumnSortAndFilterClasses(rm, oColumn);
1598
+ }
1599
+ };
1600
+
1601
+ /**
1602
+ * Adds sorting and filtering marker CSS classes to a header cell.
1603
+ *
1604
+ * @param {sap.ui.core.RenderManager} rm RenderManager instance
1605
+ * @param {sap.ui.table.Column} oColumn Column instance
1606
+ * @private
1607
+ */
1608
+ TableRenderer._addColumnSortAndFilterClasses = function(rm, oColumn) {
1609
+ const bFiltered = oColumn.getFiltered();
1610
+ let bSorted = oColumn.getSortOrder() !== SortOrder.None;
1611
+
1612
+ if (bFiltered) {
1613
+ rm.class("sapUiTableColFiltered");
1614
+ }
1615
+
1616
+ /** @deprecated As of version 1.120 */
1617
+ if (!oColumn.getSorted()) {
1618
+ bSorted = false;
1619
+ }
1620
+
1621
+ if (bSorted) {
1622
+ rm.class("sapUiTableColSorted");
1623
+ if (oColumn.getSortOrder() === SortOrder.Descending) {
1624
+ rm.class("sapUiTableColSortedD");
1625
+ }
1626
+ }
1627
+ };
1628
+
1629
+ /**
1630
+ * Decorates the cell content wrapper of a column header cell with attributes, styles and CSS classes.
1631
+ *
1632
+ * @param {sap.ui.core.RenderManager} rm RenderManager instance
1633
+ * @param {sap.ui.table.Table} oTable Table instance
1634
+ * @param {sap.ui.table.Column} oColumn Column instance
1635
+ * @param {object} mConfig Configuration object
1636
+ * @param {boolean} mConfig.isFirstColumn True if first visible column in area
1637
+ * @private
1638
+ */
1639
+ TableRenderer._decorateColumnHeaderCellInner = function(rm, oTable, oColumn, mConfig) {
1640
+ const sHAlign = oColumn.getHAlign();
1641
+
1642
+ rm.class("sapUiTableCellInner");
1643
+
1644
+ if (!TableUtils.hasRowHeader(oTable) && mConfig.isFirstColumn &&
1645
+ !TableUtils.hasRowHighlights(oTable) && !TableUtils.Grouping.isInTreeMode(oTable)) {
1646
+ rm.class("sapUiTableFirstColumnCell");
1647
+ }
1648
+
1649
+ const sTextAlign = Renderer.getTextAlign(sHAlign);
1650
+ if (sTextAlign) {
1651
+ rm.style("text-align", sTextAlign);
1652
+ }
1653
+ };
1654
+
1655
+ /**
1656
+ * Renders the content of a column header cell.
1657
+ *
1658
+ * @param {sap.ui.core.RenderManager} rm RenderManager instance
1659
+ * @param {sap.ui.table.Column} oColumn Column instance
1660
+ * @param {object} mConfig Configuration object
1661
+ * @param {int} mConfig.rowIndex Header row index
1662
+ * @private
1663
+ */
1664
+ TableRenderer._renderColumnHeaderCellContent = function(rm, oColumn, mConfig) {
1665
+ const oAction = oColumn.getAggregation("_action");
1666
+ const oLabel = this._getColumnLabel(oColumn, mConfig.rowIndex);
1667
+
1668
+ if (oAction && mConfig.rowIndex === 0) {
1669
+ if (oColumn.getMultiLabels().length > 0) {
1670
+ Log.error(`${oColumn}: ColumnAIAction is not compatible with multi labels`);
1671
+ } else {
1672
+ rm.renderControl(oAction);
1673
+ }
1674
+ }
1675
+
1676
+ if (oLabel) {
1677
+ rm.renderControl(oLabel);
1678
+ }
1679
+ };
1680
+
1681
+ /**
1682
+ * Gets the label for a column header.
1005
1683
  *
1006
- * @param {sap.ui.core.RenderManager} rm The render manager to which the indicator is written
1007
- * @param {sap.ui.table.Table} oTable Instance of the table
1008
- * @param {sap.ui.table.Row} oRow Instance of the row
1009
- * @param {int} iRowIndex Index of the row
1684
+ * @param {sap.ui.table.Column} oColumn Column instance
1685
+ * @param {int} iHeader Header index
1686
+ * @returns {sap.ui.core.Control|undefined} Header label control or undefined if none exists
1687
+ * @private
1010
1688
  */
1011
- TableRenderer.writeRowNavigationContent = function(rm, oTable, oRow, iRowIndex) {
1012
- if (!TableUtils.hasRowNavigationIndicators(oTable)) {
1013
- return;
1689
+ TableRenderer._getColumnLabel = function(oColumn, iHeader) {
1690
+ const aLabels = oColumn.getMultiLabels();
1691
+
1692
+ if (aLabels.length > 0) {
1693
+ return aLabels[iHeader];
1694
+ } else if (iHeader === 0) {
1695
+ return oColumn.getLabel();
1014
1696
  }
1015
1697
 
1016
- const oRowSettings = oRow.getAggregation("_settings");
1698
+ return undefined;
1699
+ };
1017
1700
 
1018
- rm.openStart("div", oRow.getId() + "-navIndicator");
1019
- if (oRowSettings.getNavigated()) {
1020
- rm.class("sapUiTableRowNavigated");
1701
+ /**
1702
+ * Renders a data row.
1703
+ *
1704
+ * @param {sap.ui.core.RenderManager} rm RenderManager instance
1705
+ * @param {sap.ui.table.Table} oTable Table instance
1706
+ * @param {sap.ui.table.Row} oRow Row instance
1707
+ * @param {object} mConfig Configuration object
1708
+ * @param {int} mConfig.rowIndex Index of the row in the aggregation
1709
+ * @param {boolean} mConfig.fixedColumns True if rendering in the fixed columns area
1710
+ * @param {int} mConfig.startColumnIndex Start column index (inclusive)
1711
+ * @param {int} mConfig.endColumnIndex End column index (exclusive)
1712
+ * @param {sap.ui.table.Column[]} mConfig.visibleColumns Visible columns
1713
+ * @param {int|undefined} mConfig.lastFixedColumnIndex Index of last fixed column (or undefined if none)
1714
+ * @param {boolean} mConfig.renderDummyColumn True if a dummy column should be rendered (scrollable area balancing)
1715
+ * @param {boolean} mConfig.draggable True if row is draggable
1716
+ * @private
1717
+ */
1718
+ TableRenderer.renderDataRow = function(rm, oTable, oRow, mConfig) {
1719
+ const {rowIndex, fixedColumns, draggable} = mConfig;
1720
+
1721
+ if (fixedColumns) {
1722
+ rm.openStart("tr", oRow.getId() + "-fixed");
1723
+ } else {
1724
+ rm.openStart("tr", oRow);
1021
1725
  }
1022
- rm.openEnd();
1023
- rm.close("div");
1024
- };
1025
1726
 
1026
- TableRenderer.renderColumnHeaderRow = function(rm, oTable, iRow, bFixedTable, iStartColumn, iEndColumn, bHasOnlyFixedColumns, bLastRow) {
1027
- rm.openStart("tr");
1028
- rm.class("sapUiTableRow");
1029
- rm.class("sapUiTableHeaderRow");
1030
- rm.class("sapUiTableColHdrTr");
1031
- const oAccRenderExtension = oTable._getAccRenderExtension();
1032
- oAccRenderExtension.writeAriaAttributesFor(rm, oTable, "ColumnHeaderRow", {rowIndex: iRow, fixedCol: bFixedTable});
1727
+ this._decorateDataRow(rm, oTable, oRow, {rowIndex, fixedColumns, draggable});
1033
1728
  rm.openEnd();
1034
1729
 
1035
- //
1036
- // Render header cells
1037
- //
1038
- const aColumns = this.getColumnsToRender(oTable, iStartColumn, iEndColumn);
1039
- let nSpan = 0;
1040
- let iLastVisibleCol = -1;
1041
-
1042
- // collect header spans and find the last visible column header
1043
- function collectHeaderSpans(oColumn, index, aCols) {
1044
- let colSpan = ColumnUtils.getHeaderSpan(oColumn, iRow);
1045
- let iColIndex;
1730
+ const {startColumnIndex, endColumnIndex, visibleColumns, lastFixedColumnIndex, renderDummyColumn} = mConfig;
1731
+ this._renderDataCells(rm, oTable, oRow, {
1732
+ fixedColumns,
1733
+ startColumnIndex,
1734
+ endColumnIndex,
1735
+ visibleColumns,
1736
+ lastFixedColumnIndex,
1737
+ renderDummyColumn
1738
+ });
1046
1739
 
1047
- if (nSpan < 1) {
1048
- if (colSpan > 1) {
1049
- // In case when a user makes some of the underlying columns invisible, adjust colspan
1050
- iColIndex = oColumn.getIndex();
1051
- colSpan = aCols.slice(index + 1, index + colSpan).reduce(function(span, column) {
1052
- return column.getIndex() - iColIndex < colSpan ? span + 1 : span;
1053
- }, 1);
1054
- }
1740
+ rm.close("tr");
1741
+ };
1055
1742
 
1056
- oColumn._nSpan = nSpan = colSpan;
1057
- iLastVisibleCol = index;
1058
- } else {
1059
- //Render column header but this is invisible because of the previous span
1060
- oColumn._nSpan = 0;
1061
- }
1062
- nSpan--;
1063
- }
1064
- aColumns.forEach(collectHeaderSpans);
1743
+ /**
1744
+ * Decorates a data row with attributes, styles and CSS classes.
1745
+ *
1746
+ * @param {sap.ui.core.RenderManager} rm RenderManager instance
1747
+ * @param {sap.ui.table.Table} oTable Table instance
1748
+ * @param {sap.ui.table.Row} oRow Row instance
1749
+ * @param {object} mConfig Configuration object
1750
+ * @param {int} mConfig.rowIndex Index of the row in the aggregation
1751
+ * @param {boolean} mConfig.fixedColumns True if rendering in the fixed columns area
1752
+ * @param {boolean} mConfig.draggable True if row is draggable
1753
+ * @private
1754
+ */
1755
+ TableRenderer._decorateDataRow = function(rm, oTable, oRow, mConfig) {
1756
+ const {rowIndex, fixedColumns, draggable} = mConfig;
1065
1757
 
1066
- function renderColumn(oColumn, iIndex) {
1067
- this.renderCol(rm, oTable, oColumn, iRow, oColumn._nSpan,
1068
- iIndex === 0,
1069
- bFixedTable && (iIndex === iLastVisibleCol),
1070
- !bFixedTable && (iIndex === iLastVisibleCol),
1071
- oColumn._nSpan === 1 && !oColumn._bIconsRendered);
1758
+ this._setDataRowAttributes(rm, oTable, oRow, {rowIndex, fixedColumns, draggable});
1759
+ this._addDataRowClasses(rm, oTable, oRow, {rowIndex});
1760
+ TableUtils.Hook.call(oTable, Hook.RenderRowStyles, rm);
1761
+ };
1072
1762
 
1073
- oColumn._bIconsRendered = oColumn._bIconsRendered || oColumn._nSpan === 1;
1074
- delete oColumn._nSpan;
1763
+ /**
1764
+ * Sets data row attributes.
1765
+ *
1766
+ * @param {sap.ui.core.RenderManager} rm RenderManager instance
1767
+ * @param {sap.ui.table.Table} oTable Table instance
1768
+ * @param {sap.ui.table.Row} oRow Row instance
1769
+ * @param {object} mConfig Configuration object
1770
+ * @param {int} mConfig.rowIndex Index of the row in the aggregation
1771
+ * @param {boolean} mConfig.fixedColumns True if rendering in the fixed columns area
1772
+ * @param {boolean} mConfig.draggable True if row is draggable
1773
+ * @private
1774
+ */
1775
+ TableRenderer._setDataRowAttributes = function(rm, oTable, oRow, mConfig) {
1776
+ rm.attr("data-sap-ui-rowindex", mConfig.rowIndex);
1075
1777
 
1076
- if (bLastRow) {
1077
- delete oColumn._bIconsRendered;
1078
- }
1778
+ if (mConfig.fixedColumns) {
1779
+ rm.attr("data-sap-ui-related", oRow.getId());
1079
1780
  }
1080
- aColumns.forEach(renderColumn.bind(this));
1081
1781
 
1082
- if (!bFixedTable && bHasOnlyFixedColumns && aColumns.length > 0) {
1083
- rm.openStart("td").class("sapUiTableCellDummy");
1084
- oAccRenderExtension.writeAriaAttributesFor(rm, oTable, "Presentation");
1085
- rm.openEnd().close("td");
1782
+ if (mConfig.draggable && mConfig.fixedColumns) {
1783
+ rm.attr("draggable", "true");
1784
+ rm.attr("data-sap-ui-draggable", "true");
1086
1785
  }
1087
- rm.close("tr");
1088
- };
1089
1786
 
1090
- TableRenderer.renderTableRow = function(rm, oTable, oRow, iRowIndex, bFixedTable, iStartColumn, iEndColumn, bFixedRow, aVisibleColumns, iLastFixedColumnIndex, bHasOnlyFixedColumns, bSelectOnCellsAllowed, bDraggable) {
1091
- if (!oRow) {
1092
- return;
1093
- }
1787
+ oTable._getAccRenderExtension().writeAriaAttributesFor(rm, oTable, "Tr", {
1788
+ index: mConfig.rowIndex,
1789
+ fixedCol: mConfig.fixedColumns,
1790
+ rowNavigated: oRow.getAggregation("_settings")?.getNavigated() ?? false
1791
+ });
1792
+ };
1094
1793
 
1095
- if (bFixedTable) {
1096
- rm.openStart("tr", oRow.getId() + "-fixed");
1097
- rm.attr("data-sap-ui-related", oRow.getId());
1098
- } else {
1099
- rm.openStart("tr", oRow);
1100
- }
1101
- if (oRow._bDummyRow) {
1102
- rm.style("opacity", "0");
1103
- }
1794
+ /**
1795
+ * Adds CSS classes to a data row.
1796
+ *
1797
+ * @param {sap.ui.core.RenderManager} rm RenderManager instance
1798
+ * @param {sap.ui.table.Table} oTable Table instance
1799
+ * @param {sap.ui.table.Row} oRow Row instance
1800
+ * @param {object} mConfig Configuration object
1801
+ * @param {int} mConfig.rowIndex Index of the row in the aggregation
1802
+ * @private
1803
+ */
1804
+ TableRenderer._addDataRowClasses = function(rm, oTable, oRow, mConfig) {
1104
1805
  rm.class("sapUiTableRow");
1105
1806
  rm.class("sapUiTableContentRow");
1106
1807
  rm.class("sapUiTableTr");
1107
1808
 
1108
- if (bDraggable && bFixedTable) {
1109
- rm.attr("draggable", "true");
1110
- rm.attr("data-sap-ui-draggable", "true");
1111
- }
1112
-
1113
1809
  if (oRow.isContentHidden()) {
1114
1810
  rm.class("sapUiTableRowHidden");
1115
1811
  } else if (oRow._isSelected()) {
1116
1812
  rm.class("sapUiTableRowSel");
1117
1813
  }
1118
1814
 
1119
- if (iRowIndex % 2 !== 0 && oTable.getAlternateRowColors() && !TableUtils.Grouping.isInTreeMode(oTable)) {
1815
+ if (mConfig.rowIndex % 2 !== 0 && oTable.getAlternateRowColors() && !TableUtils.Grouping.isInTreeMode(oTable)) {
1120
1816
  rm.class("sapUiTableRowAlternate");
1121
1817
  }
1122
1818
 
1123
- this.addRowCSSClasses(rm, oTable, iRowIndex);
1819
+ this.addRowClasses(rm, oTable, mConfig.rowIndex);
1820
+ };
1124
1821
 
1125
- rm.attr("data-sap-ui-rowindex", iRowIndex);
1126
- TableUtils.Hook.call(oTable, Hook.RenderRowStyles, rm);
1822
+ /**
1823
+ * Adds CSS classes to a row based on its position and table state.
1824
+ *
1825
+ * @param {sap.ui.core.RenderManager} rm RenderManager instance
1826
+ * @param {sap.ui.table.Table} oTable Table instance
1827
+ * @param {int} iIndex Index of the row in the aggregation
1828
+ * @private
1829
+ */
1830
+ TableRenderer.addRowClasses = function(rm, oTable, iIndex) {
1831
+ const mRowCounts = oTable._getRowCounts();
1832
+ const iFirstFixedBottomRowIndex = TableUtils.getFirstFixedBottomRowIndex(oTable);
1127
1833
 
1128
- const oRowSettings = oRow.getAggregation("_settings");
1129
- const oParams = {
1130
- index: iRowIndex,
1131
- fixedCol: bFixedTable,
1132
- rowNavigated: oRowSettings ? oRowSettings.getNavigated() : false
1133
- };
1134
- const oAccRenderExtension = oTable._getAccRenderExtension();
1135
- oAccRenderExtension.writeAriaAttributesFor(rm, oTable, "Tr", oParams);
1834
+ if (iIndex === 0) {
1835
+ rm.class("sapUiTableFirstRow");
1836
+ } else if (iIndex === oTable.getRows().length - 1) {
1837
+ rm.class("sapUiTableLastRow");
1838
+ }
1136
1839
 
1137
- rm.openEnd();
1840
+ if (mRowCounts.fixedTop > 0) {
1841
+ if (iIndex === mRowCounts.fixedTop - 1) {
1842
+ rm.class("sapUiTableRowLastFixedTop");
1843
+ }
1844
+ if (iIndex === mRowCounts.fixedTop) {
1845
+ rm.class("sapUiTableRowFirstScrollable");
1846
+ }
1847
+ }
1138
1848
 
1139
- const bSelected = !oRow.isEmpty() && oRow._isSelected(); //see TableRenderer.renderRowAddon
1140
- const aCells = oRow.getCells();
1849
+ if (iFirstFixedBottomRowIndex >= 0 && iFirstFixedBottomRowIndex === iIndex) {
1850
+ rm.class("sapUiTableRowFirstFixedBottom");
1851
+ } else if (iFirstFixedBottomRowIndex >= 1 && iFirstFixedBottomRowIndex - 1 === iIndex) {
1852
+ rm.class("sapUiTableRowLastScrollable");
1853
+ }
1854
+ };
1141
1855
 
1142
- for (let cell = 0, count = aCells.length; cell < count; cell++) {
1143
- this.renderTableCell(rm, oTable, oRow, aCells[cell], cell, bFixedTable, iStartColumn, iEndColumn, aVisibleColumns, iLastFixedColumnIndex, bSelected);
1856
+ /**
1857
+ * Renders all data cells for a row.
1858
+ *
1859
+ * @param {sap.ui.core.RenderManager} rm RenderManager instance
1860
+ * @param {sap.ui.table.Table} oTable Table instance
1861
+ * @param {sap.ui.table.Row} oRow Row instance
1862
+ * @param {object} mConfig Configuration object
1863
+ * @param {boolean} mConfig.fixedColumns True if fixed column area
1864
+ * @param {int} mConfig.startColumnIndex Start column index
1865
+ * @param {int} mConfig.endColumnIndex End column index
1866
+ * @param {sap.ui.table.Column[]} mConfig.visibleColumns Visible columns array
1867
+ * @param {int|undefined} mConfig.lastFixedColumnIndex Index of last fixed column
1868
+ * @param {boolean} mConfig.renderDummyColumn True if only fixed columns exist in this area
1869
+ */
1870
+ TableRenderer._renderDataCells = function(rm, oTable, oRow, mConfig) {
1871
+ const aCells = oRow.getCells();
1872
+ const {fixedColumns, startColumnIndex, endColumnIndex, visibleColumns, lastFixedColumnIndex} = mConfig;
1873
+
1874
+ for (let iCellIndex = 0, iCellCount = aCells.length; iCellIndex < iCellCount; iCellIndex++) {
1875
+ this._renderDataCell(rm, oTable, oRow, aCells[iCellIndex], {
1876
+ cellIndex: iCellIndex,
1877
+ fixedColumns,
1878
+ startColumnIndex,
1879
+ endColumnIndex,
1880
+ visibleColumns,
1881
+ lastFixedColumnIndex
1882
+ });
1144
1883
  }
1145
- if (!bFixedTable && bHasOnlyFixedColumns && aCells.length > 0) {
1146
- rm.openStart("td").class("sapUiTableCellDummy");
1147
- oAccRenderExtension.writeAriaAttributesFor(rm, oTable, "Presentation");
1148
- rm.openEnd();
1149
- rm.close("td");
1884
+
1885
+ if (!mConfig.fixedColumns && mConfig.renderDummyColumn && aCells.length > 0) {
1886
+ this._renderDummyColumnContentCell(rm, oTable);
1150
1887
  }
1151
- rm.close("tr");
1152
1888
  };
1153
1889
 
1154
- TableRenderer.renderTableCell = function(rm, oTable, oRow, oCell, iCellIndex, bFixedTable, iStartColumn, iEndColumn, aVisibleColumns, iLastFixedColumnIndex) {
1890
+ /**
1891
+ * Renders a content cell of the dummy column.
1892
+ *
1893
+ * @param {sap.ui.core.RenderManager} rm RenderManager instance
1894
+ * @param {sap.ui.table.Table} oTable Table instance
1895
+ * @private
1896
+ */
1897
+ TableRenderer._renderDummyColumnContentCell = function(rm, oTable) {
1898
+ rm.openStart("td").class("sapUiTableCellDummy");
1899
+ oTable._getAccRenderExtension().writeAriaAttributesFor(rm, oTable, "Presentation");
1900
+ rm.openEnd();
1901
+ rm.close("td");
1902
+ };
1903
+
1904
+ /**
1905
+ * Renders a data cell.
1906
+ *
1907
+ * @param {sap.ui.core.RenderManager} rm RenderManager instance
1908
+ * @param {sap.ui.table.Table} oTable Table instance
1909
+ * @param {sap.ui.table.Row} oRow Parent row instance
1910
+ * @param {sap.ui.core.Control} oCell Cell control to render
1911
+ * @param {object} mConfig Configuration object
1912
+ * @param {int} mConfig.cellIndex Index of the cell within the row
1913
+ * @param {boolean} mConfig.fixedColumns True if in fixed columns area
1914
+ * @param {int} mConfig.startColumnIndex Start column index
1915
+ * @param {int} mConfig.endColumnIndex End column index
1916
+ * @param {sap.ui.table.Column[]} mConfig.visibleColumns Visible columns
1917
+ * @param {int|undefined} mConfig.lastFixedColumnIndex Last fixed column index
1918
+ */
1919
+ TableRenderer._renderDataCell = function(rm, oTable, oRow, oCell, mConfig) {
1155
1920
  const oColumn = Column.ofCell(oCell);
1156
- const iColIndex = oColumn.getIndex();
1921
+ const iColumnIndex = oColumn.getIndex();
1922
+ const bShouldRenderCell = oColumn.shouldRender() && mConfig.startColumnIndex <= iColumnIndex && mConfig.endColumnIndex > iColumnIndex;
1157
1923
 
1158
- if (oColumn.shouldRender() && iStartColumn <= iColIndex && iEndColumn > iColIndex) {
1159
- const sId = oRow.getId() + "-col" + iCellIndex;
1160
- rm.openStart("td", sId);
1161
- rm.attr("tabindex", "-1");
1162
- rm.attr("data-sap-ui-colid", oColumn.getId());
1924
+ if (!bShouldRenderCell) {
1925
+ return;
1926
+ }
1163
1927
 
1164
- const nColumns = aVisibleColumns.length;
1165
- const bIsFirstColumn = nColumns > 0 && aVisibleColumns[0] === oColumn;
1166
- const bIsLastColumn = nColumns > 0 && aVisibleColumns[nColumns - 1] === oColumn;
1167
- const bIsLastFixedColumn = bFixedTable && iLastFixedColumnIndex === iColIndex;
1928
+ const iVisibleColumnCount = mConfig.visibleColumns.length;
1929
+ const bIsFirstColumn = iVisibleColumnCount > 0 && mConfig.visibleColumns[0] === oColumn;
1930
+ const bIsLastColumn = iVisibleColumnCount > 0 && mConfig.visibleColumns[iVisibleColumnCount - 1] === oColumn;
1931
+ const bIsLastFixedColumn = mConfig.fixedColumns && mConfig.lastFixedColumnIndex === iColumnIndex;
1168
1932
 
1169
- const oParams = {
1170
- column: oColumn
1171
- };
1172
- oTable._getAccRenderExtension().writeAriaAttributesFor(rm, oTable, "DataCell", oParams);
1933
+ rm.openStart("td", oRow.getId() + "-col" + mConfig.cellIndex);
1934
+ this._decorateDataCell(rm, oTable, oColumn, {
1935
+ isFirstColumn: bIsFirstColumn,
1936
+ isLastFixedColumn: bIsLastFixedColumn,
1937
+ isLastColumn: bIsLastColumn
1938
+ });
1939
+ rm.openEnd();
1940
+ this._renderDataCellContent(rm, oTable, oCell, oColumn, mConfig.visibleColumns);
1941
+ rm.close("td");
1942
+ };
1173
1943
 
1174
- const sTextAlign = Renderer.getTextAlign(oColumn.getHAlign());
1175
- if (sTextAlign) {
1176
- rm.style("text-align", sTextAlign);
1177
- }
1944
+ /**
1945
+ * Decorates a data cell with attributes, styles and CSS classes.
1946
+ *
1947
+ * @param {sap.ui.core.RenderManager} rm RenderManager instance
1948
+ * @param {sap.ui.table.Table} oTable Table instance
1949
+ * @param {sap.ui.table.Column} oColumn Column instance
1950
+ * @param {object} mConfig Configuration object
1951
+ * @param {boolean} mConfig.isFirstColumn True if first visible column
1952
+ * @param {boolean} mConfig.isLastFixedColumn True if last fixed column
1953
+ * @param {boolean} mConfig.isLastColumn True if last visible column overall
1954
+ * @private
1955
+ */
1956
+ TableRenderer._decorateDataCell = function(rm, oTable, oColumn, mConfig) {
1957
+ const {isFirstColumn, isLastFixedColumn, isLastColumn} = mConfig;
1178
1958
 
1179
- rm.class("sapUiTableCell");
1180
- rm.class("sapUiTableContentCell");
1181
- rm.class("sapUiTableDataCell");
1182
- if (bIsFirstColumn) {
1183
- rm.class("sapUiTableCellFirst");
1184
- }
1185
- if (bIsLastFixedColumn) {
1186
- rm.class("sapUiTableCellLastFixed");
1187
- }
1188
- if (bIsLastColumn) {
1189
- rm.class("sapUiTableCellLast");
1190
- }
1191
- if (bIsFirstColumn && TableUtils.Grouping.isInTreeMode(oTable)) {
1192
- rm.class("sapUiTableCellFlex"); // without flex, icon pushes contents too wide
1193
- }
1959
+ this._setDataCellAttributes(rm, oTable, oColumn);
1960
+ this._setDataCellStyles(rm, oColumn);
1961
+ this._addDataCellClasses(rm, oTable, {isFirstColumn, isLastFixedColumn, isLastColumn});
1962
+ };
1194
1963
 
1195
- rm.openEnd();
1964
+ /**
1965
+ * Writes data cell attributes.
1966
+ *
1967
+ * @param {sap.ui.core.RenderManager} rm RenderManager instance
1968
+ * @param {sap.ui.table.Table} oTable Table instance
1969
+ * @param {sap.ui.table.Column} oColumn Column instance
1970
+ * @private
1971
+ */
1972
+ TableRenderer._setDataCellAttributes = function(rm, oTable, oColumn) {
1973
+ rm.attr("tabindex", "-1");
1974
+ rm.attr("data-sap-ui-colid", oColumn.getId());
1975
+ oTable._getAccRenderExtension().writeAriaAttributesFor(rm, oTable, "DataCell", {
1976
+ column: oColumn
1977
+ });
1978
+ };
1196
1979
 
1197
- rm.openStart("div");
1198
- rm.class("sapUiTableCellInner");
1980
+ /**
1981
+ * Sets data cell styles.
1982
+ *
1983
+ * @param {sap.ui.core.RenderManager} rm RenderManager instance
1984
+ * @param {sap.ui.table.Column} oColumn Column instance
1985
+ * @private
1986
+ */
1987
+ TableRenderer._setDataCellStyles = function(rm, oColumn) {
1988
+ const sTextAlign = Renderer.getTextAlign(oColumn.getHAlign());
1199
1989
 
1200
- if (!TableUtils.hasRowHeader(oTable) && bIsFirstColumn && !TableUtils.hasRowHighlights(oTable) && !TableUtils.Grouping.isInTreeMode(oTable)) {
1201
- rm.class("sapUiTableFirstColumnCell");
1202
- }
1990
+ if (sTextAlign) {
1991
+ rm.style("text-align", sTextAlign);
1992
+ }
1993
+ };
1203
1994
 
1204
- TableUtils.Hook.call(oTable, Hook.RenderCellContentStyles, rm);
1995
+ /**
1996
+ * Adds data cell CSS classes.
1997
+ *
1998
+ * @param {sap.ui.core.RenderManager} rm RenderManager instance
1999
+ * @param {sap.ui.table.Table} oTable Table instance
2000
+ * @param {object} mConfig Configuration object
2001
+ * @param {boolean} mConfig.isFirstColumn True if first visible column
2002
+ * @param {boolean} mConfig.isLastFixedColumn True if last fixed column
2003
+ * @param {boolean} mConfig.isLastColumn True if last visible column overall
2004
+ * @private
2005
+ */
2006
+ TableRenderer._addDataCellClasses = function(rm, oTable, mConfig) {
2007
+ rm.class("sapUiTableCell");
2008
+ rm.class("sapUiTableContentCell");
2009
+ rm.class("sapUiTableDataCell");
1205
2010
 
1206
- rm.openEnd();
1207
- this.renderTableCellControl(rm, oTable, oCell, bIsFirstColumn);
1208
- rm.close("div");
2011
+ const {isFirstColumn, isLastFixedColumn, isLastColumn} = mConfig;
2012
+ this._addCellPositionClasses(rm, {isFirstColumn, isLastFixedColumn, isLastColumn});
2013
+
2014
+ if (mConfig.isFirstColumn && TableUtils.Grouping.isInTreeMode(oTable)) {
2015
+ rm.class("sapUiTableCellFlex"); // without flex, icon pushes contents too wide
2016
+ }
2017
+ };
2018
+
2019
+ /**
2020
+ * Adds positional marker CSS classes for a cell.
2021
+ *
2022
+ * @param {sap.ui.core.RenderManager} rm RenderManager instance
2023
+ * @param {object} mConfig Configuration object
2024
+ * @param {boolean} mConfig.isFirstColumn True if first visible column
2025
+ * @param {boolean} mConfig.isLastFixedColumn True if last fixed column
2026
+ * @param {boolean} mConfig.isLastColumn True if last visible column overall
2027
+ */
2028
+ TableRenderer._addCellPositionClasses = function(rm, mConfig) {
2029
+ if (mConfig.isFirstColumn) {
2030
+ rm.class("sapUiTableCellFirst");
2031
+ }
2032
+ if (mConfig.isLastFixedColumn) {
2033
+ rm.class("sapUiTableCellLastFixed");
2034
+ }
2035
+ if (mConfig.isLastColumn) {
2036
+ rm.class("sapUiTableCellLast");
2037
+ }
2038
+ };
2039
+
2040
+ /**
2041
+ * Renders the content of a data cell.
2042
+ *
2043
+ * @param {sap.ui.core.RenderManager} rm RenderManager instance
2044
+ * @param {sap.ui.table.Table} oTable Table instance
2045
+ * @param {sap.ui.core.Control} oCell Cell control
2046
+ * @param {sap.ui.table.Column} oColumn Column instance
2047
+ * @param {sap.ui.table.Column[]} aVisibleColumns Visible columns
2048
+ * @private
2049
+ */
2050
+ TableRenderer._renderDataCellContent = function(rm, oTable, oCell, oColumn, aVisibleColumns) {
2051
+ const nColumns = aVisibleColumns.length;
2052
+ const bIsFirstColumn = nColumns > 0 && aVisibleColumns[0] === oColumn;
2053
+
2054
+ rm.openStart("div");
2055
+ rm.class("sapUiTableCellInner");
1209
2056
 
1210
- rm.close("td");
2057
+ if (!TableUtils.hasRowHeader(oTable) && bIsFirstColumn && !TableUtils.hasRowHighlights(oTable) && !TableUtils.Grouping.isInTreeMode(oTable)) {
2058
+ rm.class("sapUiTableFirstColumnCell");
1211
2059
  }
2060
+
2061
+ TableUtils.Hook.call(oTable, Hook.RenderCellContentStyles, rm);
2062
+
2063
+ rm.openEnd();
2064
+ this.renderDataCellControl(rm, oTable, oCell, {isFirstColumn: bIsFirstColumn});
2065
+ rm.close("div");
1212
2066
  };
1213
2067
 
1214
- TableRenderer.renderTableCellControl = function(rm, oTable, oCell, bIsFirstColumn) {
1215
- if (bIsFirstColumn && TableUtils.Grouping.isInTreeMode(oTable)) {
2068
+ /**
2069
+ * Renders the inner control of a data cell including optional tree icon.
2070
+ *
2071
+ * @param {sap.ui.core.RenderManager} rm RenderManager instance
2072
+ * @param {sap.ui.table.Table} oTable Table instance
2073
+ * @param {sap.ui.core.Control} oCell Cell control
2074
+ * @param {object} mConfig Configuration object
2075
+ * @param {boolean} mConfig.isFirstColumn True if first visible column
2076
+ */
2077
+ TableRenderer.renderDataCellControl = function(rm, oTable, oCell, mConfig) {
2078
+ if (mConfig.isFirstColumn && TableUtils.Grouping.isInTreeMode(oTable)) {
1216
2079
  const oRow = oCell.getParent();
2080
+
1217
2081
  rm.openStart("span", oRow.getId() + "-treeicon");
1218
2082
  rm.class("sapUiTableTreeIcon");
1219
2083
  rm.attr("tabindex", "0");
@@ -1221,33 +2085,37 @@ sap.ui.define([
1221
2085
  rm.openEnd();
1222
2086
  rm.close("span");
1223
2087
  }
2088
+
1224
2089
  rm.renderControl(oCell);
1225
2090
  };
1226
2091
 
2092
+ /**
2093
+ * Renders the vertical scrollbar (internal container and content) of the table.
2094
+ *
2095
+ * @param {sap.ui.core.RenderManager} rm RenderManager instance
2096
+ * @param {sap.ui.table.Table} oTable Table instance
2097
+ * @param {object} [mConfig] Optional configuration object
2098
+ * @param {string} [mConfig.cssClass] Additional CSS class to apply
2099
+ * @private
2100
+ */
1227
2101
  TableRenderer.renderVSb = function(rm, oTable, mConfig) {
1228
2102
  const oScrollExtension = oTable._getScrollExtension();
1229
2103
 
1230
- mConfig = Object.assign({
1231
- tabIndex: true
1232
- }, mConfig);
1233
-
1234
2104
  rm.openStart("div");
1235
2105
  rm.class("sapUiTableVSbContainer");
1236
2106
  if (!oScrollExtension.isVerticalScrollbarRequired()) {
1237
2107
  rm.class("sapUiTableHidden");
1238
2108
  }
1239
- rm.class(mConfig.cssClass);
2109
+ rm.class(mConfig?.cssClass);
1240
2110
  rm.openEnd();
1241
2111
 
1242
2112
  rm.openStart("div", oTable.getId() + "-vsb");
1243
2113
  rm.class("sapUiTableVSb");
1244
2114
  rm.style("max-height", oScrollExtension.getVerticalScrollbarHeight() + "px");
1245
2115
 
1246
- if (mConfig.tabIndex) {
1247
- // https://bugzilla.mozilla.org/show_bug.cgi?id=1069739
1248
- // Avoid focusing of the scrollbar in Firefox with tab.
1249
- rm.attr("tabindex", "-1");
1250
- }
2116
+ // https://bugzilla.mozilla.org/show_bug.cgi?id=1069739
2117
+ // Avoid focusing of the scrollbar with tab.
2118
+ rm.attr("tabindex", "-1");
1251
2119
  rm.openEnd();
1252
2120
  rm.openStart("div");
1253
2121
  rm.class("sapUiTableVSbContent");
@@ -1259,22 +2127,39 @@ sap.ui.define([
1259
2127
  rm.close("div");
1260
2128
  };
1261
2129
 
2130
+ /**
2131
+ * Renders an external vertical scrollbar for synchronization scenarios.
2132
+ *
2133
+ * @param {sap.ui.core.RenderManager} rm RenderManager instance
2134
+ * @param {sap.ui.table.Table} oTable Table instance
2135
+ * @private
2136
+ */
1262
2137
  TableRenderer.renderVSbExternal = function(rm, oTable) {
1263
2138
  if (ExtensionBase.isEnrichedWith(oTable, "sap.ui.table.extensions.Synchronization")) {
1264
2139
  this.renderVSb(rm, oTable, {
1265
- cssClass: "sapUiTableVSbExternal",
1266
- tabIndex: false
2140
+ cssClass: "sapUiTableVSbExternal"
1267
2141
  });
1268
2142
  } else {
1269
2143
  Log.error("This method can only be used with synchronization enabled.", oTable, "TableRenderer.renderVSbExternal");
1270
2144
  }
1271
2145
  };
1272
2146
 
2147
+ /**
2148
+ * Renders the horizontal scrollbar of the table.
2149
+ *
2150
+ * @param {sap.ui.core.RenderManager} rm RenderManager instance
2151
+ * @param {sap.ui.table.Table} oTable Table instance
2152
+ * @param {object} [mConfig] Optional configuration object
2153
+ * @param {string} [mConfig.id] Scrollbar ID
2154
+ * @param {string} [mConfig.cssClass] Additional CSS class
2155
+ * @param {boolean} [mConfig.hidden=true] True if scrollbar initially hidden
2156
+ * @param {int} [mConfig.scrollWidth=0] Scroll content width
2157
+ * @private
2158
+ */
1273
2159
  TableRenderer.renderHSb = function(rm, oTable, mConfig) {
1274
2160
  mConfig = Object.assign({
1275
2161
  id: oTable.getId() + "-hsb",
1276
2162
  cssClass: "sapUiTableHSb",
1277
- tabIndex: true,
1278
2163
  hidden: true,
1279
2164
  scrollWidth: 0
1280
2165
  }, mConfig);
@@ -1284,9 +2169,7 @@ sap.ui.define([
1284
2169
  if (mConfig.hidden) {
1285
2170
  rm.class("sapUiTableHidden");
1286
2171
  }
1287
- if (mConfig.tabIndex) {
1288
- rm.attr("tabindex", "-1"); // Avoid focusing of the scrollbar in Firefox with tab.
1289
- }
2172
+ rm.attr("tabindex", "-1"); // Avoid focusing of the scrollbar with tab.
1290
2173
  rm.openEnd();
1291
2174
 
1292
2175
  rm.openStart("div", mConfig.id + "-content");
@@ -1300,49 +2183,69 @@ sap.ui.define([
1300
2183
  rm.close("div");
1301
2184
  };
1302
2185
 
1303
- TableRenderer.renderHSbExternal = function(rm, oTable, sId, iScrollWidth) {
2186
+ /**
2187
+ * Renders an external horizontal scrollbar for synchronization scenarios.
2188
+ *
2189
+ * @param {sap.ui.core.RenderManager} rm RenderManager instance
2190
+ * @param {sap.ui.table.Table} oTable Table instance
2191
+ * @param {object} mConfig Configuration object
2192
+ * @param {string} mConfig.id Scrollbar ID
2193
+ * @param {int} mConfig.scrollWidth Scroll content width
2194
+ */
2195
+ TableRenderer.renderHSbExternal = function(rm, oTable, mConfig) {
1304
2196
  if (ExtensionBase.isEnrichedWith(oTable, "sap.ui.table.extensions.Synchronization")) {
1305
2197
  this.renderHSb(rm, oTable, {
1306
- id: sId,
2198
+ id: mConfig.id,
1307
2199
  cssClass: "sapUiTableHSbExternal",
1308
- tabIndex: false,
1309
2200
  hidden: false,
1310
- scrollWidth: iScrollWidth
2201
+ scrollWidth: mConfig.scrollWidth
1311
2202
  });
1312
2203
  } else {
1313
- Log.error("This method can only be used with synchronization enabled.", oTable, "TableRenderer.renderVSbExternal");
2204
+ Log.error("This method can only be used with synchronization enabled.", oTable, "TableRenderer.renderHSbExternal");
1314
2205
  }
1315
2206
  };
1316
2207
 
2208
+ /**
2209
+ * Renders the horizontal scrollbar background area.
2210
+ *
2211
+ * @param {sap.ui.core.RenderManager} rm RenderManager instance
2212
+ * @param {sap.ui.table.Table} oTable Table instance
2213
+ * @private
2214
+ */
1317
2215
  TableRenderer.renderHSbBackground = function(rm, oTable) {
1318
2216
  rm.openStart("div", oTable.getId() + "-hsb-bg");
1319
2217
  rm.class("sapUiTableHSbBg");
1320
- rm.openEnd().close("div");
2218
+ rm.openEnd();
2219
+ rm.close("div");
1321
2220
  };
1322
2221
 
1323
- // =============================================================================
1324
- // HELPER FUNCTIONALITY
1325
- // =============================================================================
1326
-
1327
2222
  /**
1328
2223
  * Renders an empty area with tabindex=0 and the given class and id.
2224
+ *
2225
+ * @param {sap.ui.core.RenderManager} rm RenderManager instance
2226
+ * @param {object} mConfig Configuration object
2227
+ * @param {string} [mConfig.className] Optional CSS class name
2228
+ * @param {string|int} [mConfig.tabIndex="0"] Tab index to apply
2229
+ * @param {string} [mConfig.id] Optional ID to apply
1329
2230
  * @private
1330
2231
  */
1331
- TableRenderer.renderTabElement = function(rm, sClass, sTabIndex, sId) {
1332
- rm.openStart("div");
1333
- if (sClass) {
1334
- rm.class(sClass);
1335
- }
1336
- if (sId) {
1337
- rm.attr("id", sId);
2232
+ TableRenderer.renderTabElement = function(rm, mConfig) {
2233
+ rm.openStart("div", mConfig.id);
2234
+ if (mConfig.className) {
2235
+ rm.class(mConfig.className);
1338
2236
  }
1339
2237
  rm.attr("role", "none");
1340
- rm.attr("tabindex", sTabIndex == null ? "0" : sTabIndex);
2238
+ rm.attr("tabindex", mConfig.tabIndex == null ? "0" : String(mConfig.tabIndex));
1341
2239
  rm.openEnd().close("div");
1342
2240
  };
1343
2241
 
1344
2242
  /**
1345
- * Returns the columns with indices in the range between iStartIndex and iEndIndex that should be rendered.
2243
+ * Returns the columns with indices in the range between iStartIndex and iEndIndex that should be rendered.
2244
+ *
2245
+ * @param {sap.ui.table.Table} oTable Table instance
2246
+ * @param {int} iStartIndex Start index (inclusive)
2247
+ * @param {int} iEndIndex End index (exclusive)
2248
+ * @returns {sap.ui.table.Column[]} Columns to render
1346
2249
  * @private
1347
2250
  */
1348
2251
  TableRenderer.getColumnsToRender = function(oTable, iStartIndex, iEndIndex) {
@@ -1352,21 +2255,24 @@ sap.ui.define([
1352
2255
  };
1353
2256
 
1354
2257
  /**
1355
- * Returns the index of the last fixed column
2258
+ * Returns the index of the last fixed column.
2259
+ *
2260
+ * @param {sap.ui.table.Table} oTable Table instance
2261
+ * @returns {int} Index of last fixed column or -1 if there are no fixed columns
1356
2262
  * @private
1357
2263
  */
1358
2264
  TableRenderer.getLastFixedColumnIndex = function(oTable) {
1359
2265
  const iFixedColumnCount = oTable.getComputedFixedColumnCount();
1360
- const aCols = oTable.getColumns();
1361
- let oColumn; let iLastFixedColumnIndex;
2266
+ const aColumns = oTable.getColumns();
2267
+ let iLastFixedColumnIndex = -1;
1362
2268
 
1363
2269
  for (let i = iFixedColumnCount - 1; i >= 0; i--) {
1364
- oColumn = aCols[i];
1365
- if (oColumn.shouldRender()) {
2270
+ if (aColumns[i].shouldRender()) {
1366
2271
  iLastFixedColumnIndex = i;
1367
2272
  break;
1368
2273
  }
1369
2274
  }
2275
+
1370
2276
  return iLastFixedColumnIndex;
1371
2277
  };
1372
2278