@highcharts/grid-pro 2.2.0 → 2.3.1
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.
- package/LICENSE.txt +6 -0
- package/README.md +15 -9
- package/css/grid-pro.css +1262 -1122
- package/css/modules/grid-base-variables.css +131 -0
- package/css/modules/grid-button-variables.css +140 -0
- package/css/modules/grid-caption-variables.css +11 -0
- package/css/modules/grid-description-variables.css +11 -0
- package/css/modules/grid-input-variables.css +114 -0
- package/css/modules/grid-link-variables.css +18 -0
- package/css/modules/grid-menu-variables.css +50 -0
- package/css/modules/grid-pagination-variables.css +12 -0
- package/css/modules/grid-popup-variables.css +24 -0
- package/css/modules/grid-pro.css +234 -0
- package/css/modules/grid-table-variables.css +385 -0
- package/css/modules/grid-theme-default.css +55 -0
- package/es-modules/Accessibility/A11yI18n.js +1 -2
- package/es-modules/Accessibility/Accessibility.js +1 -2
- package/es-modules/Accessibility/AccessibilityComponent.d.ts +2 -2
- package/es-modules/Accessibility/Components/ContainerComponent.js +0 -1
- package/es-modules/Accessibility/Components/InfoRegionsComponent.js +6 -8
- package/es-modules/Accessibility/Components/LegendComponent.js +1 -2
- package/es-modules/Accessibility/Components/MenuComponent.js +1 -3
- package/es-modules/Accessibility/Components/NavigatorComponent.js +3 -4
- package/es-modules/Accessibility/Components/RangeSelectorComponent.js +1 -3
- package/es-modules/Accessibility/Components/SeriesComponent/ForcedMarkers.js +22 -11
- package/es-modules/Accessibility/Components/SeriesComponent/NewDataAnnouncer.js +3 -7
- package/es-modules/Accessibility/Components/SeriesComponent/SeriesComponent.js +0 -1
- package/es-modules/Accessibility/Components/SeriesComponent/SeriesDescriber.js +3 -5
- package/es-modules/Accessibility/Components/SeriesComponent/SeriesKeyboardNavigation.js +1 -4
- package/es-modules/Accessibility/Components/ZoomComponent.js +1 -2
- package/es-modules/Accessibility/FocusBorder.js +6 -7
- package/es-modules/Accessibility/KeyboardNavigation.js +1 -2
- package/es-modules/Accessibility/KeyboardNavigationHandler.js +1 -2
- package/es-modules/Accessibility/Options/A11yDefaults.d.ts +11 -0
- package/es-modules/Accessibility/Options/A11yDefaults.js +11 -0
- package/es-modules/Accessibility/Options/DeprecatedOptions.d.ts +58 -0
- package/es-modules/Accessibility/Options/DeprecatedOptions.js +8 -4
- package/es-modules/Accessibility/Options/LangDefaults.js +9 -0
- package/es-modules/Accessibility/ProxyElement.d.ts +2 -2
- package/es-modules/Accessibility/ProxyElement.js +4 -7
- package/es-modules/Accessibility/ProxyProvider.js +1 -2
- package/es-modules/Accessibility/Utils/Announcer.js +2 -3
- package/es-modules/Accessibility/Utils/ChartUtilities.js +1 -3
- package/es-modules/Accessibility/Utils/EventProvider.d.ts +2 -2
- package/es-modules/Accessibility/Utils/EventProvider.js +6 -2
- package/es-modules/Accessibility/Utils/HTMLUtilities.js +1 -3
- package/es-modules/Core/Animation/AnimationUtilities.js +1 -2
- package/es-modules/Core/Animation/Fx.js +1 -2
- package/es-modules/Core/Callback.d.ts +9 -2
- package/es-modules/Core/Chart/Chart.js +56 -42
- package/es-modules/Core/Chart/Chart3D.js +1 -2
- package/es-modules/Core/Chart/ChartDefaults.js +11 -0
- package/es-modules/Core/Chart/ChartNavigationComposition.js +0 -1
- package/es-modules/Core/Chart/ChartOptions.d.ts +8 -0
- package/es-modules/Core/Chart/GanttChart.js +1 -2
- package/es-modules/Core/Chart/MapChart.js +3 -2
- package/es-modules/Core/Chart/StockChart.js +2 -3
- package/es-modules/Core/Color/Color.js +1 -3
- package/es-modules/Core/Defaults.js +36 -10
- package/es-modules/Core/Delaunay.d.ts +1 -0
- package/es-modules/Core/Delaunay.js +312 -0
- package/es-modules/Core/Foundation.js +1 -3
- package/es-modules/Core/Geometry/CircleUtilities.js +1 -2
- package/es-modules/Core/Globals.js +1 -1
- package/es-modules/Core/HttpUtilities.js +1 -2
- package/es-modules/Core/MSPointer.js +1 -3
- package/es-modules/Core/Math3D.js +1 -2
- package/es-modules/Core/Options.d.ts +6 -2
- package/es-modules/Core/Pointer.js +23 -4
- package/es-modules/Core/PointerEvent.d.ts +2 -0
- package/es-modules/Core/Renderer/HTML/AST.js +2 -2
- package/es-modules/Core/Renderer/HTML/HTMLAttributes.d.ts +3 -0
- package/es-modules/Core/Renderer/HTML/HTMLElement.js +1 -2
- package/es-modules/Core/Renderer/RendererUtilities.js +34 -20
- package/es-modules/Core/Renderer/SVG/SVGRenderer.d.ts +1 -1
- package/es-modules/Core/Renderer/SVG/Symbols.d.ts +2 -2
- package/es-modules/Core/Responsive.d.ts +4 -2
- package/es-modules/Core/Responsive.js +10 -4
- package/es-modules/Core/Templating.d.ts +1 -1
- package/es-modules/Core/Templating.js +3 -4
- package/es-modules/Core/Time.d.ts +8 -0
- package/es-modules/Core/Time.js +2 -2
- package/es-modules/Core/Tooltip.d.ts +4 -8
- package/es-modules/Core/Tooltip.js +100 -81
- package/es-modules/Core/TooltipOptions.d.ts +44 -1
- package/es-modules/Core/Utilities.d.ts +25 -665
- package/es-modules/Core/Utilities.js +21 -1400
- package/es-modules/Data/ColumnUtils.d.ts +83 -80
- package/es-modules/Data/ColumnUtils.js +103 -113
- package/es-modules/Data/Connectors/CSVConnector.d.ts +9 -14
- package/es-modules/Data/Connectors/CSVConnector.js +3 -4
- package/es-modules/Data/Connectors/DataConnector.d.ts +56 -58
- package/es-modules/Data/Connectors/DataConnector.js +37 -56
- package/es-modules/Data/Connectors/GoogleSheetsConnector.d.ts +40 -42
- package/es-modules/Data/Connectors/GoogleSheetsConnector.js +73 -88
- package/es-modules/Data/Connectors/GoogleSheetsConnectorOptions.d.ts +4 -2
- package/es-modules/Data/Connectors/HTMLTableConnector.d.ts +23 -28
- package/es-modules/Data/Connectors/HTMLTableConnector.js +3 -4
- package/es-modules/Data/Connectors/JSONConnector.d.ts +9 -14
- package/es-modules/Data/Connectors/JSONConnector.js +3 -4
- package/es-modules/Data/Converters/CSVConverter.d.ts +5 -5
- package/es-modules/Data/Converters/CSVConverter.js +3 -4
- package/es-modules/Data/Converters/CSVConverterOptions.d.ts +2 -2
- package/es-modules/Data/Converters/DataConverter.d.ts +76 -78
- package/es-modules/Data/Converters/DataConverter.js +26 -53
- package/es-modules/Data/Converters/DataConverterUtils.d.ts +88 -81
- package/es-modules/Data/Converters/DataConverterUtils.js +169 -181
- package/es-modules/Data/Converters/GoogleSheetsConverter.d.ts +4 -4
- package/es-modules/Data/Converters/GoogleSheetsConverter.js +3 -3
- package/es-modules/Data/Converters/GoogleSheetsConverterOptions.d.ts +2 -2
- package/es-modules/Data/Converters/HTMLTableConverter.d.ts +4 -4
- package/es-modules/Data/Converters/HTMLTableConverter.js +2 -3
- package/es-modules/Data/Converters/HTMLTableConverterOptions.d.ts +2 -2
- package/es-modules/Data/Converters/JSONConverter.d.ts +7 -7
- package/es-modules/Data/Converters/JSONConverter.js +6 -6
- package/es-modules/Data/Converters/JSONConverterOptions.d.ts +2 -2
- package/es-modules/Data/DataCursor.d.ts +65 -70
- package/es-modules/Data/DataCursor.js +119 -139
- package/es-modules/Data/DataEvent.d.ts +55 -57
- package/es-modules/Data/DataPool.d.ts +10 -17
- package/es-modules/Data/DataPool.js +21 -10
- package/es-modules/Data/DataTable.d.ts +111 -113
- package/es-modules/Data/DataTable.js +3 -3
- package/es-modules/Data/DataTableCore.d.ts +9 -9
- package/es-modules/Data/DataTableCore.js +2 -2
- package/es-modules/Data/Formula/FormulaParser.js +1 -2
- package/es-modules/Data/Formula/FormulaProcessor.js +1 -2
- package/es-modules/Data/Modifiers/ChainModifier.d.ts +29 -34
- package/es-modules/Data/Modifiers/ChainModifier.js +7 -8
- package/es-modules/Data/Modifiers/DataModifier.d.ts +36 -41
- package/es-modules/Data/Modifiers/DataModifier.js +31 -53
- package/es-modules/Data/Modifiers/FilterModifier.d.ts +4 -4
- package/es-modules/Data/Modifiers/FilterModifier.js +3 -4
- package/es-modules/Data/Modifiers/FilterModifierOptions.d.ts +3 -2
- package/es-modules/Data/Modifiers/InvertModifier.d.ts +4 -4
- package/es-modules/Data/Modifiers/InvertModifier.js +3 -4
- package/es-modules/Data/Modifiers/MathModifier.d.ts +5 -4
- package/es-modules/Data/Modifiers/RangeModifier.d.ts +4 -4
- package/es-modules/Data/Modifiers/RangeModifier.js +3 -4
- package/es-modules/Data/Modifiers/SortModifier.d.ts +6 -11
- package/es-modules/Data/Modifiers/SortModifier.js +3 -4
- package/es-modules/Data/Modifiers/SortModifierOptions.d.ts +3 -3
- package/es-modules/Grid/Core/Accessibility/Accessibility.d.ts +1 -1
- package/es-modules/Grid/Core/Accessibility/Accessibility.js +5 -6
- package/es-modules/Grid/Core/Data/DataProvider.d.ts +97 -0
- package/es-modules/Grid/Core/Data/DataProvider.js +89 -0
- package/es-modules/Grid/Core/Data/DataProviderRegistry.d.ts +20 -0
- package/es-modules/Grid/Core/Data/DataProviderRegistry.js +52 -0
- package/es-modules/Grid/Core/Data/DataProviderType.d.ts +19 -0
- package/es-modules/Grid/Core/Data/DataProviderType.js +15 -0
- package/es-modules/Grid/Core/Data/LocalDataProvider.d.ts +165 -0
- package/es-modules/Grid/Core/Data/LocalDataProvider.js +341 -0
- package/es-modules/Grid/Core/Defaults.js +4 -2
- package/es-modules/Grid/Core/Globals.d.ts +20 -16
- package/es-modules/Grid/Core/Globals.js +10 -8
- package/es-modules/Grid/Core/Grid.d.ts +31 -22
- package/es-modules/Grid/Core/Grid.js +217 -139
- package/es-modules/Grid/Core/GridUtils.d.ts +33 -0
- package/es-modules/Grid/Core/GridUtils.js +50 -3
- package/es-modules/Grid/Core/Options.d.ts +145 -4
- package/es-modules/Grid/Core/Pagination/Pagination.d.ts +3 -0
- package/es-modules/Grid/Core/Pagination/Pagination.js +68 -28
- package/es-modules/Grid/Core/Pagination/PaginationOptions.d.ts +4 -0
- package/es-modules/Grid/Core/Querying/FilteringController.js +1 -2
- package/es-modules/Grid/Core/Querying/PaginationController.d.ts +3 -3
- package/es-modules/Grid/Core/Querying/PaginationController.js +7 -6
- package/es-modules/Grid/Core/Querying/QueryingController.d.ts +1 -1
- package/es-modules/Grid/Core/Querying/QueryingController.js +2 -26
- package/es-modules/Grid/Core/Responsive/ResponsiveComposition.d.ts +53 -0
- package/es-modules/Grid/Core/Responsive/ResponsiveComposition.js +272 -0
- package/es-modules/Grid/Core/Responsive/ResponsiveOptions.d.ts +58 -0
- package/es-modules/Grid/Core/Responsive/ResponsiveOptions.js +15 -0
- package/es-modules/Grid/Core/Table/Actions/ColumnFiltering/ColumnFiltering.js +2 -3
- package/es-modules/Grid/Core/Table/Actions/ColumnFiltering/FilterCell.d.ts +1 -1
- package/es-modules/Grid/Core/Table/Actions/ColumnFiltering/FilterCell.js +3 -4
- package/es-modules/Grid/Core/Table/Actions/ColumnFiltering/FilterRow.d.ts +1 -1
- package/es-modules/Grid/Core/Table/Actions/ColumnFiltering/FilterRow.js +2 -2
- package/es-modules/Grid/Core/Table/Actions/ColumnSorting.d.ts +17 -1
- package/es-modules/Grid/Core/Table/Actions/ColumnSorting.js +58 -15
- package/es-modules/Grid/Core/Table/Actions/ColumnsResizer.js +1 -3
- package/es-modules/Grid/Core/Table/Actions/RowsVirtualizer.d.ts +57 -3
- package/es-modules/Grid/Core/Table/Actions/RowsVirtualizer.js +411 -118
- package/es-modules/Grid/Core/Table/Body/CellContextMenu.d.ts +11 -0
- package/es-modules/Grid/Core/Table/Body/CellContextMenu.js +84 -0
- package/es-modules/Grid/Core/Table/Body/TableCell.d.ts +27 -13
- package/es-modules/Grid/Core/Table/Body/TableCell.js +74 -25
- package/es-modules/Grid/Core/Table/Body/TableRow.d.ts +7 -15
- package/es-modules/Grid/Core/Table/Body/TableRow.js +24 -19
- package/es-modules/Grid/Core/Table/Cell.d.ts +16 -3
- package/es-modules/Grid/Core/Table/Cell.js +36 -3
- package/es-modules/Grid/Core/Table/CellContent/TextContent.js +3 -8
- package/es-modules/Grid/Core/Table/Column.d.ts +10 -4
- package/es-modules/Grid/Core/Table/Column.js +23 -34
- package/es-modules/Grid/Core/Table/ColumnResizing/IndependentResizingMode.js +9 -8
- package/es-modules/Grid/Core/Table/ColumnResizing/ResizingMode.js +4 -3
- package/es-modules/Grid/Core/Table/Header/ColumnToolbar/ColumnToolbar.d.ts +5 -0
- package/es-modules/Grid/Core/Table/Header/ColumnToolbar/ColumnToolbar.js +7 -2
- package/es-modules/Grid/Core/Table/Header/ColumnToolbar/FilterPopup.js +1 -2
- package/es-modules/Grid/Core/Table/Header/ColumnToolbar/MenuButtons/FilterMenuButton.js +1 -2
- package/es-modules/Grid/Core/Table/Header/ColumnToolbar/MenuButtons/SortMenuButton.js +2 -3
- package/es-modules/Grid/Core/Table/Header/ColumnToolbar/ToolbarButtons/FilterToolbarButton.js +1 -2
- package/es-modules/Grid/Core/Table/Header/ColumnToolbar/ToolbarButtons/MenuToolbarButton.js +1 -2
- package/es-modules/Grid/Core/Table/Header/ColumnToolbar/ToolbarButtons/SortToolbarButton.d.ts +0 -1
- package/es-modules/Grid/Core/Table/Header/ColumnToolbar/ToolbarButtons/SortToolbarButton.js +4 -14
- package/es-modules/Grid/Core/Table/Header/HeaderCell.d.ts +6 -1
- package/es-modules/Grid/Core/Table/Header/HeaderCell.js +33 -13
- package/es-modules/Grid/Core/Table/Header/HeaderRow.js +4 -5
- package/es-modules/Grid/Core/Table/Header/TableHeader.d.ts +1 -1
- package/es-modules/Grid/Core/Table/Header/TableHeader.js +3 -3
- package/es-modules/Grid/Core/Table/Row.d.ts +1 -1
- package/es-modules/Grid/Core/Table/Row.js +2 -2
- package/es-modules/Grid/Core/Table/Table.d.ts +38 -12
- package/es-modules/Grid/Core/Table/Table.js +184 -91
- package/es-modules/Grid/Core/UI/ContextMenuButton.d.ts +6 -7
- package/es-modules/Grid/Core/UI/ContextMenuButton.js +5 -3
- package/es-modules/Grid/Core/UI/Popup.js +7 -9
- package/es-modules/Grid/Core/UI/SvgIcons.d.ts +42 -7
- package/es-modules/Grid/Core/UI/SvgIcons.js +206 -33
- package/es-modules/Grid/Core/UI/Toolbar.d.ts +5 -0
- package/es-modules/Grid/Core/UI/ToolbarButton.d.ts +4 -12
- package/es-modules/Grid/Core/UI/ToolbarButton.js +8 -26
- package/es-modules/Grid/Pro/CellEditing/CellEditMode.d.ts +2 -2
- package/es-modules/Grid/Pro/CellEditing/CellEditing.js +10 -10
- package/es-modules/Grid/Pro/CellEditing/CellEditingComposition.js +1 -2
- package/es-modules/Grid/Pro/CellRendering/CellRenderersComposition.d.ts +1 -1
- package/es-modules/Grid/Pro/CellRendering/CellRenderersComposition.js +4 -2
- package/es-modules/Grid/Pro/CellRendering/ContentTypes/CheckboxContent.d.ts +2 -2
- package/es-modules/Grid/Pro/CellRendering/ContentTypes/NumberInputContent.js +1 -2
- package/es-modules/Grid/Pro/CellRendering/ContentTypes/SelectContent.d.ts +2 -2
- package/es-modules/Grid/Pro/CellRendering/ContentTypes/SparklineContent.js +1 -2
- package/es-modules/Grid/Pro/CellRendering/ContentTypes/TextInputContent.d.ts +2 -2
- package/es-modules/Grid/Pro/CellRendering/ContentTypes/TextInputContent.js +1 -2
- package/es-modules/Grid/Pro/CellRendering/Renderers/CheckboxRenderer.js +1 -2
- package/es-modules/Grid/Pro/CellRendering/Renderers/DateInputRenderer.js +1 -2
- package/es-modules/Grid/Pro/CellRendering/Renderers/DateTimeInputRenderer.js +1 -2
- package/es-modules/Grid/Pro/CellRendering/Renderers/NumberInputRenderer.js +1 -2
- package/es-modules/Grid/Pro/CellRendering/Renderers/SelectRenderer.js +1 -2
- package/es-modules/Grid/Pro/CellRendering/Renderers/SparklineRenderer.d.ts +2 -2
- package/es-modules/Grid/Pro/CellRendering/Renderers/SparklineRenderer.js +1 -2
- package/es-modules/Grid/Pro/CellRendering/Renderers/TextInputRenderer.js +1 -2
- package/es-modules/Grid/Pro/CellRendering/Renderers/TextRenderer.js +1 -2
- package/es-modules/Grid/Pro/CellRendering/Renderers/TimeInputRenderer.js +1 -2
- package/es-modules/Grid/Pro/ColumnTypes/Validator.js +34 -32
- package/es-modules/Grid/Pro/ColumnTypes/ValidatorComposition.d.ts +1 -1
- package/es-modules/Grid/Pro/ColumnTypes/ValidatorComposition.js +3 -4
- package/es-modules/Grid/Pro/Credits/CreditsProComposition.d.ts +1 -1
- package/es-modules/Grid/Pro/Credits/CreditsProComposition.js +1 -3
- package/es-modules/Grid/Pro/Data/DataSourceHelper.d.ts +74 -0
- package/es-modules/Grid/Pro/Data/DataSourceHelper.js +256 -0
- package/es-modules/Grid/Pro/Data/QuerySerializer.d.ts +46 -0
- package/es-modules/Grid/Pro/Data/QuerySerializer.js +169 -0
- package/es-modules/Grid/Pro/Data/RemoteDataProvider.d.ts +187 -0
- package/es-modules/Grid/Pro/Data/RemoteDataProvider.js +500 -0
- package/es-modules/Grid/Pro/Export/Exporting.js +1 -2
- package/es-modules/Grid/Pro/Export/ExportingComposition.js +1 -2
- package/es-modules/Grid/Pro/GridEvents.js +1 -2
- package/es-modules/Grid/Pro/Pagination/PaginationComposition.d.ts +0 -1
- package/es-modules/Grid/Pro/Pagination/PaginationComposition.js +1 -2
- package/es-modules/Shared/BaseForm.js +1 -2
- package/es-modules/Shared/DownloadURL.js +1 -2
- package/es-modules/Shared/TimeBase.js +3 -3
- package/es-modules/Shared/Types.d.ts +7 -0
- package/es-modules/Shared/Utilities.d.ts +576 -0
- package/es-modules/Shared/Utilities.js +1360 -0
- package/es-modules/masters/grid-pro.src.d.ts +15 -11
- package/es-modules/masters/grid-pro.src.js +12 -5
- package/grid-pro.d.ts +15 -11
- package/grid-pro.js +3 -3
- package/grid-pro.js.map +1 -1
- package/grid-pro.src.d.ts +15 -11
- package/grid-pro.src.js +13854 -11395
- package/package.json +1 -1
- package/es-modules/Grid/Core/Pagination/Icons.d.ts +0 -7
- package/es-modules/Grid/Core/Pagination/Icons.js +0 -7
|
@@ -15,6 +15,7 @@
|
|
|
15
15
|
'use strict';
|
|
16
16
|
import TableRow from '../Body/TableRow.js';
|
|
17
17
|
import Globals from '../../Globals.js';
|
|
18
|
+
import { defined } from '../../../../Shared/Utilities.js';
|
|
18
19
|
/* *
|
|
19
20
|
*
|
|
20
21
|
* Class
|
|
@@ -24,6 +25,40 @@ import Globals from '../../Globals.js';
|
|
|
24
25
|
* Represents a virtualized rows renderer for the data grid.
|
|
25
26
|
*/
|
|
26
27
|
class RowsVirtualizer {
|
|
28
|
+
/**
|
|
29
|
+
* The maximum height of a HTML element in most browsers.
|
|
30
|
+
* Firefox has a lower limit than other browsers.
|
|
31
|
+
*/
|
|
32
|
+
static getMaxElementHeight() {
|
|
33
|
+
if (RowsVirtualizer.maxElementHeight !== void 0) {
|
|
34
|
+
return RowsVirtualizer.maxElementHeight;
|
|
35
|
+
}
|
|
36
|
+
const isFirefox = Globals.userAgent.indexOf('Firefox') > -1;
|
|
37
|
+
const fallbackMax = ((isFirefox ? 6000000 : 31000000) /
|
|
38
|
+
(window.devicePixelRatio || 1));
|
|
39
|
+
if (!document.body) {
|
|
40
|
+
RowsVirtualizer.maxElementHeight = fallbackMax;
|
|
41
|
+
return RowsVirtualizer.maxElementHeight;
|
|
42
|
+
}
|
|
43
|
+
let res = 1000000;
|
|
44
|
+
const testUpTo = isFirefox ? 6000000 : 1000000000;
|
|
45
|
+
const div = document.createElement('div');
|
|
46
|
+
document.body.appendChild(div);
|
|
47
|
+
let done = false;
|
|
48
|
+
while (!done) {
|
|
49
|
+
const test = res * 2;
|
|
50
|
+
div.style.height = test + 'px';
|
|
51
|
+
if (test > testUpTo || div.clientHeight !== test) {
|
|
52
|
+
done = true;
|
|
53
|
+
continue;
|
|
54
|
+
}
|
|
55
|
+
res = test;
|
|
56
|
+
}
|
|
57
|
+
div.remove();
|
|
58
|
+
const safeMax = 16000000;
|
|
59
|
+
RowsVirtualizer.maxElementHeight = Math.min(res || fallbackMax, safeMax);
|
|
60
|
+
return RowsVirtualizer.maxElementHeight;
|
|
61
|
+
}
|
|
27
62
|
/* *
|
|
28
63
|
*
|
|
29
64
|
* Constructor
|
|
@@ -36,6 +71,15 @@ class RowsVirtualizer {
|
|
|
36
71
|
* The viewport of the data grid to render rows in.
|
|
37
72
|
*/
|
|
38
73
|
constructor(viewport) {
|
|
74
|
+
/* *
|
|
75
|
+
*
|
|
76
|
+
* Properties
|
|
77
|
+
*
|
|
78
|
+
* */
|
|
79
|
+
/**
|
|
80
|
+
* The default height of a row.
|
|
81
|
+
*/
|
|
82
|
+
this.defaultRowHeight = 49;
|
|
39
83
|
/**
|
|
40
84
|
* The index of the first visible row.
|
|
41
85
|
*/
|
|
@@ -45,6 +89,21 @@ class RowsVirtualizer {
|
|
|
45
89
|
* flickering loops when scrolling to the last row.
|
|
46
90
|
*/
|
|
47
91
|
this.preventScroll = false;
|
|
92
|
+
/**
|
|
93
|
+
* The total height of the grid, used when the Grid height
|
|
94
|
+
* exceeds the max element height.
|
|
95
|
+
*/
|
|
96
|
+
this.totalGridHeight = 0;
|
|
97
|
+
/**
|
|
98
|
+
* The overflow height of the grid, used when the Grid height
|
|
99
|
+
* exceeds the max element height.
|
|
100
|
+
*/
|
|
101
|
+
this.gridHeightOverflow = 0;
|
|
102
|
+
/**
|
|
103
|
+
* The scroll offset in pixels used to adjust the row positions when
|
|
104
|
+
* the Grid height exceeds the max element height.
|
|
105
|
+
*/
|
|
106
|
+
this.scrollOffset = 0;
|
|
48
107
|
/**
|
|
49
108
|
* Reuse pool for rows that are currently out of viewport.
|
|
50
109
|
*/
|
|
@@ -54,12 +113,23 @@ class RowsVirtualizer {
|
|
|
54
113
|
* frame.
|
|
55
114
|
*/
|
|
56
115
|
this.scrollQueued = false;
|
|
116
|
+
/**
|
|
117
|
+
* Flag indicating if rows are currently being rendered to prevent
|
|
118
|
+
* concurrent render operations.
|
|
119
|
+
*/
|
|
120
|
+
this.isRendering = false;
|
|
121
|
+
/**
|
|
122
|
+
* Pending row cursor to render after current render completes.
|
|
123
|
+
* Used to ensure the final scroll position is rendered.
|
|
124
|
+
*/
|
|
125
|
+
this.pendingRowCursor = null;
|
|
57
126
|
this.rowSettings =
|
|
58
127
|
viewport.grid.options?.rendering?.rows;
|
|
59
128
|
this.viewport = viewport;
|
|
129
|
+
this.rowCount = 0;
|
|
60
130
|
this.strictRowHeights = this.rowSettings.strictHeights;
|
|
61
131
|
this.buffer = Math.max(this.rowSettings.bufferSize, 0);
|
|
62
|
-
this.
|
|
132
|
+
this.maxElementHeight = RowsVirtualizer.getMaxElementHeight();
|
|
63
133
|
if (this.strictRowHeights) {
|
|
64
134
|
viewport.tbodyElement.classList.add(Globals.getClassName('rowsContentNowrap'));
|
|
65
135
|
}
|
|
@@ -72,20 +142,26 @@ class RowsVirtualizer {
|
|
|
72
142
|
/**
|
|
73
143
|
* Renders the rows in the viewport for the first time.
|
|
74
144
|
*/
|
|
75
|
-
initialRender() {
|
|
145
|
+
async initialRender() {
|
|
146
|
+
this.defaultRowHeight = await this.getDefaultRowHeight();
|
|
76
147
|
// Initial reflow to set the viewport height
|
|
77
148
|
if (this.viewport.virtualRows) {
|
|
78
149
|
this.viewport.reflow();
|
|
79
150
|
}
|
|
151
|
+
await this.updateGridMetrics();
|
|
80
152
|
// Load & render rows
|
|
81
|
-
this.renderRows(this.rowCursor);
|
|
153
|
+
await this.renderRows(this.rowCursor);
|
|
82
154
|
this.adjustRowHeights();
|
|
155
|
+
if (this.viewport.virtualRows) {
|
|
156
|
+
this.adjustRowOffsets();
|
|
157
|
+
}
|
|
83
158
|
}
|
|
84
159
|
/**
|
|
85
160
|
* Renders the rows in the viewport. It is called when the rows need to be
|
|
86
161
|
* re-rendered, e.g., after a sort or filter operation.
|
|
87
162
|
*/
|
|
88
|
-
rerender() {
|
|
163
|
+
async rerender() {
|
|
164
|
+
await this.updateGridMetrics();
|
|
89
165
|
const tbody = this.viewport.tbodyElement;
|
|
90
166
|
let rows = this.viewport.rows;
|
|
91
167
|
const oldScrollLeft = tbody.scrollLeft;
|
|
@@ -103,12 +179,11 @@ class RowsVirtualizer {
|
|
|
103
179
|
}
|
|
104
180
|
rows.length = 0;
|
|
105
181
|
}
|
|
106
|
-
this.renderRows(this.rowCursor);
|
|
182
|
+
await this.renderRows(this.rowCursor);
|
|
107
183
|
if (this.viewport.virtualRows) {
|
|
108
|
-
if (oldScrollTop
|
|
184
|
+
if (defined(oldScrollTop)) {
|
|
109
185
|
tbody.scrollTop = oldScrollTop;
|
|
110
186
|
}
|
|
111
|
-
this.scroll();
|
|
112
187
|
}
|
|
113
188
|
rows = this.viewport.rows;
|
|
114
189
|
// Reflow the rendered row cells widths (check redundancy)
|
|
@@ -117,6 +192,47 @@ class RowsVirtualizer {
|
|
|
117
192
|
}
|
|
118
193
|
tbody.scrollLeft = oldScrollLeft;
|
|
119
194
|
}
|
|
195
|
+
/**
|
|
196
|
+
* Refreshes the rendered rows without a full teardown.
|
|
197
|
+
* It updates the row range and reuses existing rows when possible.
|
|
198
|
+
*/
|
|
199
|
+
async refreshRows() {
|
|
200
|
+
await this.updateGridMetrics();
|
|
201
|
+
const tbody = this.viewport.tbodyElement;
|
|
202
|
+
const oldScrollLeft = tbody.scrollLeft;
|
|
203
|
+
const oldScrollTop = this.viewport.virtualRows ?
|
|
204
|
+
tbody.scrollTop :
|
|
205
|
+
void 0;
|
|
206
|
+
const maxRowCursor = Math.max(0, this.rowCount - 1);
|
|
207
|
+
if (this.rowCursor > maxRowCursor) {
|
|
208
|
+
this.rowCursor = maxRowCursor;
|
|
209
|
+
}
|
|
210
|
+
// Render missing rows, drop out-of-range ones, and ensure last row.
|
|
211
|
+
await this.renderRows(this.rowCursor);
|
|
212
|
+
const rows = this.viewport.rows;
|
|
213
|
+
// For non-virtualized rows, re-order rows to match data order.
|
|
214
|
+
if (!this.viewport.virtualRows) {
|
|
215
|
+
let node = tbody.firstElementChild;
|
|
216
|
+
for (let i = 0, iEnd = rows.length; i < iEnd; ++i) {
|
|
217
|
+
if (node === rows[i].htmlElement) {
|
|
218
|
+
node = node.nextElementSibling;
|
|
219
|
+
continue;
|
|
220
|
+
}
|
|
221
|
+
// Mismatch found, so append the rest in the correct order.
|
|
222
|
+
for (let j = i; j < iEnd; ++j) {
|
|
223
|
+
tbody.appendChild(rows[j].htmlElement);
|
|
224
|
+
}
|
|
225
|
+
break;
|
|
226
|
+
}
|
|
227
|
+
}
|
|
228
|
+
for (let i = 0, iEnd = rows.length; i < iEnd; ++i) {
|
|
229
|
+
await rows[i].update();
|
|
230
|
+
}
|
|
231
|
+
if (this.viewport.virtualRows && defined(oldScrollTop)) {
|
|
232
|
+
tbody.scrollTop = oldScrollTop;
|
|
233
|
+
}
|
|
234
|
+
tbody.scrollLeft = oldScrollLeft;
|
|
235
|
+
}
|
|
120
236
|
/**
|
|
121
237
|
* Method called on the viewport scroll event, only when the virtualization
|
|
122
238
|
* is enabled.
|
|
@@ -128,16 +244,22 @@ class RowsVirtualizer {
|
|
|
128
244
|
this.scrollQueued = true;
|
|
129
245
|
requestAnimationFrame(() => {
|
|
130
246
|
this.scrollQueued = false;
|
|
131
|
-
this.applyScroll();
|
|
247
|
+
void this.applyScroll();
|
|
132
248
|
});
|
|
133
249
|
}
|
|
134
250
|
/**
|
|
135
251
|
* Applies the scroll logic for virtualized rows.
|
|
136
252
|
*/
|
|
137
|
-
applyScroll() {
|
|
253
|
+
async applyScroll() {
|
|
138
254
|
const target = this.viewport.tbodyElement;
|
|
139
255
|
const { defaultRowHeight: rowHeight } = this;
|
|
140
256
|
const lastScrollTop = target.scrollTop;
|
|
257
|
+
const scrollDenominator = this.maxElementHeight -
|
|
258
|
+
target.clientHeight;
|
|
259
|
+
const scrollPercentage = scrollDenominator > 0 ?
|
|
260
|
+
lastScrollTop / scrollDenominator :
|
|
261
|
+
0;
|
|
262
|
+
this.scrollOffset = Math.floor(scrollPercentage * this.gridHeightOverflow);
|
|
141
263
|
if (this.preventScroll) {
|
|
142
264
|
if (lastScrollTop <= target.scrollTop) {
|
|
143
265
|
this.preventScroll = false;
|
|
@@ -146,12 +268,16 @@ class RowsVirtualizer {
|
|
|
146
268
|
return;
|
|
147
269
|
}
|
|
148
270
|
// Do vertical virtual scrolling
|
|
149
|
-
|
|
271
|
+
let rowCursor = Math.floor((target.scrollTop / rowHeight) +
|
|
272
|
+
(this.scrollOffset / rowHeight));
|
|
273
|
+
const maxRowCursor = Math.max(0, this.rowCount - 1);
|
|
274
|
+
rowCursor = Math.min(rowCursor, maxRowCursor);
|
|
150
275
|
if (this.rowCursor !== rowCursor) {
|
|
151
|
-
this.renderRows(rowCursor);
|
|
276
|
+
await this.renderRows(rowCursor);
|
|
152
277
|
}
|
|
153
278
|
this.rowCursor = rowCursor;
|
|
154
279
|
this.adjustRowHeights();
|
|
280
|
+
this.adjustRowOffsets();
|
|
155
281
|
if (!this.strictRowHeights &&
|
|
156
282
|
lastScrollTop > target.scrollTop &&
|
|
157
283
|
!this.preventScroll) {
|
|
@@ -165,7 +291,16 @@ class RowsVirtualizer {
|
|
|
165
291
|
adjustBottomRowHeights() {
|
|
166
292
|
const rows = this.viewport.rows;
|
|
167
293
|
const rowsLn = rows.length;
|
|
294
|
+
if (rowsLn < 1) {
|
|
295
|
+
return;
|
|
296
|
+
}
|
|
168
297
|
const lastRow = rows[rowsLn - 1];
|
|
298
|
+
// Skip if row is not fully rendered or has no cells
|
|
299
|
+
if (!lastRow.rendered ||
|
|
300
|
+
!lastRow.cells.length ||
|
|
301
|
+
!lastRow.cells[0]?.htmlElement) {
|
|
302
|
+
return;
|
|
303
|
+
}
|
|
169
304
|
let rowTop = lastRow.translateY;
|
|
170
305
|
const rowBottom = rowTop + lastRow.htmlElement.offsetHeight;
|
|
171
306
|
let newHeight = lastRow.cells[0].htmlElement.offsetHeight;
|
|
@@ -173,16 +308,28 @@ class RowsVirtualizer {
|
|
|
173
308
|
lastRow.htmlElement.style.height = newHeight + 'px';
|
|
174
309
|
lastRow.setTranslateY(rowTop);
|
|
175
310
|
for (let j = 0, jEnd = lastRow.cells.length; j < jEnd; ++j) {
|
|
176
|
-
lastRow.cells[j]
|
|
311
|
+
const cell = lastRow.cells[j];
|
|
312
|
+
if (cell?.htmlElement) {
|
|
313
|
+
cell.htmlElement.style.transform = '';
|
|
314
|
+
}
|
|
177
315
|
}
|
|
178
316
|
for (let i = rowsLn - 2; i >= 0; i--) {
|
|
179
317
|
const row = rows[i];
|
|
318
|
+
// Skip if row is not fully rendered or has no cells
|
|
319
|
+
if (!row.rendered ||
|
|
320
|
+
!row.cells.length ||
|
|
321
|
+
!row.cells[0]?.htmlElement) {
|
|
322
|
+
continue;
|
|
323
|
+
}
|
|
180
324
|
newHeight = row.cells[0].htmlElement.offsetHeight;
|
|
181
325
|
rowTop -= newHeight;
|
|
182
326
|
row.htmlElement.style.height = newHeight + 'px';
|
|
183
327
|
row.setTranslateY(rowTop);
|
|
184
328
|
for (let j = 0, jEnd = row.cells.length; j < jEnd; ++j) {
|
|
185
|
-
row.cells[j]
|
|
329
|
+
const cell = row.cells[j];
|
|
330
|
+
if (cell?.htmlElement) {
|
|
331
|
+
cell.htmlElement.style.transform = '';
|
|
332
|
+
}
|
|
186
333
|
}
|
|
187
334
|
}
|
|
188
335
|
}
|
|
@@ -193,121 +340,197 @@ class RowsVirtualizer {
|
|
|
193
340
|
* @param rowCursor
|
|
194
341
|
* The index of the first visible row.
|
|
195
342
|
*/
|
|
196
|
-
renderRows(rowCursor) {
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
if (rowCount < 1) {
|
|
343
|
+
async renderRows(rowCursor) {
|
|
344
|
+
// Prevent concurrent render operations - queue the latest cursor
|
|
345
|
+
if (this.isRendering) {
|
|
346
|
+
this.pendingRowCursor = rowCursor;
|
|
201
347
|
return;
|
|
202
348
|
}
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
'virtualization is disabled. Consider enabling ' +
|
|
211
|
-
'virtualization in the rows settings.');
|
|
212
|
-
}
|
|
213
|
-
if (!rows.length) {
|
|
214
|
-
const last = new TableRow(vp, rowCount - 1);
|
|
215
|
-
vp.tbodyElement.appendChild(last.htmlElement);
|
|
216
|
-
last.render();
|
|
217
|
-
rows.push(last);
|
|
218
|
-
if (isVirtualization) {
|
|
219
|
-
last.setTranslateY(last.getDefaultTopOffset());
|
|
349
|
+
this.isRendering = true;
|
|
350
|
+
try {
|
|
351
|
+
const { viewport: vp, buffer } = this;
|
|
352
|
+
await this.updateGridMetrics();
|
|
353
|
+
const rowCount = this.rowCount;
|
|
354
|
+
if (!defined(rowCount)) {
|
|
355
|
+
return;
|
|
220
356
|
}
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
const currentTo = rows[rows.length - 1]?.index;
|
|
228
|
-
const hasOverlap = (rows.length > 0 &&
|
|
229
|
-
currentFrom !== void 0 &&
|
|
230
|
-
currentTo !== void 0 &&
|
|
231
|
-
!(to < currentFrom || from > currentTo));
|
|
232
|
-
if (!hasOverlap) {
|
|
233
|
-
// Remove rows that are out of the range except the last row.
|
|
234
|
-
for (let i = 0, iEnd = rows.length; i < iEnd; ++i) {
|
|
235
|
-
const row = rows[i];
|
|
236
|
-
const rowIndex = row.index;
|
|
237
|
-
if (rowIndex < from || rowIndex > to) {
|
|
238
|
-
this.poolRow(row);
|
|
239
|
-
}
|
|
240
|
-
else {
|
|
241
|
-
tempRows.push(row);
|
|
357
|
+
if (rowCount === 0) {
|
|
358
|
+
if (vp.rows.length) {
|
|
359
|
+
for (let i = 0, iEnd = vp.rows.length; i < iEnd; ++i) {
|
|
360
|
+
vp.rows[i].destroy();
|
|
361
|
+
}
|
|
362
|
+
vp.rows.length = 0;
|
|
242
363
|
}
|
|
364
|
+
vp.tbodyElement.innerHTML = '';
|
|
365
|
+
this.rowCursor = 0;
|
|
366
|
+
return;
|
|
243
367
|
}
|
|
244
|
-
rows
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
const row = rows[i - (rows[0]?.index || 0)];
|
|
248
|
-
// Recreate row when it is destroyed and it is in the range.
|
|
249
|
-
if (!row) {
|
|
250
|
-
rows.push(this.getOrCreateRow(i));
|
|
251
|
-
}
|
|
368
|
+
// Stop rendering if there are no rows to render.
|
|
369
|
+
if (rowCount < 1) {
|
|
370
|
+
return;
|
|
252
371
|
}
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
372
|
+
const isVirtualization = this.viewport.virtualRows;
|
|
373
|
+
const rowsPerPage = isVirtualization ? Math.ceil((vp.grid.tableElement?.clientHeight || 0) /
|
|
374
|
+
this.defaultRowHeight) : Infinity; // Need to be refactored when add pagination
|
|
375
|
+
let rows = vp.rows;
|
|
376
|
+
if (!isVirtualization && rows.length > 50) {
|
|
377
|
+
// eslint-disable-next-line no-console
|
|
378
|
+
console.warn('Grid: a large dataset can cause performance issues when ' +
|
|
379
|
+
'virtualization is disabled. Consider enabling ' +
|
|
380
|
+
'virtualization in the rows settings.');
|
|
259
381
|
}
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
382
|
+
if (!rows.length && rowCount > 0) {
|
|
383
|
+
const last = new TableRow(vp, rowCount - 1);
|
|
384
|
+
await last.init();
|
|
385
|
+
vp.tbodyElement.appendChild(last.htmlElement);
|
|
386
|
+
await last.render();
|
|
387
|
+
rows.push(last);
|
|
388
|
+
if (isVirtualization) {
|
|
389
|
+
const topOffset = Math.min(last.getDefaultTopOffset(), this.maxElementHeight -
|
|
390
|
+
last.htmlElement.offsetHeight);
|
|
391
|
+
last.setTranslateY(topOffset);
|
|
392
|
+
}
|
|
263
393
|
}
|
|
264
|
-
|
|
394
|
+
// The last row is always kept rendered for bottom alignment
|
|
395
|
+
let alwaysLastRow = rows.length > 0 ? rows.pop() : void 0;
|
|
396
|
+
if (alwaysLastRow && alwaysLastRow.index !== rowCount - 1) {
|
|
397
|
+
this.poolRow(alwaysLastRow);
|
|
398
|
+
alwaysLastRow = void 0;
|
|
399
|
+
}
|
|
400
|
+
const from = Math.max(0, Math.min(rowCursor - buffer, rowCount - rowsPerPage));
|
|
401
|
+
// `to` should not include the alwaysLastRow index (rowCount - 1)
|
|
402
|
+
const to = Math.min(rowCursor + rowsPerPage + buffer, rowCount - 2 // -2 because alwaysLastRow is at rowCount - 1
|
|
403
|
+
);
|
|
404
|
+
const tempRows = [];
|
|
405
|
+
const currentFrom = rows[0]?.index;
|
|
406
|
+
const currentTo = rows[rows.length - 1]?.index;
|
|
407
|
+
const hasOverlap = (rows.length > 0 &&
|
|
408
|
+
defined(currentFrom) &&
|
|
409
|
+
defined(currentTo) &&
|
|
410
|
+
!(to < currentFrom || from > currentTo));
|
|
411
|
+
if (!hasOverlap) {
|
|
412
|
+
// Remove rows that are out of the range except the last row.
|
|
413
|
+
for (let i = 0, iEnd = rows.length; i < iEnd; ++i) {
|
|
414
|
+
const row = rows[i];
|
|
415
|
+
const rowIndex = row.index;
|
|
416
|
+
if (rowIndex < from || rowIndex > to) {
|
|
417
|
+
this.poolRow(row);
|
|
418
|
+
}
|
|
419
|
+
else {
|
|
420
|
+
tempRows.push(row);
|
|
421
|
+
}
|
|
422
|
+
}
|
|
423
|
+
rows = tempRows;
|
|
424
|
+
vp.rows = rows;
|
|
265
425
|
for (let i = from; i <= to; ++i) {
|
|
266
|
-
rows.
|
|
426
|
+
const firstRowIndex = rows.length > 0 ? rows[0].index : from;
|
|
427
|
+
const row = rows[i - firstRowIndex];
|
|
428
|
+
// Recreate row when it is destroyed and it is in the range.
|
|
429
|
+
if (!row) {
|
|
430
|
+
const newRow = await this.getOrCreateRow(i);
|
|
431
|
+
rows.push(newRow);
|
|
432
|
+
}
|
|
267
433
|
}
|
|
434
|
+
rows.sort((a, b) => a.index - b.index);
|
|
268
435
|
}
|
|
269
436
|
else {
|
|
270
|
-
//
|
|
271
|
-
|
|
272
|
-
|
|
437
|
+
// Remove rows outside the range from the start.
|
|
438
|
+
while (rows.length && rows[0].index < from) {
|
|
439
|
+
this.poolRow(rows.shift());
|
|
273
440
|
}
|
|
274
|
-
//
|
|
275
|
-
|
|
276
|
-
|
|
441
|
+
// Remove rows outside the range from the end.
|
|
442
|
+
while (rows.length && rows[rows.length - 1].index > to) {
|
|
443
|
+
this.poolRow(rows.pop());
|
|
277
444
|
}
|
|
445
|
+
if (!rows.length) {
|
|
446
|
+
for (let i = from; i <= to; ++i) {
|
|
447
|
+
rows.push(await this.getOrCreateRow(i));
|
|
448
|
+
}
|
|
449
|
+
}
|
|
450
|
+
else {
|
|
451
|
+
// Add rows before the current range.
|
|
452
|
+
for (let i = rows[0].index - 1; i >= from; --i) {
|
|
453
|
+
rows.unshift(await this.getOrCreateRow(i));
|
|
454
|
+
}
|
|
455
|
+
// Add rows after the current range.
|
|
456
|
+
const lastRowIndex = rows[rows.length - 1].index + 1;
|
|
457
|
+
for (let i = lastRowIndex; i <= to; ++i) {
|
|
458
|
+
rows.push(await this.getOrCreateRow(i));
|
|
459
|
+
}
|
|
460
|
+
}
|
|
461
|
+
vp.rows = rows;
|
|
278
462
|
}
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
463
|
+
for (let i = 0, iEnd = rows.length; i < iEnd; ++i) {
|
|
464
|
+
const row = rows[i];
|
|
465
|
+
if (!row.rendered) {
|
|
466
|
+
// Ensure row is initialized before rendering
|
|
467
|
+
if (!row.htmlElement.hasAttribute('data-row-index')) {
|
|
468
|
+
await row.init();
|
|
469
|
+
}
|
|
470
|
+
vp.tbodyElement.insertBefore(row.htmlElement, vp.tbodyElement.lastChild);
|
|
471
|
+
await row.render();
|
|
472
|
+
if (isVirtualization) {
|
|
473
|
+
const topOffset = Math.min(row.getDefaultTopOffset(), this.maxElementHeight -
|
|
474
|
+
row.htmlElement.offsetHeight);
|
|
475
|
+
row.setTranslateY(topOffset);
|
|
476
|
+
}
|
|
477
|
+
continue;
|
|
478
|
+
}
|
|
479
|
+
if (!row.htmlElement.isConnected) {
|
|
480
|
+
vp.tbodyElement.insertBefore(row.htmlElement, vp.tbodyElement.lastChild);
|
|
481
|
+
}
|
|
287
482
|
}
|
|
288
|
-
if (!
|
|
289
|
-
|
|
483
|
+
if (!alwaysLastRow && rowCount > 0) {
|
|
484
|
+
alwaysLastRow = await this.getOrCreateRow(rowCount - 1);
|
|
290
485
|
}
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
486
|
+
if (alwaysLastRow) {
|
|
487
|
+
if (!alwaysLastRow.rendered) {
|
|
488
|
+
if (!alwaysLastRow.htmlElement
|
|
489
|
+
.hasAttribute('data-row-index')) {
|
|
490
|
+
await alwaysLastRow.init();
|
|
491
|
+
}
|
|
492
|
+
vp.tbodyElement.appendChild(alwaysLastRow.htmlElement);
|
|
493
|
+
await alwaysLastRow.render();
|
|
494
|
+
if (isVirtualization) {
|
|
495
|
+
const topOffset = Math.min(alwaysLastRow.getDefaultTopOffset(), this.maxElementHeight -
|
|
496
|
+
alwaysLastRow.htmlElement.offsetHeight);
|
|
497
|
+
alwaysLastRow.setTranslateY(topOffset);
|
|
498
|
+
}
|
|
499
|
+
}
|
|
500
|
+
else if (!alwaysLastRow.htmlElement.isConnected) {
|
|
501
|
+
vp.tbodyElement.appendChild(alwaysLastRow.htmlElement);
|
|
502
|
+
}
|
|
503
|
+
rows.push(alwaysLastRow);
|
|
504
|
+
}
|
|
505
|
+
// Focus the cell if the focus cursor is set
|
|
506
|
+
if (vp.focusCursor) {
|
|
507
|
+
const [rowIndex, columnIndex] = vp.focusCursor;
|
|
508
|
+
const row = rows.find((row) => row.index === rowIndex);
|
|
509
|
+
if (row) {
|
|
510
|
+
row.cells[columnIndex]?.htmlElement.focus({
|
|
511
|
+
preventScroll: true
|
|
512
|
+
});
|
|
513
|
+
}
|
|
514
|
+
}
|
|
515
|
+
// Set the focus anchor cell
|
|
516
|
+
if ((!vp.focusCursor || !vp.focusAnchorCell?.row.rendered) &&
|
|
517
|
+
rows.length > 0) {
|
|
518
|
+
const rowIndex = rowCursor - rows[0].index;
|
|
519
|
+
const targetRow = rows[rowIndex];
|
|
520
|
+
if (targetRow &&
|
|
521
|
+
targetRow.cells.length > 0 &&
|
|
522
|
+
targetRow.cells[0]) {
|
|
523
|
+
vp.setFocusAnchorCell(targetRow.cells[0]);
|
|
524
|
+
}
|
|
303
525
|
}
|
|
304
526
|
}
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
527
|
+
finally {
|
|
528
|
+
this.isRendering = false;
|
|
529
|
+
// If there's a pending render request, process it
|
|
530
|
+
if (this.pendingRowCursor !== null) {
|
|
531
|
+
const pendingCursor = this.pendingRowCursor;
|
|
532
|
+
this.pendingRowCursor = null;
|
|
533
|
+
await this.renderRows(pendingCursor);
|
|
311
534
|
}
|
|
312
535
|
}
|
|
313
536
|
}
|
|
@@ -324,18 +547,27 @@ class RowsVirtualizer {
|
|
|
324
547
|
const { rowCursor: cursor, defaultRowHeight: defaultH } = this;
|
|
325
548
|
const { rows, tbodyElement } = this.viewport;
|
|
326
549
|
const rowsLn = rows.length;
|
|
327
|
-
if (rowsLn < 1) {
|
|
550
|
+
if (rowsLn < 1 || !defaultH) {
|
|
328
551
|
return;
|
|
329
552
|
}
|
|
330
553
|
let translateBuffer = rows[0].getDefaultTopOffset();
|
|
331
554
|
for (let i = 0; i < rowsLn; ++i) {
|
|
332
555
|
const row = rows[i];
|
|
556
|
+
// Skip if row is not fully rendered or has no cells
|
|
557
|
+
if (!row.rendered ||
|
|
558
|
+
!row.cells.length ||
|
|
559
|
+
!row.cells[0]?.htmlElement) {
|
|
560
|
+
row.htmlElement.style.height = defaultH + 'px';
|
|
561
|
+
continue;
|
|
562
|
+
}
|
|
333
563
|
// Reset row height and cell transforms
|
|
334
564
|
row.htmlElement.style.height = '';
|
|
335
565
|
if (row.cells[0].htmlElement.style.transform) {
|
|
336
566
|
for (let j = 0, jEnd = row.cells.length; j < jEnd; ++j) {
|
|
337
567
|
const cell = row.cells[j];
|
|
338
|
-
cell
|
|
568
|
+
if (cell?.htmlElement) {
|
|
569
|
+
cell.htmlElement.style.transform = '';
|
|
570
|
+
}
|
|
339
571
|
}
|
|
340
572
|
}
|
|
341
573
|
// Rows above the first visible row
|
|
@@ -351,11 +583,13 @@ class RowsVirtualizer {
|
|
|
351
583
|
}
|
|
352
584
|
// First visible row
|
|
353
585
|
if (row.htmlElement.offsetHeight > defaultH) {
|
|
354
|
-
const newHeight = Math.floor(cellHeight - (cellHeight - defaultH) * (tbodyElement.scrollTop / defaultH - cursor));
|
|
586
|
+
const newHeight = Math.floor(cellHeight - (cellHeight - defaultH) * (tbodyElement.scrollTop / defaultH - Math.floor(cursor - this.scrollOffset / defaultH)));
|
|
355
587
|
row.htmlElement.style.height = newHeight + 'px';
|
|
356
588
|
for (let j = 0, jEnd = row.cells.length; j < jEnd; ++j) {
|
|
357
589
|
const cell = row.cells[j];
|
|
358
|
-
cell
|
|
590
|
+
if (cell?.htmlElement) {
|
|
591
|
+
cell.htmlElement.style.transform = `translateY(${newHeight - cellHeight}px)`;
|
|
592
|
+
}
|
|
359
593
|
}
|
|
360
594
|
}
|
|
361
595
|
}
|
|
@@ -383,6 +617,9 @@ class RowsVirtualizer {
|
|
|
383
617
|
rows[i].reflow();
|
|
384
618
|
}
|
|
385
619
|
this.adjustRowHeights();
|
|
620
|
+
if (this.viewport.virtualRows) {
|
|
621
|
+
this.adjustRowOffsets();
|
|
622
|
+
}
|
|
386
623
|
}
|
|
387
624
|
/**
|
|
388
625
|
* Gets a row from the pool or creates a new one for the given index.
|
|
@@ -393,12 +630,12 @@ class RowsVirtualizer {
|
|
|
393
630
|
* @returns
|
|
394
631
|
* A TableRow instance ready for use.
|
|
395
632
|
*/
|
|
396
|
-
getOrCreateRow(index) {
|
|
633
|
+
async getOrCreateRow(index) {
|
|
397
634
|
const vp = this.viewport;
|
|
398
635
|
const isVirtualization = vp.virtualRows;
|
|
399
636
|
const pooledRow = this.rowPool.pop();
|
|
400
637
|
if (pooledRow) {
|
|
401
|
-
pooledRow.reuse(index
|
|
638
|
+
await pooledRow.reuse(index);
|
|
402
639
|
if (isVirtualization) {
|
|
403
640
|
pooledRow.setTranslateY(pooledRow.getDefaultTopOffset());
|
|
404
641
|
}
|
|
@@ -406,6 +643,7 @@ class RowsVirtualizer {
|
|
|
406
643
|
}
|
|
407
644
|
const newRow = new TableRow(vp, index);
|
|
408
645
|
newRow.rendered = false;
|
|
646
|
+
await newRow.init();
|
|
409
647
|
if (isVirtualization) {
|
|
410
648
|
newRow.setTranslateY(newRow.getDefaultTopOffset());
|
|
411
649
|
}
|
|
@@ -433,17 +671,72 @@ class RowsVirtualizer {
|
|
|
433
671
|
* @returns
|
|
434
672
|
* The default height of a row.
|
|
435
673
|
*/
|
|
436
|
-
getDefaultRowHeight() {
|
|
674
|
+
async getDefaultRowHeight() {
|
|
437
675
|
const vp = this.viewport;
|
|
438
676
|
const mockRow = new TableRow(vp, 0);
|
|
677
|
+
await mockRow.init();
|
|
439
678
|
mockRow.htmlElement.style.position = 'absolute';
|
|
440
679
|
mockRow.htmlElement.classList.add(Globals.getClassName('mockedRow'));
|
|
441
|
-
|
|
442
|
-
mockRow.render();
|
|
680
|
+
vp.tbodyElement.appendChild(mockRow.htmlElement);
|
|
681
|
+
await mockRow.render();
|
|
443
682
|
const defaultRowHeight = mockRow.htmlElement.offsetHeight;
|
|
444
683
|
mockRow.destroy();
|
|
445
684
|
return defaultRowHeight;
|
|
446
685
|
}
|
|
686
|
+
/**
|
|
687
|
+
* Updates cached row count and derived grid height metrics used for
|
|
688
|
+
* overflow-aware scrolling.
|
|
689
|
+
*/
|
|
690
|
+
async updateGridMetrics() {
|
|
691
|
+
const rowCount = await this.viewport.grid.dataProvider?.getRowCount();
|
|
692
|
+
if (!defined(rowCount)) {
|
|
693
|
+
return;
|
|
694
|
+
}
|
|
695
|
+
this.rowCount = rowCount;
|
|
696
|
+
this.totalGridHeight = this.rowCount * this.defaultRowHeight;
|
|
697
|
+
this.gridHeightOverflow = Math.max(this.totalGridHeight - this.maxElementHeight, 0);
|
|
698
|
+
}
|
|
699
|
+
/**
|
|
700
|
+
* Updates row translate offsets based on scroll scaling. When the grid
|
|
701
|
+
* exceeds the max element height, it keeps the bottom rows aligned to the
|
|
702
|
+
* maximum scrollable height.
|
|
703
|
+
*/
|
|
704
|
+
adjustRowOffsets() {
|
|
705
|
+
const { rows } = this.viewport;
|
|
706
|
+
const rowsLn = rows.length;
|
|
707
|
+
if (rowsLn < 2) {
|
|
708
|
+
return;
|
|
709
|
+
}
|
|
710
|
+
const lastRow = rows[rowsLn - 1];
|
|
711
|
+
const preLastRow = rows[rowsLn - 2];
|
|
712
|
+
const isSecondToLastRowVisible = preLastRow &&
|
|
713
|
+
preLastRow.index === lastRow.index - 1;
|
|
714
|
+
let translateBuffer = rows[0].getDefaultTopOffset();
|
|
715
|
+
translateBuffer = Math.floor(translateBuffer - this.scrollOffset);
|
|
716
|
+
if (isSecondToLastRowVisible && this.gridHeightOverflow > 0) {
|
|
717
|
+
lastRow.setTranslateY(this.maxElementHeight -
|
|
718
|
+
lastRow.htmlElement.offsetHeight);
|
|
719
|
+
let bottomOffset = this.maxElementHeight -
|
|
720
|
+
lastRow.htmlElement.offsetHeight;
|
|
721
|
+
for (let i = rowsLn - 2; i >= 0; i--) {
|
|
722
|
+
bottomOffset -= rows[i].htmlElement.offsetHeight;
|
|
723
|
+
rows[i].setTranslateY(bottomOffset);
|
|
724
|
+
}
|
|
725
|
+
return;
|
|
726
|
+
}
|
|
727
|
+
rows[0].setTranslateY(translateBuffer);
|
|
728
|
+
for (let i = 1, iEnd = rowsLn - 1; i < iEnd; ++i) {
|
|
729
|
+
translateBuffer += rows[i - 1].htmlElement.offsetHeight;
|
|
730
|
+
rows[i].setTranslateY(translateBuffer);
|
|
731
|
+
}
|
|
732
|
+
if (this.gridHeightOverflow > 0) {
|
|
733
|
+
lastRow.setTranslateY(this.maxElementHeight);
|
|
734
|
+
return;
|
|
735
|
+
}
|
|
736
|
+
if (preLastRow && preLastRow.index === lastRow.index - 1) {
|
|
737
|
+
lastRow.setTranslateY(preLastRow.htmlElement.offsetHeight + translateBuffer);
|
|
738
|
+
}
|
|
739
|
+
}
|
|
447
740
|
}
|
|
448
741
|
/**
|
|
449
742
|
* Maximum number of rows to keep in the reuse pool.
|