@fundamental-ngx/platform 0.43.35 → 0.43.37
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/esm2020/form/multi-combobox/multi-combobox/multi-combobox.component.mjs +3 -1
- package/esm2020/table/components/table-row/table-row.component.mjs +4 -3
- package/esm2020/table/table.component.mjs +55 -12
- package/esm2020/table-helpers/directives/table-virtual-scroll.directive.mjs +235 -37
- package/esm2020/table-helpers/models/directives.mjs +1 -1
- package/esm2020/table-helpers/services/table-column-resize.service.mjs +26 -5
- package/esm2020/table-helpers/table.mjs +1 -1
- package/fesm2015/fundamental-ngx-platform-form.mjs +2 -0
- package/fesm2015/fundamental-ngx-platform-form.mjs.map +1 -1
- package/fesm2015/fundamental-ngx-platform-table-helpers.mjs +363 -147
- package/fesm2015/fundamental-ngx-platform-table-helpers.mjs.map +1 -1
- package/fesm2015/fundamental-ngx-platform-table.mjs +177 -133
- package/fesm2015/fundamental-ngx-platform-table.mjs.map +1 -1
- package/fesm2020/fundamental-ngx-platform-form.mjs +2 -0
- package/fesm2020/fundamental-ngx-platform-form.mjs.map +1 -1
- package/fesm2020/fundamental-ngx-platform-table-helpers.mjs +364 -148
- package/fesm2020/fundamental-ngx-platform-table-helpers.mjs.map +1 -1
- package/fesm2020/fundamental-ngx-platform-table.mjs +176 -133
- package/fesm2020/fundamental-ngx-platform-table.mjs.map +1 -1
- package/fundamental-ngx-platform-v0.43.37.tgz +0 -0
- package/package.json +4 -4
- package/schematics/ng-add/index.js +1 -1
- package/table/table.component.d.ts +9 -0
- package/table-helpers/directives/table-virtual-scroll.directive.d.ts +64 -5
- package/table-helpers/models/directives.d.ts +1 -0
- package/table-helpers/services/table-column-resize.service.d.ts +4 -0
- package/table-helpers/table.d.ts +10 -2
- package/fundamental-ngx-platform-v0.43.35.tgz +0 -0
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import * as i0 from '@angular/core';
|
|
2
|
-
import { InjectionToken, Injectable, EventEmitter, inject, Directive, Input, Output, NgZone, ChangeDetectorRef, forwardRef, HostBinding, Optional, ElementRef, Inject, Pipe, NgModule } from '@angular/core';
|
|
2
|
+
import { InjectionToken, Injectable, EventEmitter, inject, Directive, Input, Output, NgZone, ChangeDetectorRef, forwardRef, HostBinding, HostListener, Optional, ElementRef, Inject, Pipe, NgModule } from '@angular/core';
|
|
3
3
|
import * as i2 from '@fundamental-ngx/cdk/utils';
|
|
4
|
-
import { DestroyedService, isString, dfs,
|
|
4
|
+
import { DestroyedService, isString, dfs, KeyUtil, RtlService, resizeObservable, FDK_FOCUSABLE_ITEM_DIRECTIVE, FocusableItemDirective } from '@fundamental-ngx/cdk/utils';
|
|
5
5
|
import { isDataSource, DataSourceDirective, FD_DATA_SOURCE_TRANSFORMER } from '@fundamental-ngx/cdk/data-source';
|
|
6
6
|
import { Subject, BehaviorSubject, isObservable, Subscription, filter as filter$1, fromEvent, Observable, take as take$1, takeUntil as takeUntil$1 } from 'rxjs';
|
|
7
7
|
import { map, takeUntil, take, skip, startWith, filter, debounceTime, distinctUntilChanged, share, tap } from 'rxjs/operators';
|
|
@@ -12,7 +12,8 @@ import { get } from 'lodash-es';
|
|
|
12
12
|
import equal from 'fast-deep-equal';
|
|
13
13
|
import cloneDeep from 'lodash-es/cloneDeep';
|
|
14
14
|
import set from 'lodash-es/set';
|
|
15
|
-
import { LEFT_ARROW, RIGHT_ARROW } from '@angular/cdk/keycodes';
|
|
15
|
+
import { UP_ARROW, DOWN_ARROW, LEFT_ARROW, RIGHT_ARROW } from '@angular/cdk/keycodes';
|
|
16
|
+
import { coerceBooleanProperty } from '@angular/cdk/coercion';
|
|
16
17
|
import { DOCUMENT } from '@angular/common';
|
|
17
18
|
import { TableCellDirective } from '@fundamental-ngx/core/table';
|
|
18
19
|
import * as i1 from '@angular/forms';
|
|
@@ -2328,6 +2329,113 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.9", ngImpor
|
|
|
2328
2329
|
type: Injectable
|
|
2329
2330
|
}] });
|
|
2330
2331
|
|
|
2332
|
+
class TableRowService {
|
|
2333
|
+
constructor() {
|
|
2334
|
+
/** @hidden */
|
|
2335
|
+
this._toggleRowSubject = new Subject();
|
|
2336
|
+
/** @hidden */
|
|
2337
|
+
this._scrollToOverlappedCellSubject = new Subject();
|
|
2338
|
+
/** @hidden */
|
|
2339
|
+
this._cellClickedSubject = new Subject();
|
|
2340
|
+
/** @hidden */
|
|
2341
|
+
this._cellFocusedSubject = new Subject();
|
|
2342
|
+
/** @hidden */
|
|
2343
|
+
this._cellActivateSubject = new Subject();
|
|
2344
|
+
/** Stream that emits when the table cell being focused. */
|
|
2345
|
+
this.cellActivate$ = this._cellActivateSubject.asObservable();
|
|
2346
|
+
/** @hidden */
|
|
2347
|
+
this._toggleAllSelectableRowsSubject = new Subject();
|
|
2348
|
+
/** Stream that emits when toggling all selectable rows is needed. */
|
|
2349
|
+
this.toggleAllSelectableRows$ = this._toggleAllSelectableRowsSubject.asObservable();
|
|
2350
|
+
/** Stream that emits when table cell being clicked. */
|
|
2351
|
+
this.cellClicked$ = this._cellClickedSubject.asObservable();
|
|
2352
|
+
/** Stream that emits when scrolling to overlapped cell is needed. */
|
|
2353
|
+
this.scrollToOverlappedCell$ = this._scrollToOverlappedCellSubject.asObservable();
|
|
2354
|
+
/** Stream that emits when the table cell being focused. */
|
|
2355
|
+
this.cellFocused$ = this._cellFocusedSubject.asObservable();
|
|
2356
|
+
/** Toggle row stream. */
|
|
2357
|
+
this.toggleRow$ = this._toggleRowSubject.asObservable();
|
|
2358
|
+
/** Editable cells map. */
|
|
2359
|
+
this.editableCells = new Map();
|
|
2360
|
+
/** @hidden */
|
|
2361
|
+
this.childRowsAdded$ = new Subject();
|
|
2362
|
+
/** Stream to load child items for a particular rows. */
|
|
2363
|
+
this.loadChildRows$ = new Subject();
|
|
2364
|
+
}
|
|
2365
|
+
/** `toggleRow$` stream trigger. */
|
|
2366
|
+
toggleRow(evt) {
|
|
2367
|
+
this._toggleRowSubject.next(evt);
|
|
2368
|
+
}
|
|
2369
|
+
/** `scrollToOverlappedCell$` stream trigger. */
|
|
2370
|
+
scrollToOverlappedCell() {
|
|
2371
|
+
this._scrollToOverlappedCellSubject.next();
|
|
2372
|
+
}
|
|
2373
|
+
/** `cellClicked$` stream trigger. */
|
|
2374
|
+
cellClicked(evt) {
|
|
2375
|
+
this._cellClickedSubject.next(evt);
|
|
2376
|
+
}
|
|
2377
|
+
/** @hidden */
|
|
2378
|
+
cellActivate(columnIndex, row) {
|
|
2379
|
+
this._cellActivateSubject.next({ columnIndex, row: row.value });
|
|
2380
|
+
}
|
|
2381
|
+
/** `cellFocused$` stream trigger. */
|
|
2382
|
+
cellFocused(evt) {
|
|
2383
|
+
this._cellFocusedSubject.next(evt);
|
|
2384
|
+
}
|
|
2385
|
+
/** `toggleAllSelectableRows$` stream trigger. */
|
|
2386
|
+
toggleAllSelectableRows(selectAll) {
|
|
2387
|
+
this._toggleAllSelectableRowsSubject.next(selectAll);
|
|
2388
|
+
}
|
|
2389
|
+
/** Groups the table rows. */
|
|
2390
|
+
groupTableRows(sourceRows, groups, groupRulesMap) {
|
|
2391
|
+
const groupRules = Array.from(groups);
|
|
2392
|
+
if (!groupRules.length) {
|
|
2393
|
+
/**
|
|
2394
|
+
* In case if previously we had groups with collapsed items
|
|
2395
|
+
* but now we don't have it we need to reset row.hidden flag
|
|
2396
|
+
* in order to avoid empty table after groups settings removing
|
|
2397
|
+
*/
|
|
2398
|
+
sourceRows.forEach((row) => {
|
|
2399
|
+
row.hidden = false;
|
|
2400
|
+
});
|
|
2401
|
+
return sourceRows;
|
|
2402
|
+
}
|
|
2403
|
+
// Build tree like groups
|
|
2404
|
+
const treeLikeGroupedRows = createGroupedTableRowsTree(groupRules, sourceRows);
|
|
2405
|
+
// Sort tree like groups
|
|
2406
|
+
const sortedTreeLikeGroupedRows = sortTreeLikeGroupedRows(treeLikeGroupedRows, groupRulesMap);
|
|
2407
|
+
// Convert tree like list to a flat list
|
|
2408
|
+
return convertTreeLikeToFlatList(sortedTreeLikeGroupedRows);
|
|
2409
|
+
}
|
|
2410
|
+
/** Sets editable cells for particular row. */
|
|
2411
|
+
updateEditableCells(row, cells) {
|
|
2412
|
+
this.editableCells.set(row, cells);
|
|
2413
|
+
}
|
|
2414
|
+
/** Removes editable cells of particular row. */
|
|
2415
|
+
removeEditableCells(row) {
|
|
2416
|
+
this.editableCells.delete(row);
|
|
2417
|
+
}
|
|
2418
|
+
/** Triggers stream to load child items for a particular rows. */
|
|
2419
|
+
loadChildRows(rows) {
|
|
2420
|
+
const expandableRows = [];
|
|
2421
|
+
if (Array.isArray(rows)) {
|
|
2422
|
+
expandableRows.push(...rows.filter((r) => !r.childItemsLoading$.value));
|
|
2423
|
+
}
|
|
2424
|
+
else {
|
|
2425
|
+
if (rows.childItemsLoading$.value) {
|
|
2426
|
+
return;
|
|
2427
|
+
}
|
|
2428
|
+
expandableRows.push(rows);
|
|
2429
|
+
}
|
|
2430
|
+
this.loadChildRows$.next(expandableRows);
|
|
2431
|
+
}
|
|
2432
|
+
}
|
|
2433
|
+
TableRowService.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.2.9", ngImport: i0, type: TableRowService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
|
|
2434
|
+
TableRowService.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "15.2.9", ngImport: i0, type: TableRowService });
|
|
2435
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.9", ngImport: i0, type: TableRowService, decorators: [{
|
|
2436
|
+
type: Injectable
|
|
2437
|
+
}] });
|
|
2438
|
+
|
|
2331
2439
|
class TableVirtualScrollDirective extends TableVirtualScroll {
|
|
2332
2440
|
constructor() {
|
|
2333
2441
|
super(...arguments);
|
|
@@ -2351,7 +2459,104 @@ class TableVirtualScrollDirective extends TableVirtualScroll {
|
|
|
2351
2459
|
/** @hidden */
|
|
2352
2460
|
this._tableScrollDispatcher = inject(TableScrollDispatcherService);
|
|
2353
2461
|
/** @hidden */
|
|
2462
|
+
this._tableRowService = inject(TableRowService);
|
|
2463
|
+
/** @hidden */
|
|
2354
2464
|
this._destroy$ = inject(DestroyedService);
|
|
2465
|
+
/** @hidden */
|
|
2466
|
+
this._lastMockScrollPosition = 0;
|
|
2467
|
+
/** @hidden */
|
|
2468
|
+
this._previousStartNodeIndex = null;
|
|
2469
|
+
/** @hidden */
|
|
2470
|
+
this._scrollWholeRows = false;
|
|
2471
|
+
/**
|
|
2472
|
+
* @hidden
|
|
2473
|
+
* This function is called when the user performs a wheel event. It determines whether or not the user has scrolled
|
|
2474
|
+
* up or down using the event's deltaX property, and scrolls the table by one row.
|
|
2475
|
+
*/
|
|
2476
|
+
this._wheelScrollListenerFunction = (event) => {
|
|
2477
|
+
if (Math.abs(event.deltaX) < Math.abs(event.deltaY)) {
|
|
2478
|
+
event.preventDefault();
|
|
2479
|
+
event.stopImmediatePropagation();
|
|
2480
|
+
if (this._wheelTimeout) {
|
|
2481
|
+
window.cancelAnimationFrame(this._wheelTimeout);
|
|
2482
|
+
}
|
|
2483
|
+
const deltaY = event.deltaY;
|
|
2484
|
+
if (deltaY) {
|
|
2485
|
+
this._wheelTimeout = window.requestAnimationFrame(() => {
|
|
2486
|
+
this._scrollRow(deltaY > 0 ? 1 : -1);
|
|
2487
|
+
});
|
|
2488
|
+
}
|
|
2489
|
+
}
|
|
2490
|
+
};
|
|
2491
|
+
/**
|
|
2492
|
+
* @hidden
|
|
2493
|
+
* This function is called when the mock scrollbar (when using 'scrollWholeRows') is moved. It determines if the
|
|
2494
|
+
* scroll was up or down by comparing the current scroll top to the previous scroll top and scrolls rows accordingly.
|
|
2495
|
+
*/
|
|
2496
|
+
this._mockScrollbarListenerFunction = (event) => {
|
|
2497
|
+
event.preventDefault();
|
|
2498
|
+
event.stopImmediatePropagation();
|
|
2499
|
+
if (this._scrollMockTimeout) {
|
|
2500
|
+
window.cancelAnimationFrame(this._scrollMockTimeout);
|
|
2501
|
+
}
|
|
2502
|
+
const tableScrollMockContainer = this._table.tableScrollMockContainer.nativeElement;
|
|
2503
|
+
let deltaY = tableScrollMockContainer.scrollTop - this._lastMockScrollPosition;
|
|
2504
|
+
deltaY = Math.ceil(deltaY / this.rowHeight);
|
|
2505
|
+
this._scrollMockTimeout = window.requestAnimationFrame(() => {
|
|
2506
|
+
this._scrollRow(deltaY, true);
|
|
2507
|
+
this._lastMockScrollPosition = tableScrollMockContainer.scrollTop;
|
|
2508
|
+
if (tableScrollMockContainer.scrollTop === 0) {
|
|
2509
|
+
// Always display the first row of the table when the user scrolls all the way to the top
|
|
2510
|
+
this._setRows(0);
|
|
2511
|
+
}
|
|
2512
|
+
if (tableScrollMockContainer.scrollTop + tableScrollMockContainer.getBoundingClientRect().height ===
|
|
2513
|
+
tableScrollMockContainer.scrollHeight) {
|
|
2514
|
+
// Always display the last rows of the table when the user scrolls all the way to the bottom
|
|
2515
|
+
const startingNodeIndex = this._table._tableRowsVisible.length - this._getNumberOfRowsToDisplay();
|
|
2516
|
+
this._setRows(startingNodeIndex);
|
|
2517
|
+
}
|
|
2518
|
+
});
|
|
2519
|
+
};
|
|
2520
|
+
}
|
|
2521
|
+
/**
|
|
2522
|
+
* Whether to scroll whole rows rather than pixel by pixel when the user performs a scroll.
|
|
2523
|
+
* This gives greater performance improvements but also lends to some potentially undesirable UX changes.
|
|
2524
|
+
* A "rowHeight" must be provided when using this feature.
|
|
2525
|
+
*/
|
|
2526
|
+
set scrollWholeRows(value) {
|
|
2527
|
+
this._scrollWholeRows = coerceBooleanProperty(value);
|
|
2528
|
+
if (this._scrollWholeRows) {
|
|
2529
|
+
this.virtualScroll = true;
|
|
2530
|
+
}
|
|
2531
|
+
}
|
|
2532
|
+
get scrollWholeRows() {
|
|
2533
|
+
return this._scrollWholeRows;
|
|
2534
|
+
}
|
|
2535
|
+
/** @hidden */
|
|
2536
|
+
_keydownHandler(event) {
|
|
2537
|
+
var _a, _b;
|
|
2538
|
+
if (this.scrollWholeRows) {
|
|
2539
|
+
if (((_a = this._focusedCell) === null || _a === void 0 ? void 0 : _a.rowIndex) === 0 && KeyUtil.isKeyCode(event, UP_ARROW)) {
|
|
2540
|
+
if (this._table.tableContainer.nativeElement.querySelectorAll('tr')[1].ariaRowIndex !== '0') {
|
|
2541
|
+
const cellToFocus = {
|
|
2542
|
+
colIndex: this._focusedCell.colIndex,
|
|
2543
|
+
rowIndex: 1
|
|
2544
|
+
};
|
|
2545
|
+
this._table._focusableGrid.focusCell(cellToFocus);
|
|
2546
|
+
}
|
|
2547
|
+
this._scrollRow(-1);
|
|
2548
|
+
}
|
|
2549
|
+
else if (((_b = this._focusedCell) === null || _b === void 0 ? void 0 : _b.rowIndex) === this._getNumberOfRowsToDisplay() &&
|
|
2550
|
+
KeyUtil.isKeyCode(event, DOWN_ARROW)) {
|
|
2551
|
+
this._scrollRow(1);
|
|
2552
|
+
}
|
|
2553
|
+
}
|
|
2554
|
+
}
|
|
2555
|
+
/** @hidden */
|
|
2556
|
+
ngOnInit() {
|
|
2557
|
+
if (this.scrollWholeRows && !this.virtualScroll) {
|
|
2558
|
+
this.virtualScroll = true;
|
|
2559
|
+
}
|
|
2355
2560
|
}
|
|
2356
2561
|
/** @hidden */
|
|
2357
2562
|
ngOnChanges(changes) {
|
|
@@ -2362,55 +2567,147 @@ class TableVirtualScrollDirective extends TableVirtualScroll {
|
|
|
2362
2567
|
this.calculateVirtualScrollRows();
|
|
2363
2568
|
}
|
|
2364
2569
|
}
|
|
2570
|
+
/** @hidden */
|
|
2571
|
+
ngOnDestroy() {
|
|
2572
|
+
var _a;
|
|
2573
|
+
(_a = this._focusableGridSubscription) === null || _a === void 0 ? void 0 : _a.unsubscribe();
|
|
2574
|
+
}
|
|
2365
2575
|
/** Sets table reference. */
|
|
2366
2576
|
setTable(table) {
|
|
2367
2577
|
this._table = table;
|
|
2368
2578
|
}
|
|
2369
2579
|
/**
|
|
2370
|
-
*
|
|
2580
|
+
* This function determines how many rows can be displayed in the table, and sets the rows in the table based on the
|
|
2581
|
+
* start node index, which may come from the table state
|
|
2371
2582
|
*/
|
|
2372
2583
|
calculateVirtualScrollRows() {
|
|
2373
|
-
if (
|
|
2374
|
-
|
|
2584
|
+
if (this.scrollWholeRows) {
|
|
2585
|
+
if (!this._focusableGridSubscription) {
|
|
2586
|
+
this._focusableGridSubscription = this._table._focusableGrid.itemFocused.subscribe((event) => {
|
|
2587
|
+
this._focusedCell = event;
|
|
2588
|
+
});
|
|
2589
|
+
}
|
|
2590
|
+
if (!this.virtualScroll || !this.bodyHeight) {
|
|
2591
|
+
return;
|
|
2592
|
+
}
|
|
2593
|
+
let startNodeIndex = 0;
|
|
2594
|
+
const scrollTop = this._table.getTableState().scrollTopPosition;
|
|
2595
|
+
if (scrollTop !== 0) {
|
|
2596
|
+
startNodeIndex = Math.floor(scrollTop / this.rowHeight);
|
|
2597
|
+
if (startNodeIndex > this._table._tableRowsVisible.length) {
|
|
2598
|
+
startNodeIndex = 0;
|
|
2599
|
+
}
|
|
2600
|
+
}
|
|
2601
|
+
const totalNodeCount = this._table._tableRowsVisible.length;
|
|
2602
|
+
let visibleNodeCount = Math.floor(this._table.tableContainer.nativeElement.clientHeight / this.rowHeight);
|
|
2603
|
+
visibleNodeCount = Math.min(totalNodeCount - startNodeIndex, visibleNodeCount);
|
|
2604
|
+
this.virtualScrollTotalHeight = totalNodeCount * this.rowHeight - visibleNodeCount * this.rowHeight;
|
|
2605
|
+
this._setRows(startNodeIndex);
|
|
2606
|
+
const scrollMockContainer = this._table.tableScrollMockContainer.nativeElement;
|
|
2607
|
+
scrollMockContainer.style.maxHeight = this.bodyHeight;
|
|
2375
2608
|
}
|
|
2376
|
-
|
|
2377
|
-
|
|
2378
|
-
|
|
2379
|
-
|
|
2380
|
-
|
|
2381
|
-
|
|
2382
|
-
|
|
2383
|
-
|
|
2384
|
-
|
|
2385
|
-
|
|
2386
|
-
|
|
2387
|
-
|
|
2388
|
-
visibleNodeCount
|
|
2389
|
-
|
|
2390
|
-
//
|
|
2391
|
-
startNodeIndex ===
|
|
2392
|
-
|
|
2393
|
-
|
|
2609
|
+
else {
|
|
2610
|
+
if (!this.virtualScroll || !this.bodyHeight) {
|
|
2611
|
+
return;
|
|
2612
|
+
}
|
|
2613
|
+
const rowHeight = this.rowHeight + 1;
|
|
2614
|
+
const rowsVisible = this._table._tableRowsVisible;
|
|
2615
|
+
const rowsInViewPort = this._table.getRowsInViewport();
|
|
2616
|
+
const totalNodeCount = rowsVisible.length;
|
|
2617
|
+
const scrollTop = this._table.tableScrollable.getScrollTop();
|
|
2618
|
+
let startNodeIndex = Math.floor(scrollTop / rowHeight) - this.renderAhead;
|
|
2619
|
+
startNodeIndex = Math.max(0, startNodeIndex);
|
|
2620
|
+
let visibleNodeCount = Math.ceil(this._table.tableContainer.nativeElement.clientHeight / rowHeight) + 2 * this.renderAhead;
|
|
2621
|
+
visibleNodeCount = Math.min(totalNodeCount - startNodeIndex, visibleNodeCount);
|
|
2622
|
+
this.virtualScrollTransform$.next(startNodeIndex * rowHeight);
|
|
2623
|
+
// Simple caching to avoid unnecessary re-renderings
|
|
2624
|
+
const isCached = startNodeIndex === this._virtualScrollCache.startNodeIndex &&
|
|
2625
|
+
visibleNodeCount === this._virtualScrollCache.visibleNodeCount &&
|
|
2626
|
+
totalNodeCount === this._virtualScrollCache.totalNodeCount &&
|
|
2627
|
+
// On rows change, even if the total number of rows is the same, the row object will be different
|
|
2628
|
+
startNodeIndex === rowsInViewPort[0];
|
|
2629
|
+
if (isCached) {
|
|
2630
|
+
return;
|
|
2631
|
+
}
|
|
2632
|
+
this._virtualScrollCache = { startNodeIndex, visibleNodeCount, totalNodeCount };
|
|
2633
|
+
this.virtualScrollTotalHeight = totalNodeCount * rowHeight - visibleNodeCount * rowHeight;
|
|
2634
|
+
this._table.setRowsInViewport(startNodeIndex, rowsVisible.slice(startNodeIndex, startNodeIndex + visibleNodeCount).length);
|
|
2394
2635
|
}
|
|
2395
|
-
this._virtualScrollCache = { startNodeIndex, visibleNodeCount, totalNodeCount };
|
|
2396
|
-
this.virtualScrollTotalHeight = totalNodeCount * rowHeight - visibleNodeCount * rowHeight;
|
|
2397
|
-
this._table.setRowsInViewport(startNodeIndex, rowsVisible.slice(startNodeIndex, startNodeIndex + visibleNodeCount).length);
|
|
2398
2636
|
}
|
|
2399
2637
|
/**
|
|
2400
|
-
*
|
|
2638
|
+
* @hidden
|
|
2639
|
+
* Initialises scroll listeners.
|
|
2401
2640
|
*/
|
|
2402
2641
|
listenOnVirtualScroll() {
|
|
2403
|
-
this.
|
|
2404
|
-
.
|
|
2405
|
-
|
|
2406
|
-
|
|
2407
|
-
this.
|
|
2408
|
-
|
|
2409
|
-
|
|
2642
|
+
if (this.scrollWholeRows) {
|
|
2643
|
+
this._table.tableContainer.nativeElement.addEventListener('wheel', this._wheelScrollListenerFunction, {
|
|
2644
|
+
passive: false
|
|
2645
|
+
});
|
|
2646
|
+
this._table.tableScrollMockContainer.nativeElement.addEventListener('scroll', this._mockScrollbarListenerFunction, { passive: false });
|
|
2647
|
+
}
|
|
2648
|
+
else {
|
|
2649
|
+
this._tableScrollDispatcher
|
|
2650
|
+
.verticallyScrolled()
|
|
2651
|
+
.pipe(filter$1(() => this.virtualScroll && !!this.bodyHeight), takeUntil(this._destroy$))
|
|
2652
|
+
.subscribe((scrollable) => {
|
|
2653
|
+
this.calculateVirtualScrollRows();
|
|
2654
|
+
this._table.setTableState(Object.assign(Object.assign({}, this._table.getTableState()), { scrollTopPosition: scrollable.getScrollTop() }));
|
|
2655
|
+
});
|
|
2656
|
+
}
|
|
2657
|
+
}
|
|
2658
|
+
/** @hidden */
|
|
2659
|
+
_getNumberOfRowsToDisplay() {
|
|
2660
|
+
const tableContainer = this._table.tableContainer.nativeElement;
|
|
2661
|
+
let tableHeight = tableContainer.clientHeight;
|
|
2662
|
+
tableHeight = tableHeight - tableContainer.querySelector('thead').clientHeight;
|
|
2663
|
+
return Math.floor(tableHeight / (this.rowHeight + 2));
|
|
2664
|
+
}
|
|
2665
|
+
/**
|
|
2666
|
+
* @hidden
|
|
2667
|
+
* This function, used only when 'scrollWholeRows' is truthy, calculates what should be the new starting node, based
|
|
2668
|
+
* off the previous starting node and the provided 'count' parameter. For example if the previous start node was 10
|
|
2669
|
+
* and the count parameter is -2, the new starting node will be 8. This function also programmatically moves the
|
|
2670
|
+
* mock scrollbar.
|
|
2671
|
+
*/
|
|
2672
|
+
_scrollRow(count, fromMockScrollbarListener = false) {
|
|
2673
|
+
let startingNode = 0;
|
|
2674
|
+
if (this._previousStartNodeIndex !== null && this._previousStartNodeIndex >= 0) {
|
|
2675
|
+
startingNode = this._previousStartNodeIndex;
|
|
2676
|
+
}
|
|
2677
|
+
if (startingNode + count + this._getNumberOfRowsToDisplay() <= this._table._tableRowsVisible.length ||
|
|
2678
|
+
count < 0) {
|
|
2679
|
+
startingNode = Math.ceil(startingNode + count);
|
|
2680
|
+
}
|
|
2681
|
+
if (startingNode < 0) {
|
|
2682
|
+
startingNode = 0;
|
|
2683
|
+
}
|
|
2684
|
+
// This next 'if' statement is for triggering new page loads when 'pageScrolling' is true
|
|
2685
|
+
if (count > 0 &&
|
|
2686
|
+
startingNode === this._previousStartNodeIndex &&
|
|
2687
|
+
this._table.pageScrolling &&
|
|
2688
|
+
this._table._tableRowsVisible.length === this._table._tableRows.length) {
|
|
2689
|
+
this._table._onSpyIntersect(true);
|
|
2690
|
+
}
|
|
2691
|
+
this._setRows(startingNode);
|
|
2692
|
+
const tableScrollMockContainer = this._table.tableScrollMockContainer.nativeElement;
|
|
2693
|
+
if (!fromMockScrollbarListener) {
|
|
2694
|
+
tableScrollMockContainer.scrollBy({ top: count * this.rowHeight });
|
|
2695
|
+
}
|
|
2696
|
+
this._lastMockScrollPosition = tableScrollMockContainer.scrollTop;
|
|
2697
|
+
}
|
|
2698
|
+
/**
|
|
2699
|
+
* @hidden
|
|
2700
|
+
* This function sets rows in the table's viewport depending on the provided starting node. It also sets the table
|
|
2701
|
+
* state.
|
|
2702
|
+
*/
|
|
2703
|
+
_setRows(startingNode) {
|
|
2704
|
+
this._table.setRowsInViewport(startingNode, this._getNumberOfRowsToDisplay());
|
|
2705
|
+
this._previousStartNodeIndex = startingNode;
|
|
2706
|
+
this._table.setTableState(Object.assign(Object.assign({}, this._table.getTableState()), { scrollTopPosition: this.rowHeight * startingNode }));
|
|
2410
2707
|
}
|
|
2411
2708
|
}
|
|
2412
2709
|
TableVirtualScrollDirective.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.2.9", ngImport: i0, type: TableVirtualScrollDirective, deps: null, target: i0.ɵɵFactoryTarget.Directive });
|
|
2413
|
-
TableVirtualScrollDirective.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "15.2.9", type: TableVirtualScrollDirective, isStandalone: true, selector: "fdp-table[virtualScroll]", inputs: { virtualScroll: "virtualScroll", renderAhead: "renderAhead", bodyHeight: "bodyHeight", rowHeight: "rowHeight" }, providers: [
|
|
2710
|
+
TableVirtualScrollDirective.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "15.2.9", type: TableVirtualScrollDirective, isStandalone: true, selector: "fdp-table[virtualScroll]", inputs: { virtualScroll: "virtualScroll", scrollWholeRows: "scrollWholeRows", renderAhead: "renderAhead", bodyHeight: "bodyHeight", rowHeight: "rowHeight" }, host: { listeners: { "keydown": "_keydownHandler($event)" } }, providers: [
|
|
2414
2711
|
DestroyedService,
|
|
2415
2712
|
{
|
|
2416
2713
|
provide: FDP_TABLE_VIRTUAL_SCROLL_DIRECTIVE,
|
|
@@ -2433,12 +2730,17 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.9", ngImpor
|
|
|
2433
2730
|
}]
|
|
2434
2731
|
}], propDecorators: { virtualScroll: [{
|
|
2435
2732
|
type: Input
|
|
2733
|
+
}], scrollWholeRows: [{
|
|
2734
|
+
type: Input
|
|
2436
2735
|
}], renderAhead: [{
|
|
2437
2736
|
type: Input
|
|
2438
2737
|
}], bodyHeight: [{
|
|
2439
2738
|
type: Input
|
|
2440
2739
|
}], rowHeight: [{
|
|
2441
2740
|
type: Input
|
|
2741
|
+
}], _keydownHandler: [{
|
|
2742
|
+
type: HostListener,
|
|
2743
|
+
args: ['keydown', ['$event']]
|
|
2442
2744
|
}] } });
|
|
2443
2745
|
|
|
2444
2746
|
class TableInitialStateDirective extends TableInitialState {
|
|
@@ -2601,6 +2903,8 @@ class TableColumnResizeService {
|
|
|
2601
2903
|
this._destroyed = new Subject();
|
|
2602
2904
|
/** @hidden */
|
|
2603
2905
|
this._resizerMoveSubscription = new Subscription();
|
|
2906
|
+
/** @hidden */
|
|
2907
|
+
this._initialTableWidth = null;
|
|
2604
2908
|
/** Resize progress stream. */
|
|
2605
2909
|
this.resizeInProgress$ = new BehaviorSubject(this._resizeInProgress);
|
|
2606
2910
|
/** Whether cell mock should be visible. */
|
|
@@ -2663,8 +2967,25 @@ class TableColumnResizeService {
|
|
|
2663
2967
|
}
|
|
2664
2968
|
/** Retrieves custom column value or returns `unset` */
|
|
2665
2969
|
getColumnWidthStyle(columnName) {
|
|
2666
|
-
|
|
2667
|
-
|
|
2970
|
+
var _a, _b;
|
|
2971
|
+
if ((_a = this._tableRef._virtualScrollDirective) === null || _a === void 0 ? void 0 : _a.scrollWholeRows) {
|
|
2972
|
+
if (!this._initialTableWidth) {
|
|
2973
|
+
this._initialTableWidth = this._tableRef._tableWidthPx;
|
|
2974
|
+
}
|
|
2975
|
+
const selectionColumnWidth = (_b = SELECTION_COLUMN_WIDTH.get(this._tableRef.contentDensityObserver.value)) !== null && _b !== void 0 ? _b : 0;
|
|
2976
|
+
let sizeDividedByColumnsCount = this._initialTableWidth / this._tableRef.getVisibleTableColumns().length -
|
|
2977
|
+
selectionColumnWidth / this._tableRef.getVisibleTableColumns().length;
|
|
2978
|
+
// In the event of tables with a very high number of columns, need to prevent the default behavior which
|
|
2979
|
+
// would make each column not wide enough to be usable and instead use a horizontal scrollbar.
|
|
2980
|
+
if (sizeDividedByColumnsCount < 176) {
|
|
2981
|
+
sizeDividedByColumnsCount = 176;
|
|
2982
|
+
}
|
|
2983
|
+
return this._fixedColumnsWidthMap.get(columnName) || sizeDividedByColumnsCount + 'px';
|
|
2984
|
+
}
|
|
2985
|
+
else {
|
|
2986
|
+
const calculatedWidth = this._fixedColumnsWidthMap.get(columnName);
|
|
2987
|
+
return calculatedWidth || 'unset';
|
|
2988
|
+
}
|
|
2668
2989
|
}
|
|
2669
2990
|
/** Previous column name */
|
|
2670
2991
|
getPreviousColumnName(columnName) {
|
|
@@ -2717,7 +3038,6 @@ class TableColumnResizeService {
|
|
|
2717
3038
|
this._resizerPosition = resizerPosition - TABLE_RESIZER_BORDER_WIDTH + scrollLeftOffset;
|
|
2718
3039
|
this.resizerPosition$.next(this.resizerPosition);
|
|
2719
3040
|
}
|
|
2720
|
-
this._markForCheck.next();
|
|
2721
3041
|
}
|
|
2722
3042
|
/** Hide the column resizer. */
|
|
2723
3043
|
hideResizer() {
|
|
@@ -2800,6 +3120,10 @@ class TableColumnResizeService {
|
|
|
2800
3120
|
this._updateHeaderOverflowState(updatedWidth - padding);
|
|
2801
3121
|
this._markForCheck.next();
|
|
2802
3122
|
}
|
|
3123
|
+
/** @hidden */
|
|
3124
|
+
_setInitialTableWidth() {
|
|
3125
|
+
this._initialTableWidth = this._tableRef._tableWidthPx;
|
|
3126
|
+
}
|
|
2803
3127
|
/** Update column resizer position. */
|
|
2804
3128
|
_updateResizerPositionOnMouseMove() {
|
|
2805
3129
|
this._resizerMoveSubscription = fromEvent(document, 'mousemove')
|
|
@@ -2810,7 +3134,6 @@ class TableColumnResizeService {
|
|
|
2810
3134
|
const diffX = this._rtl ? clientStartX - event.clientX : event.clientX - clientStartX;
|
|
2811
3135
|
this._resizerPosition = ((_b = this._startX) !== null && _b !== void 0 ? _b : 0) + diffX;
|
|
2812
3136
|
this.resizerPosition$.next(this.resizerPosition);
|
|
2813
|
-
this._markForCheck.next();
|
|
2814
3137
|
});
|
|
2815
3138
|
}
|
|
2816
3139
|
/**
|
|
@@ -2841,113 +3164,6 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.9", ngImpor
|
|
|
2841
3164
|
}] }];
|
|
2842
3165
|
} });
|
|
2843
3166
|
|
|
2844
|
-
class TableRowService {
|
|
2845
|
-
constructor() {
|
|
2846
|
-
/** @hidden */
|
|
2847
|
-
this._toggleRowSubject = new Subject();
|
|
2848
|
-
/** @hidden */
|
|
2849
|
-
this._scrollToOverlappedCellSubject = new Subject();
|
|
2850
|
-
/** @hidden */
|
|
2851
|
-
this._cellClickedSubject = new Subject();
|
|
2852
|
-
/** @hidden */
|
|
2853
|
-
this._cellFocusedSubject = new Subject();
|
|
2854
|
-
/** @hidden */
|
|
2855
|
-
this._cellActivateSubject = new Subject();
|
|
2856
|
-
/** Stream that emits when the table cell being focused. */
|
|
2857
|
-
this.cellActivate$ = this._cellActivateSubject.asObservable();
|
|
2858
|
-
/** @hidden */
|
|
2859
|
-
this._toggleAllSelectableRowsSubject = new Subject();
|
|
2860
|
-
/** Stream that emits when toggling all selectable rows is needed. */
|
|
2861
|
-
this.toggleAllSelectableRows$ = this._toggleAllSelectableRowsSubject.asObservable();
|
|
2862
|
-
/** Stream that emits when table cell being clicked. */
|
|
2863
|
-
this.cellClicked$ = this._cellClickedSubject.asObservable();
|
|
2864
|
-
/** Stream that emits when scrolling to overlapped cell is needed. */
|
|
2865
|
-
this.scrollToOverlappedCell$ = this._scrollToOverlappedCellSubject.asObservable();
|
|
2866
|
-
/** Stream that emits when the table cell being focused. */
|
|
2867
|
-
this.cellFocused$ = this._cellFocusedSubject.asObservable();
|
|
2868
|
-
/** Toggle row stream. */
|
|
2869
|
-
this.toggleRow$ = this._toggleRowSubject.asObservable();
|
|
2870
|
-
/** Editable cells map. */
|
|
2871
|
-
this.editableCells = new Map();
|
|
2872
|
-
/** @hidden */
|
|
2873
|
-
this.childRowsAdded$ = new Subject();
|
|
2874
|
-
/** Stream to load child items for a particular rows. */
|
|
2875
|
-
this.loadChildRows$ = new Subject();
|
|
2876
|
-
}
|
|
2877
|
-
/** `toggleRow$` stream trigger. */
|
|
2878
|
-
toggleRow(evt) {
|
|
2879
|
-
this._toggleRowSubject.next(evt);
|
|
2880
|
-
}
|
|
2881
|
-
/** `scrollToOverlappedCell$` stream trigger. */
|
|
2882
|
-
scrollToOverlappedCell() {
|
|
2883
|
-
this._scrollToOverlappedCellSubject.next();
|
|
2884
|
-
}
|
|
2885
|
-
/** `cellClicked$` stream trigger. */
|
|
2886
|
-
cellClicked(evt) {
|
|
2887
|
-
this._cellClickedSubject.next(evt);
|
|
2888
|
-
}
|
|
2889
|
-
/** @hidden */
|
|
2890
|
-
cellActivate(columnIndex, row) {
|
|
2891
|
-
this._cellActivateSubject.next({ columnIndex, row: row.value });
|
|
2892
|
-
}
|
|
2893
|
-
/** `cellFocused$` stream trigger. */
|
|
2894
|
-
cellFocused(evt) {
|
|
2895
|
-
this._cellFocusedSubject.next(evt);
|
|
2896
|
-
}
|
|
2897
|
-
/** `toggleAllSelectableRows$` stream trigger. */
|
|
2898
|
-
toggleAllSelectableRows(selectAll) {
|
|
2899
|
-
this._toggleAllSelectableRowsSubject.next(selectAll);
|
|
2900
|
-
}
|
|
2901
|
-
/** Groups the table rows. */
|
|
2902
|
-
groupTableRows(sourceRows, groups, groupRulesMap) {
|
|
2903
|
-
const groupRules = Array.from(groups);
|
|
2904
|
-
if (!groupRules.length) {
|
|
2905
|
-
/**
|
|
2906
|
-
* In case if previously we had groups with collapsed items
|
|
2907
|
-
* but now we don't have it we need to reset row.hidden flag
|
|
2908
|
-
* in order to avoid empty table after groups settings removing
|
|
2909
|
-
*/
|
|
2910
|
-
sourceRows.forEach((row) => {
|
|
2911
|
-
row.hidden = false;
|
|
2912
|
-
});
|
|
2913
|
-
return sourceRows;
|
|
2914
|
-
}
|
|
2915
|
-
// Build tree like groups
|
|
2916
|
-
const treeLikeGroupedRows = createGroupedTableRowsTree(groupRules, sourceRows);
|
|
2917
|
-
// Sort tree like groups
|
|
2918
|
-
const sortedTreeLikeGroupedRows = sortTreeLikeGroupedRows(treeLikeGroupedRows, groupRulesMap);
|
|
2919
|
-
// Convert tree like list to a flat list
|
|
2920
|
-
return convertTreeLikeToFlatList(sortedTreeLikeGroupedRows);
|
|
2921
|
-
}
|
|
2922
|
-
/** Sets editable cells for particular row. */
|
|
2923
|
-
updateEditableCells(row, cells) {
|
|
2924
|
-
this.editableCells.set(row, cells);
|
|
2925
|
-
}
|
|
2926
|
-
/** Removes editable cells of particular row. */
|
|
2927
|
-
removeEditableCells(row) {
|
|
2928
|
-
this.editableCells.delete(row);
|
|
2929
|
-
}
|
|
2930
|
-
/** Triggers stream to load child items for a particular rows. */
|
|
2931
|
-
loadChildRows(rows) {
|
|
2932
|
-
const expandableRows = [];
|
|
2933
|
-
if (Array.isArray(rows)) {
|
|
2934
|
-
expandableRows.push(...rows.filter((r) => !r.childItemsLoading$.value));
|
|
2935
|
-
}
|
|
2936
|
-
else {
|
|
2937
|
-
if (rows.childItemsLoading$.value) {
|
|
2938
|
-
return;
|
|
2939
|
-
}
|
|
2940
|
-
expandableRows.push(rows);
|
|
2941
|
-
}
|
|
2942
|
-
this.loadChildRows$.next(expandableRows);
|
|
2943
|
-
}
|
|
2944
|
-
}
|
|
2945
|
-
TableRowService.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.2.9", ngImport: i0, type: TableRowService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
|
|
2946
|
-
TableRowService.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "15.2.9", ngImport: i0, type: TableRowService });
|
|
2947
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.9", ngImport: i0, type: TableRowService, decorators: [{
|
|
2948
|
-
type: Injectable
|
|
2949
|
-
}] });
|
|
2950
|
-
|
|
2951
3167
|
class TableHeaderResizerDirective {
|
|
2952
3168
|
constructor() {
|
|
2953
3169
|
/** @hidden */
|