import { coerceBooleanProperty , coerceNumberProperty } from '@angular/cdk/coercion' ; import { AfterViewInit , ChangeDetectionStrategy , Component , ElementRef , EventEmitter , HostBinding , Inject , Input , OnDestroy , Output , Renderer2 } from '@angular/core' ; import { Subject } from 'rxjs' ; import { filter , takeUntil } from 'rxjs/operators' ; import { BaseResizableTableService , ResizableTableType } from './resizable-table-base.service' ; import { RESIZABLE_TABLE_SERVICE_TOKEN } from './resizable-table-service.token' ; import { ColumnUnit } from './table-column-resize-standard/resizable-table.service' ; @ Component ( { selector : '[uxResizableTableColumn]' , templateUrl : './resizable-table-column.component.html' , changeDetection : ChangeDetectionStrategy . OnPush , host : { class : 'ux-resizable-table-column' , '[class.ux-resizable-table-hide-handle]' : '!handleVisible' } } ) export class ResizableTableColumnComponent implements AfterViewInit , OnDestroy { /** Show/Hide column resizable handle */ private _handleVisible : boolean = true ; /** Disabled the column resizing */ @ Input ( ) @ HostBinding ( 'class.ux-resizable-table-column-disabled' ) disabled : boolean = false ; @ Input ( ) get handleVisible ( ) : boolean { return this . _handleVisible ; } set handleVisible ( value ) { this . _handleVisible = coerceBooleanProperty ( value ) ; } /** Define the width of a column */ @ Input ( ) set width ( width ) { if ( width === null || width === undefined ) { return ; } this . _width = coerceNumberProperty ( width ) ; this . isFixedWidth = true ; if ( ! this . _table . isInitialised$ . value ) { this . _renderer . setStyle ( this . _elementRef . nativeElement , 'width' , `${ this . _width }px` ) ; } else { const currentWidth = this . _table . getColumnWidth ( this . getCellIndex ( ) , ColumnUnit . Pixel ) ; if ( isNaN ( currentWidth ) ) { this . _table . resizeColumn ( this . getCellIndex ( ) , this . _width , false ) ; } else { this . _table . resizeColumn ( this . getCellIndex ( ) , this . _width - currentWidth , false ) ; } } } get width ( ) : number { return this . _width ; } /** Emit the current column width */ @ Output ( ) widthChange = new EventEmitter < number > ( ) ; /** Get the minimum width allowed by the column */ get minWidth ( ) : number { const computed = parseFloat ( getComputedStyle ( this . _elementRef . nativeElement ) . minWidth ) ; return this . disabled ? this . _elementRef . nativeElement . offsetWidth : isNaN ( computed ) ? 0 : computed ; } /** Determine if this column is a variable width column */ isFixedWidth : boolean = false ; /** Store the width specifically set by the input */ private _width : number ; /** Store the position of the mouse within the drag handle */ private _offset : number ; /** Min width of the column*/ private _minWidth : number ; /** Emit when all observables should be unsubscribed */ private _onDestroy = new Subject < void > ( ) ; constructor ( private _elementRef , @ Inject ( RESIZABLE_TABLE_SERVICE_TOKEN ) private _table , private _renderer ) { } ngAfterViewInit ( ) { this . _table . isInitialised$ . pipe ( takeUntil ( this . _onDestroy ) , filter ( isInitialised => isInitialised ) ) . subscribe ( ( ) => { this . _minWidth = parseFloat ( getComputedStyle ( this . _elementRef . nativeElement ) . minWidth ) ; const width = this . _table . getColumnWidth ( this . getCellIndex ( ) , ColumnUnit . Pixel ) ; if ( ! isNaN ( width ) ) { this . widthChange . emit ( width ) ; } } ) ; this . _table . onResize$ . pipe ( takeUntil ( this . _onDestroy ) ) . subscribe ( ( ) => { this . setColumnWidth ( ) ; this . setColumnFlex ( ) ; const width = this . _table . getColumnWidth ( this . getCellIndex ( ) , ColumnUnit . Pixel ) ; if ( ! isNaN ( width ) && ( this . _width === undefined || Math . max ( width , this . _width ) - Math . min ( width , this . _width ) >= 1 ) ) { this . widthChange . emit ( width ) ; } } ) ; } /** Cleanup when component is destroyed */ ngOnDestroy ( ) { this . _onDestroy . next ( ) ; this . _onDestroy . complete ( ) ; } /** Get the natural pixel width of the column */ getNaturalWidth ( ) { return this . _width || this . _elementRef . nativeElement . offsetWidth ; } /** When the dragging starts */ onDragStart ( event ) { this . _offset = event . clientX - ( event . target as HTMLElement ) . getBoundingClientRect ( ) . left ; } /** When the mouse is moved */ onDragMove ( event , handle ) { const mouseX = event . pageX - pageXOffset ; const { left } = handle . getBoundingClientRect ( ) ; const delta = mouseX - ( left + this . _offset ) ; this . _table . resizeColumn ( this . getCellIndex ( ) , delta ) ; this . _table . setResizing ( true ) ; } /** When the dragging ends */ onDragEnd ( ) { this . _table . setResizing ( false ) ; } /** Shrink the column when the left arrow key is pressed */ onMoveLeft ( ) { this . _table . resizeColumn ( this . getCellIndex ( ) , - 10 ) ; } /** Grow the column when the right arrow key is pressed */ onMoveRight ( ) { this . _table . resizeColumn ( this . getCellIndex ( ) , 10 ) ; } /** Get the column index this cell is part of */ getCellIndex ( ) { return ( this . _elementRef . nativeElement as HTMLTableCellElement ) . cellIndex ; } /** The percentage width of the column */ private setColumnWidth ( ) { if ( this . disabled && this . _width !== undefined ) { this . _renderer . setStyle ( this . _elementRef . nativeElement , 'width' , `${ this . _width }px` ) ; this . _renderer . setStyle ( this . _elementRef . nativeElement , 'max-width' , `${ this . _width }px` ) ; return ; } if ( ! this . _table . isInitialised$ . value ) { return ; } const width = this . _table . isResizing$ . value ? `${ this . _table . getColumnWidth ( this . getCellIndex ( ) , ColumnUnit . Pixel ) }px` : `${ this . _table . getColumnWidth ( this . getCellIndex ( ) , ColumnUnit . Percentage ) }%` ; this . _renderer . setStyle ( this . _elementRef . nativeElement , 'width' , width ) ; this . _renderer . setStyle ( this . _elementRef . nativeElement , 'max-width' , null ) ; } /** The flex width of the column */ private setColumnFlex ( ) { let flex ; if ( this . _table . isResizing$ . value || this . disabled ) { this . _renderer . setStyle ( this . _elementRef . nativeElement , 'flex' , 'none' ) ; } if ( this . _table . type === ResizableTableType . Expand ) { flex = this . _table . isInitialised$ . value ? `0 0 ${ this . _table . getColumnWidth ( this . getCellIndex ( ) , ColumnUnit . Pixel ) }px` : '' ; } else { flex = this . _table . isInitialised$ . value ? `0 1 ${ this . _table . getColumnWidth ( this . getCellIndex ( ) , ColumnUnit . Percentage ) }%` : '' ; } this . _renderer . setStyle ( this . _elementRef . nativeElement , 'flex' , flex ) ; } }