@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.
Files changed (42) hide show
  1. package/approval-flow/approval-flow-user-list/approval-flow-user-list.component.d.ts +10 -0
  2. package/esm2020/approval-flow/approval-flow-add-node/approval-flow-add-node.component.mjs +2 -4
  3. package/esm2020/approval-flow/approval-flow-user-list/approval-flow-user-list.component.mjs +50 -14
  4. package/esm2020/form/multi-combobox/multi-combobox/multi-combobox.component.mjs +3 -1
  5. package/esm2020/list/base-list-item.mjs +4 -2
  6. package/esm2020/list/list.component.mjs +12 -2
  7. package/esm2020/table/components/table-row/table-row.component.mjs +4 -3
  8. package/esm2020/table/table.component.mjs +43 -10
  9. package/esm2020/table-helpers/directives/table-virtual-scroll.directive.mjs +241 -37
  10. package/esm2020/table-helpers/models/directives.mjs +1 -1
  11. package/esm2020/table-helpers/services/table-column-resize.service.mjs +26 -5
  12. package/esm2020/table-helpers/table.mjs +1 -1
  13. package/fesm2015/fundamental-ngx-platform-approval-flow.mjs +52 -20
  14. package/fesm2015/fundamental-ngx-platform-approval-flow.mjs.map +1 -1
  15. package/fesm2015/fundamental-ngx-platform-form.mjs +2 -0
  16. package/fesm2015/fundamental-ngx-platform-form.mjs.map +1 -1
  17. package/fesm2015/fundamental-ngx-platform-list.mjs +15 -2
  18. package/fesm2015/fundamental-ngx-platform-list.mjs.map +1 -1
  19. package/fesm2015/fundamental-ngx-platform-table-helpers.mjs +369 -147
  20. package/fesm2015/fundamental-ngx-platform-table-helpers.mjs.map +1 -1
  21. package/fesm2015/fundamental-ngx-platform-table.mjs +165 -131
  22. package/fesm2015/fundamental-ngx-platform-table.mjs.map +1 -1
  23. package/fesm2020/fundamental-ngx-platform-approval-flow.mjs +50 -18
  24. package/fesm2020/fundamental-ngx-platform-approval-flow.mjs.map +1 -1
  25. package/fesm2020/fundamental-ngx-platform-form.mjs +2 -0
  26. package/fesm2020/fundamental-ngx-platform-form.mjs.map +1 -1
  27. package/fesm2020/fundamental-ngx-platform-list.mjs +14 -2
  28. package/fesm2020/fundamental-ngx-platform-list.mjs.map +1 -1
  29. package/fesm2020/fundamental-ngx-platform-table-helpers.mjs +370 -148
  30. package/fesm2020/fundamental-ngx-platform-table-helpers.mjs.map +1 -1
  31. package/fesm2020/fundamental-ngx-platform-table.mjs +164 -131
  32. package/fesm2020/fundamental-ngx-platform-table.mjs.map +1 -1
  33. package/fundamental-ngx-platform-v0.43.38.tgz +0 -0
  34. package/list/list.component.d.ts +6 -0
  35. package/package.json +4 -4
  36. package/schematics/ng-add/index.js +1 -1
  37. package/table/table.component.d.ts +9 -0
  38. package/table-helpers/directives/table-virtual-scroll.directive.d.ts +64 -5
  39. package/table-helpers/models/directives.d.ts +1 -0
  40. package/table-helpers/services/table-column-resize.service.d.ts +4 -0
  41. package/table-helpers/table.d.ts +10 -2
  42. 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, RtlService, KeyUtil, resizeObservable, FDK_FOCUSABLE_ITEM_DIRECTIVE, FocusableItemDirective } from '@fundamental-ngx/cdk/utils';
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
- * Calculates rows in viewport.
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 (!this.virtualScroll || !this.bodyHeight) {
2374
- return;
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
- const rowHeight = this.rowHeight + 1;
2377
- const rowsVisible = this._table._tableRowsVisible;
2378
- const rowsInViewPort = this._table.getRowsInViewport();
2379
- const totalNodeCount = rowsVisible.length;
2380
- const scrollTop = this._table.tableScrollable.getScrollTop();
2381
- let startNodeIndex = Math.floor(scrollTop / rowHeight) - this.renderAhead;
2382
- startNodeIndex = Math.max(0, startNodeIndex);
2383
- let visibleNodeCount = Math.ceil(this._table.tableContainer.nativeElement.clientHeight / rowHeight) + 2 * this.renderAhead;
2384
- visibleNodeCount = Math.min(totalNodeCount - startNodeIndex, visibleNodeCount);
2385
- this.virtualScrollTransform$.next(startNodeIndex * rowHeight);
2386
- // Simple caching to avoid unnecessary re-renderings
2387
- const isCached = startNodeIndex === this._virtualScrollCache.startNodeIndex &&
2388
- visibleNodeCount === this._virtualScrollCache.visibleNodeCount &&
2389
- totalNodeCount === this._virtualScrollCache.totalNodeCount &&
2390
- // On rows change, even if the total number of rows is the same, the row object will be different
2391
- startNodeIndex === rowsInViewPort[0];
2392
- if (isCached) {
2393
- return;
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
- * Initialises scroll listener.
2638
+ * @hidden
2639
+ * Initialises scroll listeners.
2401
2640
  */
2402
2641
  listenOnVirtualScroll() {
2403
- this._tableScrollDispatcher
2404
- .verticallyScrolled()
2405
- .pipe(filter$1(() => this.virtualScroll && !!this.bodyHeight), takeUntil(this._destroy$))
2406
- .subscribe((scrollable) => {
2407
- this.calculateVirtualScrollRows();
2408
- this._table.setTableState(Object.assign(Object.assign({}, this._table.getTableState()), { scrollTopPosition: scrollable.getScrollTop() }));
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
- const calculatedWidth = this._fixedColumnsWidthMap.get(columnName);
2667
- return calculatedWidth || 'unset';
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 */