UNPKG

ngx-gem-spaas

Version:

This library contains services, components, images and styles to provide a unified look and way-of-working throughout GEM SPaaS.

1 lines 66.9 kB
{"version":3,"file":"ngx-gem-spaas-table.mjs","sources":["../../../projects/ngx-gem-spaas/table/src/_directives/table-selection-free.directive.ts","../../../projects/ngx-gem-spaas/table/src/_directives/table-header.directive.ts","../../../projects/ngx-gem-spaas/table/src/_directives/table-cell.directive.ts","../../../projects/ngx-gem-spaas/table/src/table/table.component.ts","../../../projects/ngx-gem-spaas/table/src/table/table.component.html","../../../projects/ngx-gem-spaas/table/src/_directives/table-selection-row.directive.ts","../../../projects/ngx-gem-spaas/table/src/_models/table-column.model.ts","../../../projects/ngx-gem-spaas/table/src/table-filter/table-filter.component.ts","../../../projects/ngx-gem-spaas/table/src/table-filter/table-filter.component.html","../../../projects/ngx-gem-spaas/table/src/table.module.ts","../../../projects/ngx-gem-spaas/table/src/public-api.ts","../../../projects/ngx-gem-spaas/table/src/ngx-gem-spaas-table.ts"],"sourcesContent":["import {Directive, EventEmitter, HostListener, Input, OnDestroy, Output} from '@angular/core';\r\nimport {Subject} from 'rxjs';\r\n\r\n@Directive({\r\n selector: '[spaasTableSelectionFree]',\r\n exportAs: 'spaasTableSelectionFree'\r\n})\r\nexport class TableSelectionFreeDirective implements OnDestroy {\r\n\r\n @Input() freeSelectionMatrix: number[][] = [];\r\n @Input() freeSelectionLockAxis: '' | 'x' | 'y' = '';\r\n\r\n @Output() selectionChanged = new EventEmitter<{ row: number, column: number }>(); // will emit the last selected row and column\r\n\r\n isSelecting = false;\r\n private selectionId = 1;\r\n\r\n // set the from/to variables to public because it's very handy to be able to access these directly in the template\r\n fromCol = 0;\r\n fromRow = 0;\r\n toCol: number = 0;\r\n toRow: number = 0;\r\n\r\n private onDestroy = new Subject<void>();\r\n\r\n @HostListener('mousedown', ['$event'])\r\n mouseDown(e: MouseEvent) {\r\n const mouseData = this.checkMouseData(e);\r\n if (mouseData.valid) {\r\n this.onClickCell(e, mouseData.rowIdx, mouseData.colIdx);\r\n }\r\n }\r\n\r\n @HostListener('mousemove', ['$event'])\r\n mouseMove(e: MouseEvent) {\r\n const mouseData = this.checkMouseData(e);\r\n if (\r\n this.isSelecting &&\r\n mouseData.valid &&\r\n (mouseData.rowIdx !== this.toRow || mouseData.colIdx !== this.toCol)\r\n ) {\r\n this.onSelecting(mouseData.rowIdx, mouseData.colIdx);\r\n }\r\n }\r\n\r\n @HostListener('mouseup', ['$event'])\r\n mouseUp() {\r\n this.onStopSelect('mouseup');\r\n }\r\n\r\n @HostListener('mouseleave', ['$event'])\r\n mouseLeave() {\r\n this.onStopSelect('mouseleave');\r\n }\r\n\r\n @HostListener('tableSortedOrFiltered', ['$event'])\r\n sort() {\r\n this.resetSelectionRange(true, true);\r\n this.emitNewSelection();\r\n }\r\n\r\n ngOnDestroy() {\r\n this.onDestroy.next();\r\n this.onDestroy.complete();\r\n }\r\n\r\n private checkMouseData(e: MouseEvent): { valid: boolean, rowIdx: number, colIdx: number } {\r\n const target = (e.target) as HTMLElement;\r\n let dataset: any = target?.dataset;\r\n if (!dataset?.rowIdx) {\r\n // also check the offsetParent, for cells with sub-divs\r\n dataset = ((target?.offsetParent) as HTMLElement).dataset;\r\n }\r\n let rowIdx = -1, colIdx = -1;\r\n if (dataset?.rowIdx && dataset.colIdx) {\r\n rowIdx = Number.isNaN((Number(dataset.rowIdx))) ? -1 : Number(dataset.rowIdx);\r\n colIdx = Number.isNaN((Number(dataset.colIdx))) ? -1 : Number(dataset.colIdx);\r\n }\r\n return {\r\n valid: rowIdx > -1 && colIdx > -1,\r\n rowIdx: rowIdx,\r\n colIdx: colIdx\r\n };\r\n }\r\n\r\n private onClickCell(e: MouseEvent, rowIdx: number, colIdx: number): void {\r\n if (!e) {\r\n return;\r\n }\r\n this.isSelecting = true;\r\n if (!e.shiftKey && !e.ctrlKey) {\r\n // normal click: update all selection variables\r\n ++this.selectionId;\r\n this.fromRow = rowIdx;\r\n this.fromCol = colIdx;\r\n this.toRow = rowIdx;\r\n this.toCol = colIdx;\r\n this.resetSelectionRange(true);\r\n } else if (e.shiftKey) {\r\n // shift click: set last variables for range selection\r\n document.getSelection()?.removeAllRanges();\r\n this.setTo(rowIdx, colIdx);\r\n this.updateSelectionRange();\r\n } else if (e.ctrlKey) {\r\n // ctrl-click in non-origin row/col and lock-axis is active: reset all (considered a regular click in this case)\r\n if (\r\n (this.freeSelectionLockAxis === 'x' && rowIdx !== this.fromRow) ||\r\n (this.freeSelectionLockAxis === 'y' && colIdx !== this.fromCol)\r\n ) {\r\n this.resetSelectionRange(true);\r\n }\r\n // ctrl key: just set for cell itself\r\n ++this.selectionId;\r\n this.freeSelectionMatrix[rowIdx][colIdx] = !this.freeSelectionMatrix[rowIdx][colIdx] ? this.selectionId : 0;\r\n if (this.freeSelectionMatrix[rowIdx][colIdx]) {\r\n this.fromRow = rowIdx;\r\n this.fromCol = colIdx;\r\n this.setTo(rowIdx, colIdx);\r\n } else {\r\n // it's a deselection: search for last selected cell to put focus on\r\n for (let row = 0; row < this.freeSelectionMatrix.length; row++) {\r\n for (let col = 0; col < this.freeSelectionMatrix[row].length; col++) {\r\n if (this.freeSelectionMatrix[row][col]) {\r\n this.toRow = row;\r\n this.toCol = col;\r\n }\r\n }\r\n }\r\n }\r\n }\r\n }\r\n\r\n private onSelecting(rowIdx: number, colIdx: number): void {\r\n if (this.isSelecting) {\r\n document.getSelection()?.removeAllRanges();\r\n this.setTo(rowIdx, colIdx);\r\n this.resetSelectionRange();\r\n this.updateSelectionRange();\r\n }\r\n }\r\n\r\n private onStopSelect(fromMouseEvent: 'mouseup' | 'mouseleave'): void {\r\n if (this.isSelecting) {\r\n this.isSelecting = false;\r\n if (fromMouseEvent === 'mouseup') {\r\n this.emitNewSelection();\r\n }\r\n }\r\n }\r\n\r\n private emitNewSelection(): void {\r\n this.selectionChanged.emit(\r\n this.freeSelectionMatrix[this.toRow][this.toCol] > 0 ?\r\n {row: this.toRow, column: this.toCol} :\r\n {row: -1, column: -1}\r\n );\r\n }\r\n\r\n private setTo(rowIdx: number, colIdx: number): void {\r\n this.toRow = this.freeSelectionLockAxis === 'x' ? this.fromRow : rowIdx;\r\n this.toCol = this.freeSelectionLockAxis === 'y' ? this.fromCol : colIdx;\r\n }\r\n\r\n private resetSelectionRange(fullReset = false, fromSort = false): void {\r\n const wasSelected = this.freeSelectionMatrix[this.toRow][this.toCol] > 0;\r\n for (let rowIdx = 0; rowIdx < this.freeSelectionMatrix.length; rowIdx++) {\r\n for (let colIdx = 0; colIdx < this.freeSelectionMatrix[rowIdx].length; colIdx++) {\r\n if (fullReset || this.freeSelectionMatrix[rowIdx][colIdx] === this.selectionId) {\r\n this.freeSelectionMatrix[rowIdx][colIdx] = 0;\r\n }\r\n }\r\n }\r\n this.freeSelectionMatrix[this.toRow][this.toCol] = fromSort || wasSelected ? 0 : this.selectionId;\r\n }\r\n\r\n private updateSelectionRange(): void {\r\n const fromRow = Math.min(this.fromRow, this.toRow);\r\n const toRow = Math.max(this.fromRow, this.toRow);\r\n const fromCol = Math.min(this.fromCol, this.toCol);\r\n const toCol = Math.max(this.fromCol, this.toCol);\r\n for (let rowIdx = fromRow; rowIdx <= toRow; rowIdx++) {\r\n for (let colIdx = fromCol; colIdx <= toCol; colIdx++) {\r\n this.freeSelectionMatrix[rowIdx][colIdx] = this.selectionId;\r\n }\r\n }\r\n }\r\n\r\n}\r\n","import {Directive, Input, TemplateRef} from '@angular/core';\r\n\r\n@Directive({\r\n selector: '[spaasTableHeader]',\r\n exportAs: 'spaasTableHeader'\r\n})\r\nexport class TableHeaderDirective {\r\n\r\n @Input() spaasTableHeader: string = '';\r\n\r\n constructor(\r\n public templateRef: TemplateRef<any>,\r\n ) {\r\n }\r\n\r\n\r\n}\r\n","import {Directive, Input, TemplateRef} from '@angular/core';\r\n\r\n@Directive({\r\n selector: '[spaasTableCell]',\r\n exportAs: 'spaasTableCell'\r\n})\r\nexport class TableCellDirective {\r\n\r\n @Input() spaasTableCell: string = '';\r\n\r\n constructor(\r\n public templateRef: TemplateRef<any>,\r\n ) {\r\n }\r\n\r\n\r\n}\r\n","import {\r\n AfterContentInit,\r\n Component,\r\n ContentChildren,\r\n EventEmitter,\r\n Input,\r\n OnChanges,\r\n OnInit,\r\n Output,\r\n QueryList,\r\n SimpleChanges,\r\n ViewChild\r\n} from '@angular/core';\r\nimport {debounceTime, Subject} from \"rxjs\";\r\nimport {CdkVirtualScrollViewport} from \"@angular/cdk/scrolling\";\r\nimport {Sort} from '@angular/material/sort';\r\nimport {TableColumnModel} from \"../_models/table-column.model\";\r\nimport {TableHeaderDirective} from \"../_directives/table-header.directive\";\r\nimport {TableCellDirective} from \"../_directives/table-cell.directive\";\r\nimport {BaseComponent} from \"ngx-gem-spaas\";\r\nimport {TableFilterComponent} from \"../table-filter/table-filter.component\";\r\nimport {takeUntil} from \"rxjs/operators\";\r\n\r\n@Component({\r\n selector: 'spaas-table',\r\n templateUrl: './table.component.html',\r\n styleUrls: ['./table.component.scss']\r\n})\r\nexport class TableComponent extends BaseComponent implements OnInit, AfterContentInit, OnChanges {\r\n\r\n @Input({required: true}) tableData: any[] = [];\r\n @Input({required: true}) columns: TableColumnModel[] = [];\r\n @Input() columnMaxWidth: number = 214;\r\n\r\n @Input() freeSelectionMatrix: number[][] | null = null;\r\n @Input() rowSelectionMatrix: number[] | null = null;\r\n\r\n @Input() orientation: 'horizontal' | 'vertical' = 'vertical';\r\n @Input() showToTop = false;\r\n @Input() withSort: boolean = true;\r\n\r\n @Input() filter: TableFilterComponent | null = null;\r\n\r\n @Input() align: 'left' | 'right' | '' = '';\r\n\r\n // do not just change the name of this emitter. Selection directives listen to it.\r\n @Output() tableSortedOrFiltered = new EventEmitter<number>();\r\n\r\n @ViewChild('vScroller') vScroller: CdkVirtualScrollViewport | null = null;\r\n\r\n @ContentChildren(TableHeaderDirective) headerTemplates!: QueryList<TableHeaderDirective>;\r\n @ContentChildren(TableCellDirective) cellTemplates!: QueryList<TableCellDirective>;\r\n\r\n // these shallow copies are necessary because we want to keep the reference to the parent tableData\r\n // aka, we want the parent tableData to also get sorted and filtered\r\n origData: any[] = []; // a shallow copy for the original order\r\n domData: any[] = []; // a shallow copy for the DOM rendering (without this copying, the changeDetection would not fire on sort)\r\n\r\n toTopActive = false;\r\n private scrolling$ = new Subject<void>();\r\n\r\n private activeSort: Sort | null = null;\r\n\r\n private static compare(a: number | string, b: number | string, isAsc: boolean): number {\r\n const conv = isAsc ? 1 : -1;\r\n if (typeof a === 'string' && typeof b === 'string') {\r\n return ((a || '').toLowerCase() < (b || '').toLowerCase() ? -1 : 1) * conv;\r\n }\r\n return ((a || '') < (b || '') ? -1 : 1) * conv;\r\n }\r\n\r\n ngOnInit() {\r\n if (this.showToTop) {\r\n this.checkToTop();\r\n }\r\n if (this.filter) {\r\n this.filter.filterChanged\r\n .pipe(\r\n takeUntil(this.onDestroy$)\r\n )\r\n .subscribe(() => {\r\n this.sortAndFilter();\r\n })\r\n }\r\n }\r\n\r\n ngAfterContentInit() {\r\n for (const col of this.columns) {\r\n // set optional booleans that should be true by default\r\n if (!col.hasOwnProperty('withSort')) {\r\n col.withSort = true;\r\n }\r\n // then set the templates, if any provided\r\n const headerTemplate = this.headerTemplates.find((h) => h.spaasTableHeader === col.dataField);\r\n if (headerTemplate) {\r\n col.headerTemplate = headerTemplate.templateRef;\r\n }\r\n const cellTemplate = this.cellTemplates.find((h) => h.spaasTableCell === col.dataField);\r\n if (cellTemplate) {\r\n col.cellTemplate = cellTemplate.templateRef;\r\n }\r\n }\r\n }\r\n\r\n ngOnChanges(changes: SimpleChanges) {\r\n if (changes.hasOwnProperty('tableData')) {\r\n this.origData = this.tableData.slice();\r\n this.sortAndFilter();\r\n }\r\n }\r\n\r\n override ngOnDestroy(): void {\r\n this.resetTableData();\r\n super.ngOnDestroy();\r\n }\r\n\r\n onScroll(): void {\r\n this.scrolling$.next();\r\n }\r\n\r\n private checkToTop(): void {\r\n this.scrolling$\r\n .pipe(debounceTime(400))\r\n .subscribe(() => {\r\n if (this.vScroller) {\r\n this.toTopActive = (this.vScroller.getOffsetToRenderedContentStart() || 0) > 400;\r\n }\r\n })\r\n }\r\n\r\n onGoToTop(): void {\r\n if (this.vScroller) {\r\n this.vScroller.scrollToOffset(0);\r\n }\r\n }\r\n\r\n onSort(matSort: Sort | null): void {\r\n this.activeSort = matSort;\r\n this.sortAndFilter();\r\n }\r\n\r\n private sortAndFilter(): void {\r\n // first always reset to avoid strange sorting behaviour\r\n this.resetTableData();\r\n // first filter\r\n if (this.filter?.filterString) {\r\n // filter tableData itself, so the parent data is also filtered (necessary for selection)\r\n const func = this.createFilterFunction(this.filter.filterString);\r\n for (let rowIdx = 0; rowIdx < this.tableData.length; rowIdx++) {\r\n if (!(func(this.tableData[rowIdx]))) {\r\n this.tableData.splice(rowIdx, 1);\r\n rowIdx--;\r\n }\r\n }\r\n }\r\n // then sort\r\n if (this.activeSort?.active && this.activeSort?.direction) {\r\n // sort tableData itself, so the parent data is also sorted (necessary for selection)\r\n const isAsc = this.activeSort.direction === 'asc';\r\n this.tableData.sort((a, b) => {\r\n return TableComponent.compare(a[this.activeSort?.active || ''], b[this.activeSort?.active || ''], isAsc);\r\n });\r\n }\r\n this.updateDomData();\r\n this.onGoToTop();\r\n };\r\n\r\n private createFilterFunction(funcBody: string): Function {\r\n return Function.call(\r\n this,\r\n 'e',\r\n 'return ' + funcBody + ';'\r\n );\r\n }\r\n\r\n private resetTableData(): void {\r\n // reset tableData to the origData order, without breaking reference with the parent data\r\n this.tableData.length = 0;\r\n this.tableData.push(...this.origData);\r\n }\r\n\r\n private updateDomData(): void {\r\n this.domData = this.tableData.slice();\r\n // only emit when there is actual data...\r\n // else it's not a real sort or filter (can't change anything to non-existing data)\r\n if (this.origData?.length) {\r\n // wrap it in setTimeout to avoid \"expression has changed after it was checked\" errors that might occur if\r\n // the parent component is displaying the number of rows in the data (new js VM turn invoked)\r\n setTimeout(() => {\r\n this.tableSortedOrFiltered.emit(this.domData.length);\r\n })\r\n }\r\n }\r\n\r\n}\r\n","<div class=\"spaas-table pos-relative\">\r\n\r\n @if (orientation === 'vertical') {\r\n <div (matSortChange)=\"onSort($event)\"\r\n (scroll)=\"onScroll()\"\r\n [matSortDisabled]=\"!withSort\"\r\n cdkVirtualScrollingElement\r\n class=\"flextable by-row striped flex col {{align}}\"\r\n matSort>\r\n <!-- header row -->\r\n <div class=\"row header pos-sticky-vertical\">\r\n @for (column of columns; track column) {\r\n <div [disabled]=\"!column.withSort\"\r\n [mat-sort-header]=\"column.dataField\"\r\n class=\"cell {{column.cssClasses}}\">\r\n <ng-container [ngTemplateOutlet]=\"column.headerTemplate || NoVertHeaderTemplate\">\r\n </ng-container>\r\n <ng-template #NoVertHeaderTemplate>\r\n {{ column.columnLabel || column.dataField }}\r\n </ng-template>\r\n </div>\r\n }\r\n </div>\r\n <!-- virtual scroller with data rows -->\r\n <cdk-virtual-scroll-viewport #vScroller itemSize=\"36\">\r\n <div *cdkVirtualFor=\"let row of domData; let rowIdx = index\"\r\n [class.selected]=\"rowSelectionMatrix?.[rowIdx]\"\r\n class=\"row\">\r\n @for (column of columns; track column; let colIdx = $index) {\r\n <div [attr.data-col-idx]=\"colIdx\"\r\n [attr.data-row-idx]=\"rowIdx\"\r\n [class.selected]=\"freeSelectionMatrix?.[rowIdx]?.[colIdx]\"\r\n class=\"cell {{column.cssClasses}}\">\r\n <ng-container [ngTemplateOutletContext]=\"{row: row}\"\r\n [ngTemplateOutlet]=\"column.cellTemplate || NoVertCellTemplate\">\r\n </ng-container>\r\n <ng-template #NoVertCellTemplate>\r\n {{ row[column.dataField] }}\r\n </ng-template>\r\n </div>\r\n }\r\n </div>\r\n </cdk-virtual-scroll-viewport>\r\n </div>\r\n } @else {\r\n <div (matSortChange)=\"onSort($event)\"\r\n (scroll)=\"onScroll()\"\r\n [matSortDisabled]=\"!withSort\"\r\n cdkVirtualScrollingElement\r\n class=\"flextable by-column striped {{align}}\"\r\n matSort>\r\n <!-- header column -->\r\n <div class=\"column header pos-sticky-horizontal\">\r\n @for (column of columns; track column) {\r\n <div [disabled]=\"!column.withSort\"\r\n [mat-sort-header]=\"column.dataField\"\r\n [style.max-width.px]=\"columnMaxWidth\"\r\n class=\"cell {{column.cssClasses}}\">\r\n <ng-container [ngTemplateOutlet]=\"column.headerTemplate || NoHorHeaderTemplate\">\r\n </ng-container>\r\n <ng-template #NoHorHeaderTemplate>\r\n {{ column.columnLabel || column.dataField }}\r\n </ng-template>\r\n </div>\r\n }\r\n </div>\r\n <!-- virtual scroller with data columns -->\r\n <cdk-virtual-scroll-viewport #vScroller [orientation]=\"'horizontal'\" itemSize=\"114\">\r\n <div *cdkVirtualFor=\"let row of domData; let rowIdx = index\"\r\n [class.selected]=\"rowSelectionMatrix?.[rowIdx]\"\r\n [style.max-width.px]=\"columnMaxWidth\"\r\n class=\"column\">\r\n @for (column of columns; track column; let colIdx = $index) {\r\n <div [attr.data-col-idx]=\"colIdx\"\r\n [attr.data-row-idx]=\"rowIdx\"\r\n [class.selected]=\"freeSelectionMatrix?.[rowIdx]?.[colIdx]\"\r\n class=\"cell {{column.cssClasses}}\">\r\n <ng-container [ngTemplateOutletContext]=\"{row: row}\"\r\n [ngTemplateOutlet]=\"column.cellTemplate || NoHorCellTemplate\">\r\n </ng-container>\r\n <ng-template #NoHorCellTemplate>\r\n {{ row[column.dataField] }}\r\n </ng-template>\r\n </div>\r\n }\r\n </div>\r\n </cdk-virtual-scroll-viewport>\r\n </div>\r\n }\r\n\r\n @if (showToTop && toTopActive) {\r\n <div (click)=\"onGoToTop()\"\r\n [matTooltip]=\"orientation === 'vertical' ? 'to top' : 'to left'\"\r\n class=\"flextable__to-top\"\r\n matTooltipClass=\"bg-accent\">\r\n <mat-icon [fontIcon]=\"orientation === 'vertical' ? 'arrow_upward' : 'arrow_back'\" class=\"small\">\r\n </mat-icon>\r\n </div>\r\n }\r\n\r\n</div>\r\n","import {Directive, EventEmitter, HostListener, Input, OnDestroy, Output} from '@angular/core';\r\nimport {Subject} from 'rxjs';\r\n\r\n@Directive({\r\n selector: '[spaasTableSelectionRow]',\r\n exportAs: 'spaasTableSelectionRow'\r\n})\r\nexport class TableSelectionRowDirective implements OnDestroy {\r\n\r\n @Input() rowSelectionMatrix: number[] = [];\r\n @Input() multiSelect: boolean = false;\r\n @Output() selectionChanged = new EventEmitter<number>(); // will emit last selected row index\r\n\r\n isSelecting = false;\r\n private selectionId = 1;\r\n\r\n // set the from/to variables to public because it's very handy to be able to access these directly in the template\r\n fromRow = 0;\r\n toRow: number = 0;\r\n\r\n private onDestroy = new Subject<void>();\r\n\r\n @HostListener('mousedown', ['$event'])\r\n mouseDown(e: MouseEvent) {\r\n const mouseData = this.checkMouseData(e);\r\n if (mouseData.valid) {\r\n this.onClickCell(e, mouseData.rowIdx);\r\n }\r\n }\r\n\r\n @HostListener('mousemove', ['$event'])\r\n mouseMove(e: MouseEvent) {\r\n const mouseData = this.checkMouseData(e);\r\n if (this.isSelecting && mouseData.valid && mouseData.rowIdx !== this.toRow) {\r\n this.onSelecting(mouseData.rowIdx);\r\n }\r\n }\r\n\r\n @HostListener('mouseup', ['$event'])\r\n mouseUp() {\r\n this.onStopSelect('mouseup');\r\n }\r\n\r\n @HostListener('mouseleave', ['$event'])\r\n mouseLeave() {\r\n this.onStopSelect('mouseleave');\r\n }\r\n\r\n @HostListener('tableSortedOrFiltered', ['$event'])\r\n sort() {\r\n this.resetSelectionRange(true, true);\r\n this.emitNewSelection();\r\n }\r\n\r\n ngOnDestroy() {\r\n this.onDestroy.next();\r\n this.onDestroy.complete();\r\n }\r\n\r\n private checkMouseData(e: MouseEvent): { valid: boolean, rowIdx: number } {\r\n const target = (e.target) as HTMLElement;\r\n let dataset: any = target?.dataset;\r\n if (!dataset?.rowIdx) {\r\n // also check the offsetParent, for cells with sub-divs\r\n dataset = ((target?.offsetParent) as HTMLElement).dataset;\r\n }\r\n let rowIdx = -1;\r\n if (dataset?.rowIdx) {\r\n rowIdx = Number.isNaN((Number(dataset.rowIdx))) ? -1 : Number(dataset.rowIdx);\r\n }\r\n return {\r\n valid: rowIdx > -1,\r\n rowIdx: rowIdx,\r\n };\r\n }\r\n\r\n private onClickCell(e: MouseEvent, rowIdx: number): void {\r\n if (!e) {\r\n return;\r\n }\r\n this.isSelecting = true;\r\n if (!e.shiftKey && !e.ctrlKey) {\r\n // normal click: update all selection variables\r\n ++this.selectionId;\r\n this.fromRow = rowIdx;\r\n this.toRow = rowIdx;\r\n this.resetSelectionRange(true);\r\n } else if (e.shiftKey && this.multiSelect) {\r\n // shift click: set last variables for range selection\r\n document.getSelection()?.removeAllRanges();\r\n this.toRow = rowIdx;\r\n this.updateSelectionRange();\r\n } else if (e.ctrlKey && this.multiSelect) {\r\n // ctrl key: just set for row itself\r\n ++this.selectionId;\r\n this.rowSelectionMatrix[rowIdx] = !this.rowSelectionMatrix[rowIdx] ? this.selectionId : 0;\r\n if (this.rowSelectionMatrix[rowIdx]) {\r\n this.fromRow = rowIdx;\r\n this.toRow = rowIdx;\r\n } else {\r\n // it's a deselection: search for last selected row to put focus on\r\n for (let row = 0; row < this.rowSelectionMatrix.length; row++) {\r\n if (this.rowSelectionMatrix[row]) {\r\n this.toRow = row;\r\n }\r\n }\r\n }\r\n }\r\n }\r\n\r\n private onSelecting(rowIdx: number): void {\r\n if (this.isSelecting && this.multiSelect) {\r\n document.getSelection()?.removeAllRanges();\r\n this.toRow = rowIdx;\r\n this.resetSelectionRange();\r\n this.updateSelectionRange();\r\n }\r\n }\r\n\r\n private onStopSelect(fromMouseEvent: 'mouseup' | 'mouseleave'): void {\r\n if (this.isSelecting) {\r\n this.isSelecting = false;\r\n if (fromMouseEvent === 'mouseup') {\r\n this.emitNewSelection();\r\n }\r\n }\r\n }\r\n\r\n private emitNewSelection(): void {\r\n this.selectionChanged.emit(this.rowSelectionMatrix[this.toRow] > 0 ? this.toRow : -1);\r\n }\r\n\r\n private resetSelectionRange(fullReset = false, fromSort = false): void {\r\n const wasSelected = this.rowSelectionMatrix[this.toRow] > 0;\r\n for (let rowIdx = 0; rowIdx < this.rowSelectionMatrix.length; rowIdx++) {\r\n if (fullReset || this.rowSelectionMatrix[rowIdx] === this.selectionId) {\r\n this.rowSelectionMatrix[rowIdx] = 0;\r\n }\r\n }\r\n this.rowSelectionMatrix[this.toRow] = fromSort || wasSelected ? 0 : this.selectionId;\r\n }\r\n\r\n private updateSelectionRange(): void {\r\n const fromRow = Math.min(this.fromRow, this.toRow);\r\n const toRow = Math.max(this.fromRow, this.toRow);\r\n for (let rowIdx = fromRow; rowIdx <= toRow; rowIdx++) {\r\n this.rowSelectionMatrix[rowIdx] = this.selectionId;\r\n }\r\n }\r\n\r\n}\r\n","import {TemplateRef} from \"@angular/core\";\r\n\r\nexport class TableColumnModel {\r\n cellTemplate?: TemplateRef<any> | null = null;\r\n columnLabel?: string = '';\r\n cssClasses?: string;\r\n dataField: string = '';\r\n headerTemplate?: TemplateRef<any>;\r\n withFilterDefault?: string | string[] = '';\r\n withFilterSelect?: '' | 'single' | 'multiple' = '';\r\n withSort?: boolean = true;\r\n}\r\n\r\nexport class TableColumnFilterModel extends TableColumnModel {\r\n filterDropdownValues: any[] = [];\r\n\r\n update(col: Partial<TableColumnFilterModel>) {\r\n Object.assign(this, col);\r\n }\r\n\r\n}\r\n","import {Component, EventEmitter, Input, OnChanges, Output, SimpleChanges} from '@angular/core';\r\nimport {FormControl, FormGroup} from \"@angular/forms\";\r\nimport {TableColumnFilterModel, TableColumnModel} from \"../_models/table-column.model\";\r\nimport {UtilsService} from \"ngx-gem-spaas\";\r\n\r\n@Component({\r\n selector: 'spaas-table-filter',\r\n styleUrls: ['./table-filter.component.scss'],\r\n templateUrl: './table-filter.component.html',\r\n})\r\nexport class TableFilterComponent implements OnChanges {\r\n\r\n @Input() tableData: any[] = [];\r\n @Input() columns: TableColumnModel[] = [];\r\n @Input() withFreeSearch: boolean = true;\r\n\r\n @Output() filterChanged = new EventEmitter<string>();\r\n // also emit separately that the \"clear all\" button has been clicked (for parent components with additional filtering)\r\n @Output() filterCleared = new EventEmitter<void>();\r\n\r\n filterString = '';\r\n filterForm = new FormGroup<any>({});\r\n filterColumns: TableColumnFilterModel[] = [];\r\n\r\n readonly FREESEARCH_CTRL = 'freeSearch';\r\n readonly ALL_VALUE = '';\r\n\r\n private static cleanValue(val: any): string {\r\n // trim, escape backslashes and lowercase the value\r\n return (val + '').trim().replace(/\\\\/g, '\\\\\\\\').toLowerCase();\r\n }\r\n\r\n constructor() {\r\n this.filterForm.addControl(this.FREESEARCH_CTRL, new FormControl<string>(''));\r\n }\r\n\r\n ngOnChanges(changes: SimpleChanges): void {\r\n if (changes.hasOwnProperty('columns')) {\r\n this.setFilterFormAndColumns();\r\n }\r\n if (changes.hasOwnProperty('tableData') && this.tableData?.length) {\r\n this.setDropdownLists();\r\n }\r\n }\r\n\r\n private setFilterFormAndColumns(): void {\r\n this.filterColumns = [];\r\n let hasValidDefault = false;\r\n for (const col of this.columns) {\r\n if (col.withFilterSelect) {\r\n let newValidDefault = false;\r\n const filterCol = new TableColumnFilterModel();\r\n filterCol.update(col);\r\n this.filterColumns.push(filterCol);\r\n if (col.withFilterSelect === 'single') {\r\n newValidDefault = !!col.withFilterDefault && typeof col.withFilterDefault === 'string';\r\n const filterDefault = newValidDefault ? col.withFilterDefault as string : '';\r\n this.filterForm.addControl(col.dataField, new FormControl<string>(filterDefault));\r\n } else {\r\n newValidDefault = !!col.withFilterDefault && Array.isArray(col.withFilterDefault) && col.withFilterDefault.length > 0;\r\n const filterDefault = newValidDefault ? col.withFilterDefault as string[] : [this.ALL_VALUE];\r\n this.filterForm.addControl(col.dataField, new FormControl<string[]>(filterDefault));\r\n }\r\n hasValidDefault = hasValidDefault || newValidDefault;\r\n }\r\n }\r\n if (hasValidDefault) {\r\n this.updateFilter();\r\n }\r\n }\r\n\r\n private setDropdownLists(): void {\r\n if (!this.filterColumns.length) {\r\n // should not happen since the columns should always be initialised before the data, but do the check anyway\r\n this.setFilterFormAndColumns();\r\n }\r\n for (const col of this.filterColumns) {\r\n const allColValues = this.tableData.map((t) => t[col.dataField] === null ? '' : '' + t[col.dataField]);\r\n col.filterDropdownValues = UtilsService.distinct(allColValues);\r\n }\r\n }\r\n\r\n onSelectAll(column: TableColumnFilterModel): void {\r\n if (column.withFilterSelect === 'multiple') {\r\n this.filterForm.controls[column.dataField].patchValue([this.ALL_VALUE]);\r\n }\r\n this.updateFilter();\r\n }\r\n\r\n onSelectOne(column: TableColumnFilterModel): void {\r\n if (column.withFilterSelect === 'multiple') {\r\n const val = this.filterForm.controls[column.dataField].value;\r\n if (!val.length) {\r\n // user has deselected the only selected value => set to \"all\" value\r\n this.filterForm.controls[column.dataField].patchValue([this.ALL_VALUE]);\r\n } else {\r\n // user has selected an option, deselect \"all\" value\r\n this.filterForm.controls[column.dataField].patchValue(val.filter((v: string) => v !== this.ALL_VALUE));\r\n }\r\n }\r\n this.updateFilter();\r\n }\r\n\r\n updateFilter(): void {\r\n let freeValueFilter = '';\r\n let dropdownFilter = '';\r\n // first free search\r\n const freeValue = TableFilterComponent.cleanValue(this.filterForm.controls[this.FREESEARCH_CTRL].value);\r\n if (freeValue) {\r\n // here we add ALL columns, not just the ones with filter === true\r\n for (const col of this.columns) {\r\n freeValueFilter += '(\"\" + e[\"' + col.dataField + '\"]).toLowerCase().includes(\"' + freeValue + '\") || ';\r\n }\r\n freeValueFilter = '(' + freeValueFilter.substring(0, freeValueFilter.length - 4) + ') ';\r\n }\r\n // then dropdown fields\r\n for (const col of this.filterColumns) {\r\n if (col.withFilterSelect == 'single') {\r\n const colFilterValue = TableFilterComponent.cleanValue(this.filterForm.controls[col.dataField].value);\r\n if (colFilterValue) {\r\n dropdownFilter += '(\"\" + e[\"' + col.dataField + '\"]).toLowerCase() === \"' + colFilterValue + '\" && ';\r\n }\r\n } else {\r\n const colFilterValues = this.filterForm.controls[col.dataField].value;\r\n let multiGroup = '';\r\n for (const val of colFilterValues) {\r\n if (val) {\r\n multiGroup += '(\"\" + e[\"' + col.dataField + '\"]).toLowerCase() === \"' + TableFilterComponent.cleanValue(val) + '\" || ';\r\n }\r\n }\r\n if (multiGroup) {\r\n dropdownFilter += '(' + multiGroup.substring(0, multiGroup.length - 4) + ') && ';\r\n }\r\n }\r\n }\r\n if (dropdownFilter) {\r\n dropdownFilter = '(' + dropdownFilter.substring(0, dropdownFilter.length - 4) + ') ';\r\n }\r\n const concatFilter = freeValueFilter && dropdownFilter ? freeValueFilter + ' && ' + dropdownFilter : freeValueFilter || dropdownFilter;\r\n this.emitFilter(concatFilter);\r\n }\r\n\r\n onReset(): void {\r\n this.filterForm.controls[this.FREESEARCH_CTRL].patchValue('');\r\n for (const col of this.filterColumns) {\r\n const ctrl = this.filterForm.controls[col.dataField];\r\n ctrl.patchValue(col.withFilterSelect === 'single' ? '' : [this.ALL_VALUE]);\r\n }\r\n this.emitFilter('')\r\n this.filterCleared.emit();\r\n }\r\n\r\n private emitFilter(filter: string): void {\r\n this.filterString = filter;\r\n this.filterChanged.emit(filter);\r\n }\r\n\r\n}\r\n","<div [formGroup]=\"filterForm\"\r\n [ngClass]=\"{\r\n 'column': withFreeSearch,\r\n 'row-reverse': !withFreeSearch,\r\n }\"\r\n class=\"filter pad-small flex column-gap-10\">\r\n\r\n <div class=\"flex wrap column-gap-10 align-center\">\r\n\r\n @if (withFreeSearch) {\r\n <mat-form-field class=\"grow-h free-search\"\r\n floatLabel=\"always\">\r\n <mat-label>search any field...</mat-label>\r\n <input matInput\r\n type=\"search\"\r\n (search)=\"updateFilter()\"\r\n formControlName=\"freeSearch\">\r\n </mat-form-field>\r\n }\r\n\r\n <div class=\"flex column-gap-10 pad-small-top\">\r\n @if (withFreeSearch) {\r\n <button class=\"primary\"\r\n (click)=\"updateFilter()\">\r\n search\r\n </button>\r\n }\r\n @if (filterColumns?.length) {\r\n <button class=\"error\"\r\n (click)=\"onReset()\">\r\n clear all\r\n </button>\r\n }\r\n </div>\r\n\r\n </div>\r\n\r\n <div class=\"flex wrap column-gap-10 align-center\"\r\n [class.grow-h]=\"!withFreeSearch\">\r\n\r\n @for (column of filterColumns; track column) {\r\n <mat-form-field class=\"grow-h\"\r\n floatLabel=\"always\">\r\n <mat-label>{{ column.columnLabel || column.dataField }}</mat-label>\r\n <mat-select [formControlName]=\"column.dataField\"\r\n [multiple]=\"column.withFilterSelect === 'multiple'\">\r\n <mat-option (click)=\"onSelectAll(column)\" [value]=\"ALL_VALUE\">all</mat-option>\r\n @for (val of column.filterDropdownValues; track val) {\r\n <mat-option (click)=\"onSelectOne(column)\"\r\n [value]=\"val\">\r\n {{ val }}\r\n </mat-option>\r\n }\r\n </mat-select>\r\n </mat-form-field>\r\n }\r\n\r\n </div>\r\n\r\n</div>\r\n","import {NgModule} from \"@angular/core\";\r\nimport {TableSelectionFreeDirective} from \"./_directives/table-selection-free.directive\";\r\nimport {TableComponent} from \"./table/table.component\";\r\nimport {MatSortModule} from \"@angular/material/sort\";\r\nimport {CommonModule} from \"@angular/common\";\r\nimport {ScrollingModule} from \"@angular/cdk/scrolling\";\r\nimport {MatTooltipModule} from \"@angular/material/tooltip\";\r\nimport {MatIconModule} from \"@angular/material/icon\";\r\nimport {TableSelectionRowDirective} from \"./_directives/table-selection-row.directive\";\r\nimport {TableCellDirective} from \"./_directives/table-cell.directive\";\r\nimport {TableHeaderDirective} from \"./_directives/table-header.directive\";\r\nimport {TableFilterComponent} from \"./table-filter/table-filter.component\";\r\nimport {MatInputModule} from \"@angular/material/input\";\r\nimport {MatFormFieldModule} from \"@angular/material/form-field\";\r\nimport {MatSelectModule} from \"@angular/material/select\";\r\nimport {ReactiveFormsModule} from \"@angular/forms\";\r\n\r\n@NgModule({\r\n declarations: [\r\n TableCellDirective,\r\n TableComponent,\r\n TableFilterComponent,\r\n TableHeaderDirective,\r\n TableSelectionFreeDirective,\r\n TableSelectionRowDirective,\r\n ],\r\n exports: [\r\n TableCellDirective,\r\n TableComponent,\r\n TableFilterComponent,\r\n TableHeaderDirective,\r\n TableSelectionFreeDirective,\r\n TableSelectionRowDirective,\r\n ],\r\n imports: [\r\n CommonModule,\r\n MatFormFieldModule,\r\n MatIconModule,\r\n MatInputModule,\r\n MatSelectModule,\r\n MatSortModule,\r\n MatTooltipModule,\r\n ReactiveFormsModule,\r\n ScrollingModule,\r\n ],\r\n providers: []\r\n})\r\nexport class SpaasTableModule {\r\n}\r\n","// MODULE\r\nexport * from './table.module';\r\n\r\n// DIRECTIVES\r\nexport * from './_directives/table-cell.directive';\r\nexport * from './_directives/table-header.directive';\r\nexport * from './_directives/table-selection-free.directive';\r\nexport * from './_directives/table-selection-row.directive';\r\n\r\n// COMPONENTS\r\nexport * from './table/table.component';\r\nexport * from './table-filter/table-filter.component';\r\n\r\n// MODELS AND CONSTANTS\r\nexport * from './_models/table-column.model';\r\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './public-api';\n"],"names":["i2","i3","i4","i5"],"mappings":"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