@fundamental-ngx/platform 0.43.36 → 0.43.38
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/approval-flow/approval-flow-user-list/approval-flow-user-list.component.d.ts +10 -0
- package/esm2020/approval-flow/approval-flow-add-node/approval-flow-add-node.component.mjs +2 -4
- package/esm2020/approval-flow/approval-flow-user-list/approval-flow-user-list.component.mjs +50 -14
- package/esm2020/form/multi-combobox/multi-combobox/multi-combobox.component.mjs +3 -1
- package/esm2020/list/base-list-item.mjs +4 -2
- package/esm2020/list/list.component.mjs +12 -2
- package/esm2020/table/components/table-row/table-row.component.mjs +4 -3
- package/esm2020/table/table.component.mjs +43 -10
- package/esm2020/table-helpers/directives/table-virtual-scroll.directive.mjs +241 -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-approval-flow.mjs +52 -20
- package/fesm2015/fundamental-ngx-platform-approval-flow.mjs.map +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-list.mjs +15 -2
- package/fesm2015/fundamental-ngx-platform-list.mjs.map +1 -1
- package/fesm2015/fundamental-ngx-platform-table-helpers.mjs +369 -147
- package/fesm2015/fundamental-ngx-platform-table-helpers.mjs.map +1 -1
- package/fesm2015/fundamental-ngx-platform-table.mjs +165 -131
- package/fesm2015/fundamental-ngx-platform-table.mjs.map +1 -1
- package/fesm2020/fundamental-ngx-platform-approval-flow.mjs +50 -18
- package/fesm2020/fundamental-ngx-platform-approval-flow.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-list.mjs +14 -2
- package/fesm2020/fundamental-ngx-platform-list.mjs.map +1 -1
- package/fesm2020/fundamental-ngx-platform-table-helpers.mjs +370 -148
- package/fesm2020/fundamental-ngx-platform-table-helpers.mjs.map +1 -1
- package/fesm2020/fundamental-ngx-platform-table.mjs +164 -131
- package/fesm2020/fundamental-ngx-platform-table.mjs.map +1 -1
- package/fundamental-ngx-platform-v0.43.38.tgz +0 -0
- package/list/list.component.d.ts +6 -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.36.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,153 @@ 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
|
+
const numberOfRows = Math.floor(tableHeight / (this.rowHeight + 2));
|
|
2664
|
+
if (this._table._tableRowsVisible.length < numberOfRows) {
|
|
2665
|
+
return this._table._tableRowsVisible.length;
|
|
2666
|
+
}
|
|
2667
|
+
else {
|
|
2668
|
+
return numberOfRows;
|
|
2669
|
+
}
|
|
2670
|
+
}
|
|
2671
|
+
/**
|
|
2672
|
+
* @hidden
|
|
2673
|
+
* This function, used only when 'scrollWholeRows' is truthy, calculates what should be the new starting node, based
|
|
2674
|
+
* off the previous starting node and the provided 'count' parameter. For example if the previous start node was 10
|
|
2675
|
+
* and the count parameter is -2, the new starting node will be 8. This function also programmatically moves the
|
|
2676
|
+
* mock scrollbar.
|
|
2677
|
+
*/
|
|
2678
|
+
_scrollRow(count, fromMockScrollbarListener = false) {
|
|
2679
|
+
let startingNode = 0;
|
|
2680
|
+
if (this._previousStartNodeIndex !== null && this._previousStartNodeIndex >= 0) {
|
|
2681
|
+
startingNode = this._previousStartNodeIndex;
|
|
2682
|
+
}
|
|
2683
|
+
if (startingNode + count + this._getNumberOfRowsToDisplay() <= this._table._tableRowsVisible.length ||
|
|
2684
|
+
count < 0) {
|
|
2685
|
+
startingNode = Math.ceil(startingNode + count);
|
|
2686
|
+
}
|
|
2687
|
+
if (startingNode < 0) {
|
|
2688
|
+
startingNode = 0;
|
|
2689
|
+
}
|
|
2690
|
+
// This next 'if' statement is for triggering new page loads when 'pageScrolling' is true
|
|
2691
|
+
if (count > 0 &&
|
|
2692
|
+
startingNode === this._previousStartNodeIndex &&
|
|
2693
|
+
this._table.pageScrolling &&
|
|
2694
|
+
this._table._tableRowsVisible.length === this._table._tableRows.length) {
|
|
2695
|
+
this._table._onSpyIntersect(true);
|
|
2696
|
+
}
|
|
2697
|
+
this._setRows(startingNode);
|
|
2698
|
+
const tableScrollMockContainer = this._table.tableScrollMockContainer.nativeElement;
|
|
2699
|
+
if (!fromMockScrollbarListener) {
|
|
2700
|
+
tableScrollMockContainer.scrollBy({ top: count * this.rowHeight });
|
|
2701
|
+
}
|
|
2702
|
+
this._lastMockScrollPosition = tableScrollMockContainer.scrollTop;
|
|
2703
|
+
}
|
|
2704
|
+
/**
|
|
2705
|
+
* @hidden
|
|
2706
|
+
* This function sets rows in the table's viewport depending on the provided starting node. It also sets the table
|
|
2707
|
+
* state.
|
|
2708
|
+
*/
|
|
2709
|
+
_setRows(startingNode) {
|
|
2710
|
+
this._table.setRowsInViewport(startingNode, this._getNumberOfRowsToDisplay());
|
|
2711
|
+
this._previousStartNodeIndex = startingNode;
|
|
2712
|
+
this._table.setTableState(Object.assign(Object.assign({}, this._table.getTableState()), { scrollTopPosition: this.rowHeight * startingNode }));
|
|
2410
2713
|
}
|
|
2411
2714
|
}
|
|
2412
2715
|
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: [
|
|
2716
|
+
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
2717
|
DestroyedService,
|
|
2415
2718
|
{
|
|
2416
2719
|
provide: FDP_TABLE_VIRTUAL_SCROLL_DIRECTIVE,
|
|
@@ -2433,12 +2736,17 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.9", ngImpor
|
|
|
2433
2736
|
}]
|
|
2434
2737
|
}], propDecorators: { virtualScroll: [{
|
|
2435
2738
|
type: Input
|
|
2739
|
+
}], scrollWholeRows: [{
|
|
2740
|
+
type: Input
|
|
2436
2741
|
}], renderAhead: [{
|
|
2437
2742
|
type: Input
|
|
2438
2743
|
}], bodyHeight: [{
|
|
2439
2744
|
type: Input
|
|
2440
2745
|
}], rowHeight: [{
|
|
2441
2746
|
type: Input
|
|
2747
|
+
}], _keydownHandler: [{
|
|
2748
|
+
type: HostListener,
|
|
2749
|
+
args: ['keydown', ['$event']]
|
|
2442
2750
|
}] } });
|
|
2443
2751
|
|
|
2444
2752
|
class TableInitialStateDirective extends TableInitialState {
|
|
@@ -2601,6 +2909,8 @@ class TableColumnResizeService {
|
|
|
2601
2909
|
this._destroyed = new Subject();
|
|
2602
2910
|
/** @hidden */
|
|
2603
2911
|
this._resizerMoveSubscription = new Subscription();
|
|
2912
|
+
/** @hidden */
|
|
2913
|
+
this._initialTableWidth = null;
|
|
2604
2914
|
/** Resize progress stream. */
|
|
2605
2915
|
this.resizeInProgress$ = new BehaviorSubject(this._resizeInProgress);
|
|
2606
2916
|
/** Whether cell mock should be visible. */
|
|
@@ -2663,8 +2973,25 @@ class TableColumnResizeService {
|
|
|
2663
2973
|
}
|
|
2664
2974
|
/** Retrieves custom column value or returns `unset` */
|
|
2665
2975
|
getColumnWidthStyle(columnName) {
|
|
2666
|
-
|
|
2667
|
-
|
|
2976
|
+
var _a, _b;
|
|
2977
|
+
if ((_a = this._tableRef._virtualScrollDirective) === null || _a === void 0 ? void 0 : _a.scrollWholeRows) {
|
|
2978
|
+
if (!this._initialTableWidth) {
|
|
2979
|
+
this._initialTableWidth = this._tableRef._tableWidthPx;
|
|
2980
|
+
}
|
|
2981
|
+
const selectionColumnWidth = (_b = SELECTION_COLUMN_WIDTH.get(this._tableRef.contentDensityObserver.value)) !== null && _b !== void 0 ? _b : 0;
|
|
2982
|
+
let sizeDividedByColumnsCount = this._initialTableWidth / this._tableRef.getVisibleTableColumns().length -
|
|
2983
|
+
selectionColumnWidth / this._tableRef.getVisibleTableColumns().length;
|
|
2984
|
+
// In the event of tables with a very high number of columns, need to prevent the default behavior which
|
|
2985
|
+
// would make each column not wide enough to be usable and instead use a horizontal scrollbar.
|
|
2986
|
+
if (sizeDividedByColumnsCount < 176) {
|
|
2987
|
+
sizeDividedByColumnsCount = 176;
|
|
2988
|
+
}
|
|
2989
|
+
return this._fixedColumnsWidthMap.get(columnName) || sizeDividedByColumnsCount + 'px';
|
|
2990
|
+
}
|
|
2991
|
+
else {
|
|
2992
|
+
const calculatedWidth = this._fixedColumnsWidthMap.get(columnName);
|
|
2993
|
+
return calculatedWidth || 'unset';
|
|
2994
|
+
}
|
|
2668
2995
|
}
|
|
2669
2996
|
/** Previous column name */
|
|
2670
2997
|
getPreviousColumnName(columnName) {
|
|
@@ -2717,7 +3044,6 @@ class TableColumnResizeService {
|
|
|
2717
3044
|
this._resizerPosition = resizerPosition - TABLE_RESIZER_BORDER_WIDTH + scrollLeftOffset;
|
|
2718
3045
|
this.resizerPosition$.next(this.resizerPosition);
|
|
2719
3046
|
}
|
|
2720
|
-
this._markForCheck.next();
|
|
2721
3047
|
}
|
|
2722
3048
|
/** Hide the column resizer. */
|
|
2723
3049
|
hideResizer() {
|
|
@@ -2800,6 +3126,10 @@ class TableColumnResizeService {
|
|
|
2800
3126
|
this._updateHeaderOverflowState(updatedWidth - padding);
|
|
2801
3127
|
this._markForCheck.next();
|
|
2802
3128
|
}
|
|
3129
|
+
/** @hidden */
|
|
3130
|
+
_setInitialTableWidth() {
|
|
3131
|
+
this._initialTableWidth = this._tableRef._tableWidthPx;
|
|
3132
|
+
}
|
|
2803
3133
|
/** Update column resizer position. */
|
|
2804
3134
|
_updateResizerPositionOnMouseMove() {
|
|
2805
3135
|
this._resizerMoveSubscription = fromEvent(document, 'mousemove')
|
|
@@ -2810,7 +3140,6 @@ class TableColumnResizeService {
|
|
|
2810
3140
|
const diffX = this._rtl ? clientStartX - event.clientX : event.clientX - clientStartX;
|
|
2811
3141
|
this._resizerPosition = ((_b = this._startX) !== null && _b !== void 0 ? _b : 0) + diffX;
|
|
2812
3142
|
this.resizerPosition$.next(this.resizerPosition);
|
|
2813
|
-
this._markForCheck.next();
|
|
2814
3143
|
});
|
|
2815
3144
|
}
|
|
2816
3145
|
/**
|
|
@@ -2841,113 +3170,6 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.9", ngImpor
|
|
|
2841
3170
|
}] }];
|
|
2842
3171
|
} });
|
|
2843
3172
|
|
|
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
3173
|
class TableHeaderResizerDirective {
|
|
2952
3174
|
constructor() {
|
|
2953
3175
|
/** @hidden */
|