@progress/kendo-angular-pivotgrid 16.6.0-develop.1 → 16.6.0-develop.11

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.
@@ -2,53 +2,205 @@
2
2
  * Copyright © 2024 Progress Software Corporation. All rights reserved.
3
3
  * Licensed under commercial license. See LICENSE.md in the project root for more information
4
4
  *-------------------------------------------------------------------------------------------*/
5
- import { Component, Input } from '@angular/core';
5
+ import { Component, ElementRef, Input, NgZone } from '@angular/core';
6
6
  import { Subscription } from 'rxjs';
7
7
  import { PivotGridDataService } from '../data-binding/pivotgrid-data.service';
8
8
  import { CellTemplateDirective } from './templates/pivotgrid-cell-template.directive';
9
9
  import { ValueCellTemplateDirective } from './templates/pivotgrid-value-cell-template.directive';
10
10
  import { ColumnHeaderCellTemplateDirective } from './templates/pivotgrid-column-header-cell-template.directive';
11
11
  import { RowHeaderCellTemplateDirective } from './templates/pivotgrid-row-header-cell-template.directive';
12
+ import { ScrollableTable } from '../virtual/scrollable-container';
12
13
  import { PivotGridCellDirective } from './pivotgrid-cell.directive';
13
- import { NgFor, NgIf } from '@angular/common';
14
+ import { NgFor, NgIf, NgStyle } from '@angular/common';
15
+ import { LocalizationService } from '@progress/kendo-angular-l10n';
16
+ import { Keys, isDocumentAvailable } from '@progress/kendo-angular-common';
17
+ import { isVisible, matchAriaAttributes } from '../util';
18
+ import { PivotGridScrollService } from '../virtual/scroll.service';
14
19
  import * as i0 from "@angular/core";
15
20
  import * as i1 from "../data-binding/pivotgrid-data.service";
21
+ import * as i2 from "@progress/kendo-angular-l10n";
22
+ import * as i3 from "../virtual/scroll.service";
16
23
  /**
17
24
  * @hidden
18
25
  */
19
26
  export class PivotGridTableComponent {
20
- constructor(dataService) {
27
+ constructor(host, dataService, localization, zone, scrollService) {
28
+ this.host = host;
21
29
  this.dataService = dataService;
22
- this.dataChangeSubs = new Subscription();
30
+ this.localization = localization;
31
+ this.zone = zone;
32
+ this.scrollService = scrollService;
33
+ this.startRowIndex = 0;
34
+ this.startColIndex = 0;
35
+ this.rtl = false;
36
+ this.subs = new Subscription();
37
+ this.colsUpdateCallback = (cols) => {
38
+ this.renderedCols = Math.min(cols.length, this.scrollableSettings?.columns);
39
+ this.renderedCols && this.scrollable && (this.scrollable.totalCols = cols.length);
40
+ (this.scrollableSettings && this.scrollableSettings.type !== 'row') && this.scrollable?.onNewData(true);
41
+ this.headerItems = cols;
42
+ isDocumentAvailable() && !this.scrollable && this.tableType === 'values' && (this.columnVirtualization || this.rowVirtualization) && this.initScrollable();
43
+ };
44
+ this.initScrollable = () => {
45
+ this.scrollable = new ScrollableTable(this.host.nativeElement, {
46
+ onScroll: () => {
47
+ this.startRowIndex = this.scrollable.startRow;
48
+ this.startColIndex = this.scrollable.startCol;
49
+ this.renderedRows = this.rows.slice(this.startRowIndex, this.startRowIndex + this.scrollableSettings.rows);
50
+ this.scrollable.renderedRows = this.renderedRows.length;
51
+ this.scrollable.renderedCols = this.renderedCols;
52
+ },
53
+ onScrollEnd: () => {
54
+ matchAriaAttributes(this.host.nativeElement.closest('.k-pivotgrid'));
55
+ }
56
+ }, {
57
+ itemHeight: this.scrollableSettings.rowHeight,
58
+ itemWidth: this.colWidth || 200,
59
+ total: this.totalRows,
60
+ totalCols: this.headerItems.length,
61
+ renderedRows: this.scrollableSettings.rows,
62
+ renderedCols: this.scrollableSettings.columns,
63
+ columnVirtualization: this.columnVirtualization,
64
+ rowVirtualization: this.rowVirtualization,
65
+ rtl: this.rtl
66
+ });
67
+ };
68
+ this.subs.add(this.localization.changes.subscribe(({ rtl }) => {
69
+ this.rtl = rtl;
70
+ this.scrollable && (this.scrollable.rtl = rtl);
71
+ }));
23
72
  }
24
73
  get pivotGridId() {
25
74
  return `kendo-pivotgrid-${this.dataService.pivotGridId}-`;
26
75
  }
76
+ get columnVirtualization() {
77
+ return this.scrollableSettings?.type && this.scrollableSettings?.type !== 'row';
78
+ }
79
+ get rowVirtualization() {
80
+ return this.scrollableSettings?.type && this.scrollableSettings?.type !== 'column';
81
+ }
27
82
  ngOnInit() {
28
- this.dataChangeSubs.add(this.dataService[`${this.tableType}Rows`].subscribe(rows => this.rows = rows));
29
- this.dataChangeSubs.add(this.tableType === 'values' ?
30
- this.dataService.columnHeaderCols.subscribe(cols => this.headerItems = cols) :
31
- this.dataService[`${this.tableType}Cols`].subscribe(cols => this.headerItems = cols));
83
+ this.subs.add(this.dataService[`${this.tableType}Rows`].subscribe(rows => {
84
+ this.rows = rows;
85
+ this.renderedRows = this.scrollableSettings ? rows.slice(this.startRowIndex, this.startRowIndex + this.scrollableSettings.rows) : rows;
86
+ this.totalRows && this.totalRows !== rows.length && this.scrollable && (this.scrollable.total = rows.length);
87
+ this.scrollable && this.scrollable.onNewData(this.totalRows && this.totalRows !== rows.length);
88
+ this.totalRows = rows.length;
89
+ }));
90
+ this.subs.add(this.tableType === 'values' ?
91
+ this.dataService.columnHeaderCols.subscribe(this.colsUpdateCallback) :
92
+ this.dataService[`${this.tableType}Cols`].subscribe(this.colsUpdateCallback));
93
+ }
94
+ ngAfterViewInit() {
95
+ if (isDocumentAvailable() && this.scrollService.virtualScrolling) {
96
+ this.initScrollableKeyboardNavigation();
97
+ }
32
98
  }
33
99
  ngOnDestroy() {
34
- this.dataChangeSubs.unsubscribe();
100
+ this.subs.unsubscribe();
101
+ this.scrollable?.destroy();
102
+ }
103
+ initScrollableKeyboardNavigation() {
104
+ const pivotGrid = this.scrollService.pivotGrid;
105
+ this.host.nativeElement.addEventListener('keydown', (e) => {
106
+ if (this.tableType === 'values' && e.target.tagName === 'TD') {
107
+ e.stopImmediatePropagation();
108
+ e.preventDefault();
109
+ if (e.keyCode === Keys.ArrowLeft) {
110
+ const id = e.target.getAttribute('id');
111
+ if (id.split('-')[5] === '1') {
112
+ const target = document.querySelector(`tr[aria-owns*="${id}"]`);
113
+ pivotGrid.navigation.focusElement(target.lastElementChild, e.target);
114
+ }
115
+ else {
116
+ pivotGrid.navigation.focusElement(e.target.previousElementSibling, e.target);
117
+ if (!isVisible(e.target.previousElementSibling, this.host.nativeElement, this.scrollable.offsetFirst, this.rtl).visibleX) {
118
+ e.target.previousElementSibling.scrollIntoView({ behavior: 'auto', block: 'nearest', inline: 'start' });
119
+ }
120
+ }
121
+ }
122
+ else if (e.keyCode === Keys.ArrowRight) {
123
+ const id = e.target.getAttribute('id');
124
+ if (id.split('-')[5] !== this.headerItems.length.toString()) {
125
+ pivotGrid.navigation.focusElement(e.target.nextElementSibling, e.target);
126
+ if (!isVisible(e.target.nextElementSibling, this.host.nativeElement, this.scrollable.offsetFirst, this.rtl).visibleX) {
127
+ e.target.nextElementSibling.scrollIntoView({ behavior: 'auto', block: 'nearest', inline: 'start' });
128
+ }
129
+ }
130
+ }
131
+ else if (e.keyCode === Keys.ArrowUp) {
132
+ const id = e.target.getAttribute('id');
133
+ if (id.split('-')[4] === '1') {
134
+ const target = document.getElementById(e.target.getAttribute('aria-describedby').split(' ').pop());
135
+ pivotGrid.navigation.focusElement(target, e.target);
136
+ }
137
+ else {
138
+ const index = Array.from(e.target.parentElement.children).findIndex(el => el === e.target);
139
+ const elementToFocus = e.target.parentElement.previousElementSibling.children[index];
140
+ pivotGrid.navigation.focusElement(elementToFocus, e.target);
141
+ if (!isVisible(elementToFocus, this.host.nativeElement, this.scrollable.offsetFirst, this.rtl).visibleY) {
142
+ elementToFocus.scrollIntoView();
143
+ }
144
+ }
145
+ }
146
+ else if (e.keyCode === Keys.ArrowDown) {
147
+ const id = e.target.getAttribute('id');
148
+ if (id.split('-')[4] !== this.totalRows.toString()) {
149
+ const index = Array.from(e.target.parentElement.children).findIndex(el => el === e.target);
150
+ const elementToFocus = e.target.parentElement.nextElementSibling.children[index];
151
+ pivotGrid.navigation.focusElement(elementToFocus, e.target);
152
+ if (!isVisible(elementToFocus, this.host.nativeElement, this.scrollable.offsetFirst, this.rtl).visibleY) {
153
+ elementToFocus.scrollIntoView(false);
154
+ }
155
+ }
156
+ }
157
+ }
158
+ if (this.tableType === 'rowHeader' && e.target.tagName === 'TH' && e.keyCode === Keys.ArrowRight) {
159
+ if (e.target.matches(':last-child')) {
160
+ e.stopImmediatePropagation();
161
+ e.preventDefault();
162
+ const valuesContainer = this.host.nativeElement.nextElementSibling;
163
+ valuesContainer.scrollLeft = this.rtl ? valuesContainer.scrollWidth : 0;
164
+ this.zone.runOutsideAngular(() => setTimeout(() => {
165
+ const elementToFocusId = e.target.parentElement.getAttribute('aria-owns').split(' ')[0];
166
+ const elementToFocus = document.getElementById(elementToFocusId);
167
+ pivotGrid.navigation.focusElement(elementToFocus, e.target);
168
+ }));
169
+ }
170
+ }
171
+ if (this.tableType === 'columnHeader' && e.target.tagName === 'TH' && e.keyCode === Keys.ArrowDown) {
172
+ if (e.target.parentElement.matches(':last-child')) {
173
+ e.stopImmediatePropagation();
174
+ e.preventDefault();
175
+ const valuesContainer = this.host.nativeElement.nextElementSibling.nextElementSibling;
176
+ valuesContainer.scrollTop = 0;
177
+ this.zone.runOutsideAngular(() => setTimeout(() => {
178
+ const elementToFocus = valuesContainer.querySelector(`td[aria-describedby*="${e.target.getAttribute('id')}"]`);
179
+ pivotGrid.navigation.focusElement(elementToFocus, e.target);
180
+ }));
181
+ }
182
+ }
183
+ }, true);
35
184
  }
36
185
  }
37
- PivotGridTableComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.2.10", ngImport: i0, type: PivotGridTableComponent, deps: [{ token: i1.PivotGridDataService }], target: i0.ɵɵFactoryTarget.Component });
38
- PivotGridTableComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "15.2.10", type: PivotGridTableComponent, isStandalone: true, selector: "kendo-pivotgrid-table", inputs: { tableType: "tableType", colWidth: "colWidth", customCellTemplate: "customCellTemplate", valueCellTemplate: "valueCellTemplate", rowHeaderCellTemplate: "rowHeaderCellTemplate", columnHeaderCellTemplate: "columnHeaderCellTemplate" }, ngImport: i0, template: `
186
+ PivotGridTableComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.2.10", ngImport: i0, type: PivotGridTableComponent, deps: [{ token: i0.ElementRef }, { token: i1.PivotGridDataService }, { token: i2.LocalizationService }, { token: i0.NgZone }, { token: i3.PivotGridScrollService }], target: i0.ɵɵFactoryTarget.Component });
187
+ PivotGridTableComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "15.2.10", type: PivotGridTableComponent, isStandalone: true, selector: "kendo-pivotgrid-table", inputs: { tableType: "tableType", colWidth: "colWidth", customCellTemplate: "customCellTemplate", valueCellTemplate: "valueCellTemplate", rowHeaderCellTemplate: "rowHeaderCellTemplate", columnHeaderCellTemplate: "columnHeaderCellTemplate", scrollableSettings: "scrollableSettings" }, ngImport: i0, template: `
39
188
  <table
40
189
  class="k-pivotgrid-table"
41
- role="presentation">
190
+ role="presentation"
191
+ [ngStyle]="{float: this.tableType === 'values' ? this.rtl ? 'right' : 'left' : 'initial'}">
42
192
  <colgroup>
193
+ <col *ngIf="tableType === 'values' && columnVirtualization && startColIndex > 0" [style.width]="startColIndex * (colWidth >= 0 ? colWidth : 200) + 'px'"/>
43
194
  <col
44
- *ngFor="let item of headerItems;"
195
+ *ngFor="let item of (tableType === 'values' && columnVirtualization ? headerItems?.slice(0, renderedCols) : headerItems);"
45
196
  [style.width]="tableType !== 'rowHeader' ? colWidth >= 0 ? colWidth + 'px' : '200px' : undefined" />
46
197
  </colgroup>
47
198
  <tbody class="k-pivotgrid-tbody" [attr.role]="tableType === 'values' ? 'none' : 'rowgroup'">
48
- <tr *ngFor="let row of rows; index as rowIndex"
199
+ <tr *ngFor="let row of (tableType === 'values' && rowVirtualization ? renderedRows : rows); index as rowIndex"
49
200
  class="k-pivotgrid-row"
50
201
  [attr.role]="tableType === 'values' ? 'none' : 'row'">
51
- <ng-container *ngFor="let cell of row.cells; index as colIndex">
202
+ <td *ngIf="tableType === 'values' && columnVirtualization && startColIndex > 0" class="k-pivotgrid-cell"></td>
203
+ <ng-container *ngFor="let cell of (tableType === 'values' && columnVirtualization ? row.cells.slice(startColIndex, (startColIndex + renderedCols)) : row.cells); index as colIndex">
52
204
  <th
53
205
  *ngIf="cell && tableType !== 'values'"
54
206
  [kendoPivotGridCell]="cell"
@@ -56,8 +208,8 @@ PivotGridTableComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0"
56
208
  [rowHeaderCellTemplate]="rowHeaderCellTemplate"
57
209
  [columnHeaderCellTemplate]="columnHeaderCellTemplate"
58
210
  [tableType]="tableType"
59
- [colIndex]="colIndex"
60
- [rowIndex]="rowIndex"
211
+ [colIndex]="colIndex + startColIndex"
212
+ [rowIndex]="rowIndex + startRowIndex"
61
213
  [attr.aria-expanded]="cell.hasChildren && cell.children.length ? 'true' : 'false'"
62
214
  [attr.role]="tableType === 'columnHeader' ? 'columnheader' : tableType === 'rowHeader' ? 'rowheader' : 'none'"
63
215
  [attr.id]="pivotGridId + (tableType === 'columnHeader' ? 'ch-' : 'rh-') + (rowIndex + 1) + '-' + (colIndex + 1)"></th>
@@ -67,15 +219,15 @@ PivotGridTableComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0"
67
219
  [valueCellTemplate]="valueCellTemplate"
68
220
  [kendoPivotGridCell]="cell"
69
221
  tableType="values"
70
- [colIndex]="colIndex"
71
- [rowIndex]="rowIndex"
222
+ [colIndex]="colIndex + startColIndex"
223
+ [rowIndex]="rowIndex + startRowIndex"
72
224
  role="gridcell"
73
- [attr.id]="pivotGridId + 'cell-' + (rowIndex + 1) + '-' + (colIndex + 1)"></td>
225
+ [attr.id]="pivotGridId + 'cell-' + (rowIndex + startRowIndex + 1) + '-' + (colIndex + startColIndex + 1)"></td>
74
226
  </ng-container>
75
227
  </tr>
76
228
  </tbody>
77
229
  </table>
78
- `, isInline: true, dependencies: [{ kind: "directive", type: NgFor, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "component", type: PivotGridCellDirective, selector: "[kendoPivotGridCell]", inputs: ["kendoPivotGridCell", "tableType", "rowIndex", "colIndex", "customCellTemplate", "valueCellTemplate", "rowHeaderCellTemplate", "columnHeaderCellTemplate"] }] });
230
+ `, isInline: true, dependencies: [{ kind: "directive", type: NgFor, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "component", type: PivotGridCellDirective, selector: "[kendoPivotGridCell]", inputs: ["kendoPivotGridCell", "tableType", "rowIndex", "colIndex", "customCellTemplate", "valueCellTemplate", "rowHeaderCellTemplate", "columnHeaderCellTemplate"] }, { kind: "directive", type: NgStyle, selector: "[ngStyle]", inputs: ["ngStyle"] }] });
79
231
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.10", ngImport: i0, type: PivotGridTableComponent, decorators: [{
80
232
  type: Component,
81
233
  args: [{
@@ -83,17 +235,20 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.10", ngImpo
83
235
  template: `
84
236
  <table
85
237
  class="k-pivotgrid-table"
86
- role="presentation">
238
+ role="presentation"
239
+ [ngStyle]="{float: this.tableType === 'values' ? this.rtl ? 'right' : 'left' : 'initial'}">
87
240
  <colgroup>
241
+ <col *ngIf="tableType === 'values' && columnVirtualization && startColIndex > 0" [style.width]="startColIndex * (colWidth >= 0 ? colWidth : 200) + 'px'"/>
88
242
  <col
89
- *ngFor="let item of headerItems;"
243
+ *ngFor="let item of (tableType === 'values' && columnVirtualization ? headerItems?.slice(0, renderedCols) : headerItems);"
90
244
  [style.width]="tableType !== 'rowHeader' ? colWidth >= 0 ? colWidth + 'px' : '200px' : undefined" />
91
245
  </colgroup>
92
246
  <tbody class="k-pivotgrid-tbody" [attr.role]="tableType === 'values' ? 'none' : 'rowgroup'">
93
- <tr *ngFor="let row of rows; index as rowIndex"
247
+ <tr *ngFor="let row of (tableType === 'values' && rowVirtualization ? renderedRows : rows); index as rowIndex"
94
248
  class="k-pivotgrid-row"
95
249
  [attr.role]="tableType === 'values' ? 'none' : 'row'">
96
- <ng-container *ngFor="let cell of row.cells; index as colIndex">
250
+ <td *ngIf="tableType === 'values' && columnVirtualization && startColIndex > 0" class="k-pivotgrid-cell"></td>
251
+ <ng-container *ngFor="let cell of (tableType === 'values' && columnVirtualization ? row.cells.slice(startColIndex, (startColIndex + renderedCols)) : row.cells); index as colIndex">
97
252
  <th
98
253
  *ngIf="cell && tableType !== 'values'"
99
254
  [kendoPivotGridCell]="cell"
@@ -101,8 +256,8 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.10", ngImpo
101
256
  [rowHeaderCellTemplate]="rowHeaderCellTemplate"
102
257
  [columnHeaderCellTemplate]="columnHeaderCellTemplate"
103
258
  [tableType]="tableType"
104
- [colIndex]="colIndex"
105
- [rowIndex]="rowIndex"
259
+ [colIndex]="colIndex + startColIndex"
260
+ [rowIndex]="rowIndex + startRowIndex"
106
261
  [attr.aria-expanded]="cell.hasChildren && cell.children.length ? 'true' : 'false'"
107
262
  [attr.role]="tableType === 'columnHeader' ? 'columnheader' : tableType === 'rowHeader' ? 'rowheader' : 'none'"
108
263
  [attr.id]="pivotGridId + (tableType === 'columnHeader' ? 'ch-' : 'rh-') + (rowIndex + 1) + '-' + (colIndex + 1)"></th>
@@ -112,19 +267,19 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.10", ngImpo
112
267
  [valueCellTemplate]="valueCellTemplate"
113
268
  [kendoPivotGridCell]="cell"
114
269
  tableType="values"
115
- [colIndex]="colIndex"
116
- [rowIndex]="rowIndex"
270
+ [colIndex]="colIndex + startColIndex"
271
+ [rowIndex]="rowIndex + startRowIndex"
117
272
  role="gridcell"
118
- [attr.id]="pivotGridId + 'cell-' + (rowIndex + 1) + '-' + (colIndex + 1)"></td>
273
+ [attr.id]="pivotGridId + 'cell-' + (rowIndex + startRowIndex + 1) + '-' + (colIndex + startColIndex + 1)"></td>
119
274
  </ng-container>
120
275
  </tr>
121
276
  </tbody>
122
277
  </table>
123
278
  `,
124
279
  standalone: true,
125
- imports: [NgFor, NgIf, PivotGridCellDirective]
280
+ imports: [NgFor, NgIf, PivotGridCellDirective, NgStyle]
126
281
  }]
127
- }], ctorParameters: function () { return [{ type: i1.PivotGridDataService }]; }, propDecorators: { tableType: [{
282
+ }], ctorParameters: function () { return [{ type: i0.ElementRef }, { type: i1.PivotGridDataService }, { type: i2.LocalizationService }, { type: i0.NgZone }, { type: i3.PivotGridScrollService }]; }, propDecorators: { tableType: [{
128
283
  type: Input
129
284
  }], colWidth: [{
130
285
  type: Input
@@ -136,4 +291,6 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.10", ngImpo
136
291
  type: Input
137
292
  }], columnHeaderCellTemplate: [{
138
293
  type: Input
294
+ }], scrollableSettings: [{
295
+ type: Input
139
296
  }] } });
package/esm2020/util.mjs CHANGED
@@ -110,19 +110,19 @@ export const matchAriaAttributes = (wrapper) => {
110
110
  const firstColHeaderRowCellsIds = Array.from(firstColHeadersRow?.children).map(el => el.getAttribute('id')).join(' ');
111
111
  firstColHeadersRow.setAttribute('aria-owns', `${emptyCell.getAttribute('id')} ${firstColHeaderRowCellsIds}`);
112
112
  rowHeaderRows.forEach((row, index) => {
113
- const valueCellsIds = filterAndMap(Array.from(valueTableCells), c => c.getAttribute('id').split('-')[4] === (index + 1).toString(), c => c.getAttribute('id'));
113
+ const valueCellsIds = filterAndMap(Array.from(valueTableCells), c => c.getAttribute('id')?.split('-')[4] === (index + 1).toString(), c => c.getAttribute('id'));
114
114
  row.setAttribute('aria-owns', valueCellsIds.join(' '));
115
115
  });
116
116
  valueTableCells.forEach(cell => {
117
- const cellColIndex = +cell.getAttribute('id').split('-')[5];
117
+ const cellColIndex = +cell.getAttribute('id')?.split('-')[5];
118
118
  const colHeaderCellsIds = filterAndMap(Array.from(colHeaderCells), c => {
119
- const headerCellColIndex = +c.getAttribute('id').split('-')[5];
119
+ const headerCellColIndex = +c.getAttribute('id')?.split('-')[5];
120
120
  const headerCellColspan = +c.getAttribute('colspan');
121
121
  const colIndexIsEqual = cellColIndex === headerCellColIndex;
122
- const cellColIndexIsWithinHeaderCellRange = headerCellColspan > 1 && (headerCellColIndex + headerCellColspan - 1 >= cellColIndex);
122
+ const cellColIndexIsWithinHeaderCellRange = headerCellColIndex < cellColIndex && headerCellColspan > 1 && (headerCellColIndex + headerCellColspan - 1 >= cellColIndex);
123
123
  return colIndexIsEqual || cellColIndexIsWithinHeaderCellRange;
124
124
  }, c => c.getAttribute('id'));
125
- cell.setAttribute('aria-describedby', colHeaderCellsIds.join(' '));
125
+ colHeaderCellsIds.length && cell.setAttribute('aria-describedby', colHeaderCellsIds.join(' '));
126
126
  });
127
127
  };
128
128
  /**
@@ -197,3 +197,28 @@ export const swapItems = (arr, i1, i2) => {
197
197
  arr[i1] = arr[i2];
198
198
  arr[i2] = temp;
199
199
  };
200
+ /**
201
+ * @hidden
202
+ */
203
+ export const isVisible = (el, container, offsetY, rtl) => {
204
+ const elTop = el.offsetTop;
205
+ const elBottom = elTop + el.clientHeight;
206
+ let rect;
207
+ let containerRect;
208
+ if (rtl) {
209
+ rect = el.getBoundingClientRect();
210
+ containerRect = container.getBoundingClientRect();
211
+ }
212
+ const elLeft = rtl ? rect.left : el.offsetLeft;
213
+ const elRight = rtl ? rect.right : elLeft + el.clientWidth;
214
+ const containerTop = container.scrollTop;
215
+ const containerBottom = containerTop + container.clientHeight;
216
+ const containerLeft = rtl ? containerRect.left : container.scrollLeft;
217
+ const containerRight = rtl ? containerRect.right : containerLeft + container.clientWidth;
218
+ const visibleY = elTop >= containerTop - offsetY && elBottom <= containerBottom - offsetY;
219
+ const visibleX = rtl ? elRight <= containerRight && elLeft >= containerLeft : elLeft >= containerLeft && elRight <= containerRight;
220
+ return {
221
+ visibleX,
222
+ visibleY
223
+ };
224
+ };
@@ -0,0 +1,19 @@
1
+ /**-----------------------------------------------------------------------------------------
2
+ * Copyright © 2024 Progress Software Corporation. All rights reserved.
3
+ * Licensed under commercial license. See LICENSE.md in the project root for more information
4
+ *-------------------------------------------------------------------------------------------*/
5
+ import { Injectable } from '@angular/core';
6
+ import * as i0 from "@angular/core";
7
+ /**
8
+ * @hidden
9
+ */
10
+ export class PivotGridScrollService {
11
+ constructor() {
12
+ this.virtualScrolling = false;
13
+ }
14
+ }
15
+ PivotGridScrollService.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.2.10", ngImport: i0, type: PivotGridScrollService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
16
+ PivotGridScrollService.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "15.2.10", ngImport: i0, type: PivotGridScrollService });
17
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.10", ngImport: i0, type: PivotGridScrollService, decorators: [{
18
+ type: Injectable
19
+ }] });
@@ -0,0 +1,114 @@
1
+ /**-----------------------------------------------------------------------------------------
2
+ * Copyright © 2024 Progress Software Corporation. All rights reserved.
3
+ * Licensed under commercial license. See LICENSE.md in the project root for more information
4
+ *-------------------------------------------------------------------------------------------*/
5
+ /**
6
+ * @hidden
7
+ */
8
+ export class ScrollableTable {
9
+ constructor(element, handlers, options) {
10
+ this.element = element;
11
+ this.handlers = handlers;
12
+ this.options = options;
13
+ this.startRow = 0;
14
+ this.startCol = 0;
15
+ this.lastKnownScrollPosition = { top: 0, left: 0 };
16
+ this.offsetFirst = 0;
17
+ this.scrollHandler = (e) => {
18
+ const verticalDir = this.element.scrollTop - this.lastKnownScrollPosition.top;
19
+ const horizontalDir = Math.abs(this.element.scrollLeft) - this.lastKnownScrollPosition.left;
20
+ if (this.options.rowVirtualization) {
21
+ if (verticalDir > 0) {
22
+ if (this.element.scrollTop > (this.renderedRows * this.options.itemHeight + this.offsetFirst - this.rect.height)) {
23
+ this.startRow = Math.floor(this.element.scrollTop / this.options.itemHeight);
24
+ this.rowVirtualizationUpdate();
25
+ }
26
+ }
27
+ else {
28
+ if (this.element.scrollTop <= this.offsetFirst) {
29
+ this.startRow = Math.max(0, Math.ceil(this.element.scrollTop / this.options.itemHeight) - Math.ceil(this.options.renderedRows / 3));
30
+ this.rowVirtualizationUpdate();
31
+ }
32
+ }
33
+ }
34
+ if (this.options.columnVirtualization) {
35
+ if (horizontalDir > 0) {
36
+ if (Math.abs(this.element.scrollLeft) - (Math.max(this.startCol - 1, 0) * (this.options.colWidth || 200)) > (this.options.colWidth || 200)) {
37
+ this.startCol = Math.min(Math.max(Math.floor(Math.abs(this.element.scrollLeft) / this.options.itemWidth) - 1, 0), this.totalCols - this.renderedCols);
38
+ this.handlers.onScroll();
39
+ }
40
+ }
41
+ else {
42
+ if (Math.abs(this.element.scrollLeft) <= (this.startCol + 1) * (this.options.colWidth || 200)) {
43
+ this.startCol = Math.min(Math.max(Math.floor(Math.abs(this.element.scrollLeft) / this.options.itemWidth) - 1, 0), this.totalCols - this.renderedCols);
44
+ this.handlers.onScroll();
45
+ }
46
+ }
47
+ }
48
+ this.lastKnownScrollPosition = {
49
+ top: this.element.scrollTop,
50
+ left: Math.abs(this.element.scrollLeft)
51
+ };
52
+ };
53
+ this.scrollEndHandler = () => {
54
+ this.handlers.onScrollEnd();
55
+ };
56
+ this.initialize();
57
+ }
58
+ onNewData(recalculateSize = false) {
59
+ this.offsetFirst = this.startRow * this.options.itemHeight;
60
+ this.renderedRows = Math.min(this.options.renderedRows || Math.ceil(this.visibleRows * 3), this.total);
61
+ this.endRow = this.startRow + this.renderedRows;
62
+ this.renderedCols = Math.min(this.options.renderedCols || Math.ceil(this.visibleCols * 1.3), this.totalCols);
63
+ this.element.querySelector('table').style.transform = `translateY(${this.offsetFirst}px)`;
64
+ recalculateSize && this.recalculateSize();
65
+ }
66
+ destroy() {
67
+ this.element.removeEventListener('scroll', this.scrollHandler);
68
+ this.element.removeEventListener('scrollend', this.scrollEndHandler);
69
+ this.element.removeChild(this.stretcher);
70
+ }
71
+ initialize() {
72
+ this.rtl = this.options.rtl;
73
+ this.rect = this.element.getBoundingClientRect();
74
+ // visible rows and cols
75
+ this.visibleRows = Math.ceil(this.rect.height / this.options.itemHeight);
76
+ this.visibleCols = Math.ceil(this.rect.width / this.options.itemWidth);
77
+ // current totals
78
+ this.total = this.options.total;
79
+ this.totalCols = this.options.totalCols;
80
+ const totalHeight = this.total * this.options.itemHeight;
81
+ const totalWidth = this.totalCols * this.options.itemWidth;
82
+ // "page" size (rows and cols)
83
+ this.renderedRows = Math.min(this.options.renderedRows || Math.ceil(this.visibleRows * 3), this.total);
84
+ this.renderedCols = Math.min(this.options.renderedCols || Math.ceil(this.visibleCols * 1.3), this.totalCols);
85
+ // start and end row/col
86
+ this.startRow = 0;
87
+ this.startCol = 0;
88
+ this.endRow = this.startRow + this.renderedRows;
89
+ this.endCol = this.startCol + this.renderedCols;
90
+ // element that ensures correct scrolling dimensions of the container
91
+ this.stretcher = document.createElement('DIV');
92
+ this.stretcher.style.height = `${totalHeight}px`;
93
+ this.stretcher.style.width = `${totalWidth}px`;
94
+ this.element.appendChild(this.stretcher);
95
+ this.element.addEventListener('scroll', this.scrollHandler);
96
+ this.element.addEventListener('scrollend', this.scrollEndHandler);
97
+ }
98
+ recalculateSize() {
99
+ const totalHeight = this.total * this.options.itemHeight;
100
+ const totalWidth = this.totalCols * this.options.itemWidth;
101
+ this.stretcher.style.height = `${totalHeight}px`;
102
+ this.stretcher.style.width = `${totalWidth}px`;
103
+ this.rect = this.element.getBoundingClientRect();
104
+ // visible rows and cols
105
+ this.visibleRows = Math.ceil(this.rect.height / this.options.itemHeight);
106
+ this.visibleCols = Math.ceil(this.rect.width / this.options.itemWidth);
107
+ }
108
+ rowVirtualizationUpdate() {
109
+ this.endRow = Math.min(this.startRow + this.renderedRows, this.total);
110
+ this.offsetFirst = this.startRow * this.options.itemHeight;
111
+ this.element.querySelector('table').style.transform = `translateY(${this.offsetFirst}px)`;
112
+ this.handlers.onScroll();
113
+ }
114
+ }