import { TableInterface , ControllBarInterface , ControllDragging , ControllChangeSize , ControllOptions , ControllDraggingHeader , } from '../types' ; import { EventEmitter2 } from 'eventemitter2' ; import { $ , CardActiveTrigger , EditorInterface , isEngine , isHotkey , isMobile , NodeInterface , removeUnit , } from '@aomao/engine' ; import Template from './template' ; class ControllBar extends EventEmitter2 implements ControllBarInterface { private editor : EditorInterface ; private table : TableInterface ; private readonly COL_MIN_WIDTH : number ; private readonly ROW_MIN_HEIGHT : number ; tableRoot ? : NodeInterface ; colsHeader ? : NodeInterface ; rowsHeader ? : NodeInterface ; tableHeader ? : NodeInterface ; menuBar ? : NodeInterface ; dragging ? : ControllDragging ; draggingHeader ? : ControllDraggingHeader ; changeSize ? : ControllChangeSize ; viewport ? : NodeInterface ; placeholder ? : NodeInterface ; contextVisible : boolean = false ; rowDeleteButton ? : NodeInterface ; colDeleteButton ? : NodeInterface ; colAddButton ? : NodeInterface ; colAddAlign ? : 'right' | 'left' ; colAddButtonSplit ? : NodeInterface ; moveColIndex : number = - 1 ; hideColAddButtonTimeount ? : NodeJS . Timeout ; rowAddButton ? : NodeInterface ; rowAddAlign ? : 'up' | 'down' ; rowAddButtonSplit ? : NodeInterface ; moveRowIndex : number = - 1 ; hideRowAddButtonTimeount ? : NodeJS . Timeout ; constructor ( editor , table , options ) { super ( ) ; this . table = table ; this . editor = editor ; this . COL_MIN_WIDTH = options . col_min_width ; this . ROW_MIN_HEIGHT = options . row_min_height ; } init ( ) { const { wrapper } = this . table ; if ( ! wrapper ) return ; this . tableRoot = wrapper . find ( Template . TABLE_CLASS ) ; this . colsHeader = wrapper . find ( Template . COLS_HEADER_CLASS ) ; this . rowsHeader = wrapper . find ( Template . ROWS_HEADER_CLASS ) ; this . tableHeader = wrapper . find ( Template . HEADER_CLASS ) ; this . viewport = wrapper . find ( Template . VIEWPORT ) ; this . menuBar = wrapper . find ( Template . MENUBAR_CLASS ) ; this . placeholder = wrapper . find ( Template . PLACEHOLDER_CLASS ) ; this . renderRowBars ( ) ; this . renderColBars ( ) ; this . bindEvents ( ) ; } renderRowBars ( start = 0 , end ? ) { const table = this . tableRoot ?. get < HTMLTableElement > ( ) ; if ( ! table ) return ; this . rowDeleteButton ?. removeAllEvents ( ) ; this . rowDeleteButton = this . rowsHeader ?. find ( Template . ROW_DELETE_BUTTON_CLASS ) ; this . rowAddButton ?. removeAllEvents ( ) ; this . rowAddButton = this . rowsHeader ?. find ( Template . ROW_ADD_BUTTON_CLASS ) ; this . rowAddButtonSplit = this . rowAddButton ?. find ( Template . ROW_ADD_BUTTON_SPLIT_CLASS ) ; this . rowDeleteButton ?. on ( 'mouseover' , ( event ) => this . handleHighlightRow ( ) ) . on ( 'mouseleave' , ( event ) => this . hideHighlight ( event ) ) . on ( 'mousedown' , ( event ) => { event . preventDefault ( ) ; this . table . command [ 'removeRow' ] ( ) ; } ) ; this . rowAddButton ?. on ( 'mouseenter' , ( ) => { if ( this . hideRowAddButtonTimeount ) clearTimeout ( this . hideRowAddButtonTimeount ) ; this . rowsHeader ?. css ( 'z-index' , 126 ) ; } ) . on ( 'mouseleave' , ( ) => { this . hideRowAddButtonTimeount = setTimeout ( ( ) => { this . rowAddButton ?. hide ( ) ; this . rowsHeader ?. css ( 'z-index' , 1 ) ; this . moveRowIndex = - 1 ; } , 200 ) ; } ) . on ( 'mousedown' , ( event ) => { event . preventDefault ( ) ; this . table . command . insertRowAt ( this . moveRowIndex , 1 , this . rowAddAlign === 'down' ? false : true ) ; } ) ; const trs = table . rows ; end = end || trs . length ; const rowBars = this . rowsHeader ?. find ( Template . ROWS_HEADER_ITEM_CLASS ) ; for ( let i = start ; i < end ; i ++ ) { rowBars ?. eq ( i ) ?. css ( 'height' , `${ trs [ i ] . offsetHeight }px` ) ; } const rowTrigger = this . rowsHeader ?. find ( Template . ROWS_HEADER_TRIGGER_CLASS ) ; const tableWidth = this . tableRoot ! . width ( ) ; const wrapperWidth = this . table . wrapper ?. width ( ) || 0 ; const width = tableWidth < wrapperWidth ? tableWidth : wrapperWidth ; rowTrigger ?. css ( 'width' , `${ width + ( this . rowsHeader ?. width ( ) || 0 ) - 1 }px` ) ; } renderColBars ( ) { const table = this . tableRoot ?. get < HTMLTableElement > ( ) ; if ( ! table ) return ; const tableWidth = table . offsetWidth ; this . colDeleteButton ?. removeAllEvents ( ) ; this . colDeleteButton = this . table . wrapper ?. find ( Template . COL_DELETE_BUTTON_CLASS ) ; this . colAddButton ?. removeAllEvents ( ) ; this . colAddButton = this . colsHeader ?. find ( Template . COL_ADD_BUTTON_CLASS ) ; this . colAddButtonSplit = this . colAddButton ?. find ( Template . COL_ADD_BUTTON_SPLIT_CLASS ) ; this . colDeleteButton ?. on ( 'mouseover' , ( event ) => this . handleHighlightCol ( ) ) . on ( 'mouseleave' , ( event ) => this . hideHighlight ( event ) ) . on ( 'mousedown' , ( event ) => { event . preventDefault ( ) ; this . table . command [ 'removeCol' ] ( ) ; } ) ; this . colAddButton ?. on ( 'mouseenter' , ( ) => { if ( this . hideColAddButtonTimeount ) clearTimeout ( this . hideColAddButtonTimeount ) ; } ) . on ( 'mouseleave' , ( ) => { this . hideColAddButtonTimeount = setTimeout ( ( ) => { this . colAddButton ?. hide ( ) ; this . moveColIndex = - 1 ; } , 200 ) ; } ) . on ( 'mousedown' , ( event ) => { event . preventDefault ( ) ; if ( this . moveColIndex > - 1 ) this . table . command . insertColAt ( this . moveColIndex , 1 , this . colAddAlign === 'right' ? false : true ) ; } ) ; this . tableRoot ?. css ( 'width' , `${ tableWidth }px` ) ; this . colsHeader ?. css ( 'width' , `${ tableWidth }px` ) ; const cols = this . tableRoot ?. find ( 'col' ) ; if ( ! cols ) return ; let isInit = true ; const colWidthArray = { } ; let allColWidth = 0 ; let colIndex = 0 ; cols . each ( ( col , i ) => { const colWidth = $ ( col ) . attributes ( 'width' ) ; if ( colWidth ) { colWidthArray [ i ] = colWidth ; allColWidth += parseInt ( colWidth ) ; isInit = false ; } else { colIndex ++ ; } } ) ; const colBars = this . colsHeader ?. find ( Template . COLS_HEADER_ITEM_CLASS ) ; if ( ! colBars ) return ; const { tableModel } = this . table . selection ; if ( isInit ) { let tdWidth = [ ] ; tableModel ?. table ?. forEach ( ( trModel ) => { trModel . forEach ( ( tdModel , c ) => { if ( ! tdWidth [ c ] && ! this . table . helper . isEmptyModelCol ( tdModel ) && ! tdModel . isMulti && tdModel . element ) { tdWidth [ c ] = tdModel . element . offsetWidth ; } } ) ; } ) ; let unkownCount = 0 ; let knownWidth = 0 ; for ( let c = 0 ; c < cols . length ; c ++ ) { if ( ! tdWidth [ c ] ) { unkownCount ++ ; } else { knownWidth += tdWidth [ c ] ; } } let averageWidth = 0 ; if ( unkownCount > 0 ) { averageWidth = Math . round ( ( tableWidth - knownWidth ) / unkownCount ) ; } for ( let i = 0 ; i < cols . length ; i ++ ) { const width = tdWidth [ i ] || averageWidth ; colBars . eq ( i ) ?. css ( 'width' , width + 'px' ) ; cols . eq ( i ) ?. attributes ( 'width' , width ) ; } } else if ( colIndex ) { const averageWidth = Math . round ( ( tableWidth - allColWidth ) / colIndex ) ; cols . each ( ( _ , index ) => { const width = undefined === colWidthArray [ index ] ? averageWidth : colWidthArray [ index ] ; colBars . eq ( index ) ?. css ( 'width' , width + 'px' ) ; cols . eq ( index ) ?. attributes ( 'width' , width ) ; } ) ; } else { cols . each ( ( _ , index ) => { const width = Math . round ( ( tableWidth * colWidthArray [ index ] ) / allColWidth ) ; colBars . eq ( index ) ?. css ( 'width' , width + 'px' ) ; cols . eq ( index ) ?. attributes ( 'width' , width ) ; } ) ; } const colTrigger = this . colsHeader ?. find ( Template . COLS_HEADER_TRIGGER_CLASS ) ; colTrigger ?. css ( 'height' , `${ ( tableModel ?. height || 0 ) + ( this . colsHeader ?. height ( ) || 0 ) }px` ) ; } /**
     * 绑定事件
     */ bindEvents ( ) { this . colsHeader ?. on ( isMobile ? 'touchstart' : 'mousedown' , this . onMouseDownColsHeader ) . on ( 'click' , this . onClickColsHeader ) . on ( 'dragstart' , this . onDragStartColsHeader ) ; this . rowsHeader ?. on ( isMobile ? 'touchstart' : 'mousedown' , this . onMouseDownRowsHeader ) . on ( 'click' , this . onClickRowsHeader ) . on ( 'dragstart' , this . onDragStartRowsHeader ) ; this . tableHeader ?. on ( 'mousedown' , this . onClickTableHeader ) ; this . table . wrapper ?. on ( 'contextmenu' , ( event ) => event . preventDefault ( ) ) ; this . tableRoot ?. on ( 'contextmenu' , ( event ) => event . preventDefault ( ) ) ; this . colsHeader ?. on ( 'contextmenu' , ( event ) => event . preventDefault ( ) ) ; this . rowsHeader ?. on ( 'contextmenu' , ( event ) => event . preventDefault ( ) ) ; this . tableRoot ?. on ( 'mousedown' , ( event ) => this . onTableMouseDown ( event ) ) ; this . menuBar ?. on ( 'click' , ( event ) => this . handleClickMenu ( event ) ) ; this . menuBar ?. on ( 'mouseover' , ( event ) => this . handleHoverMenu ( event ) ) ; this . menuBar ?. on ( 'mouseleave' , ( event ) => this . hideHighlight ( event ) ) ; this . viewport ?. on ( isMobile ? 'touchstart' : 'mousedown' , ( event ) => { if ( ! event . target ) return ; const targetNode = $ ( event . target ) ; if ( ! isEngine ( this . editor ) || ! event . target || ! this . viewport ?. equal ( targetNode ) ) return ; event . preventDefault ( ) ; event . stopPropagation ( ) ; const { change } = this . editor ; const range = change . range . get ( ) ; this . editor . card . focusPrevBlock ( this . table , range , true ) ; this . editor . card . activate ( range . startNode , CardActiveTrigger . MOUSE_DOWN ) ; change . range . select ( range ) ; } ) ; this . colsHeader ?. on ( 'mouseenter' , ( ) => { if ( this . hideColAddButtonTimeount ) clearTimeout ( this . hideColAddButtonTimeount ) ; } ) . on ( 'mousemove' , ( event ) => this . onMouseMoveColsHeader ( event ) ) . on ( 'mouseleave' , ( ) => { this . hideColAddButtonTimeount = setTimeout ( ( ) => { this . colAddButton ?. hide ( ) ; } , 200 ) ; } ) ; this . rowsHeader ?. on ( 'mouseenter' , ( ) => { if ( this . hideRowAddButtonTimeount ) clearTimeout ( this . hideRowAddButtonTimeount ) ; } ) . on ( 'mousemove' , ( event ) => { this . onMouseMoveRowsHeader ( event ) ; this . rowsHeader ?. css ( 'z-index' , 126 ) ; } ) . on ( 'mouseleave' , ( ) => { this . hideRowAddButtonTimeount = setTimeout ( ( ) => { this . rowsHeader ?. css ( 'z-index' , '' ) ; this . rowAddButton ?. hide ( ) ; } , 200 ) ; } ) ; } param event onTableMouseDown ( event ) { if ( ! event . target ) return ; const td = $ ( event . target ) . closest ( 'td' ) ; if ( td . length > 0 && event . button === 2 && this . table . activated ) { this . showContextMenu ( event ) ; } else { this . hideContextMenu ( ) ; } } param event onMouseMoveColsHeader ( event ) { if ( ! event . target || ! this . colAddButton || ! this . colAddButtonSplit ) return ; const targetNode = $ ( event . target ) ; const itemNode = targetNode . closest ( Template . COLS_HEADER_ITEM_CLASS ) ; if ( itemNode . length === 0 ) return ; const items = this . colsHeader ! . find ( Template . COLS_HEADER_ITEM_CLASS ) . toArray ( ) ; const width = itemNode . width ( ) ; const buttonWidth = this . colAddButton . width ( ) ; let left = itemNode . get < HTMLElement > ( ) ! . offsetLeft ; const index = items . findIndex ( ( item ) => item . equal ( itemNode ) ) ; const isEnd = event . offsetX > width / 2 || targetNode . hasClass ( 'cols-trigger' ) ; const isLast = items [ items . length - 1 ] . equal ( itemNode ) ; if ( isEnd ) { left += isLast ? width - buttonWidth / 2 : width ; } this . colAddAlign = isEnd ? 'left' : 'right' ; this . moveColIndex = index ; this . colAddButton ?. show ( 'flex' ) ; this . colAddButton . css ( 'left' , `${ left }px` ) ; this . colAddButton . css ( 'z-index' , 126 ) ; const splitHeight = ( this . table . selection . tableModel ?. height || 0 ) + itemNode . height ( ) + 4 ; this . colAddButtonSplit . css ( 'height' , `${ splitHeight }px` ) ; this . colAddButtonSplit . css ( 'left' , `${ isLast && isEnd ? buttonWidth - 3 + 'px' : '' }` ) ; } param event returns onMouseMoveRowsHeader ( event ) { if ( ! event . target || ! this . rowAddButton || ! this . rowAddButtonSplit ) return ; const targetNode = $ ( event . target ) ; const itemNode = targetNode . closest ( Template . ROWS_HEADER_ITEM_CLASS ) ; if ( itemNode . length === 0 ) return ; const items = this . rowsHeader ! . find ( Template . ROWS_HEADER_ITEM_CLASS ) . toArray ( ) ; const height = itemNode . height ( ) ; let top = itemNode . get < HTMLElement > ( ) ! . offsetTop ; const index = items . findIndex ( ( item ) => item . equal ( itemNode ) ) ; const isEnd = event . offsetY > height / 2 || targetNode . hasClass ( 'rows-trigger' ) ; if ( isEnd ) { top += height ; } this . moveRowIndex = index ; this . rowAddButton . show ( 'flex' ) ; this . rowAddButton . css ( 'top' , `${ top }px` ) ; this . rowAddAlign = isEnd ? 'down' : 'up' ; const splitWidth = ( this . table . selection . tableModel ?. width || 0 ) + itemNode . width ( ) + 4 ; this . rowAddButtonSplit . css ( 'width' , `${ splitWidth }px` ) ; } param event returns onMouseDownColsHeader = ( event ) => { const trigger = $ ( event . target || [ ] ) . closest ( Template . COLS_HEADER_TRIGGER_CLASS ) ; if ( trigger . length === 0 ) { if ( event instanceof MouseEvent && event . button === 2 ) { this . showContextMenu ( event ) ; } return ; } this . startChangeCol ( trigger , event ) ; } ; param event returns onMouseDownRowsHeader = ( event ) => { const trigger = $ ( event . target || [ ] ) . closest ( Template . ROWS_HEADER_TRIGGER_CLASS ) ; if ( trigger . length === 0 ) { if ( event instanceof MouseEvent && event . button === 2 ) { this . showContextMenu ( event ) ; } return ; } this . startChangeRow ( trigger , event ) ; } ; param event onClickColsHeader = ( event ) => { const { selection } = this . table ; const trigger = $ ( event . target || [ ] ) . closest ( Template . COLS_HEADER_TRIGGER_CLASS ) ; if ( trigger . length > 0 ) return ; const colHeader = $ ( event . target || [ ] ) . closest ( Template . COLS_HEADER_ITEM_CLASS ) ; if ( colHeader . length === 0 ) return ; const index = this . colsHeader ?. find ( Template . COLS_HEADER_ITEM_CLASS ) . toArray ( ) . findIndex ( ( item ) => item . equal ( colHeader ) ) ; if ( index === undefined ) return ; selection . selectCol ( index ) ; } ; param event onClickRowsHeader = ( event ) => { const { selection } = this . table ; const trigger = $ ( event . target || [ ] ) . closest ( Template . ROWS_HEADER_TRIGGER_CLASS ) ; if ( trigger . length > 0 ) return ; const rowHeader = $ ( event . target || [ ] ) . closest ( Template . ROWS_HEADER_ITEM_CLASS ) ; if ( rowHeader . length === 0 ) return ; const index = this . rowsHeader ?. find ( Template . ROWS_HEADER_ITEM_CLASS ) . toArray ( ) . findIndex ( ( item ) => item . equal ( rowHeader ) ) ; if ( index === undefined ) return ; selection . selectRow ( index ) ; } ; param event onClickTableHeader = ( event ) => { event . preventDefault ( ) ; const { selection } = this . table ; if ( this . tableHeader ?. hasClass ( 'selected' ) ) { selection . clearSelect ( ) ; } else { const { tableModel } = selection ; if ( ! tableModel ) return ; selection . select ( { row : 0 , col : 0 } , { row : tableModel . rows - 1 , col : tableModel . cols - 1 } ) ; } } ; returns activeHeader ( ) { const selectArea = this . table . selection . getSelectArea ( ) ; this . clearActiveStatus ( ) ; const colBars = this . colsHeader ?. find ( Template . COLS_HEADER_ITEM_CLASS ) ; const rowBars = this . rowsHeader ?. find ( Template . ROWS_HEADER_ITEM_CLASS ) ; const { begin , end , allCol , allRow } = selectArea ; for ( let r = begin . row ; r <= end . row ; r ++ ) { if ( allCol ) { rowBars ?. eq ( r ) ?. addClass ( 'selected' ) ; if ( allRow ) rowBars ?. eq ( r ) ?. addClass ( 'no-dragger' ) ; } } for ( let c = begin . col ; c <= end . col ; c ++ ) { if ( allRow ) { colBars ?. eq ( c ) ?. addClass ( 'selected' ) ; if ( allCol ) colBars ?. eq ( c ) ?. addClass ( 'no-dragger' ) ; } } if ( allCol && allRow ) { this . tableHeader ?. addClass ( 'selected' ) ; } else { this . tableHeader ?. removeClass ( 'selected' ) ; } if ( allCol && ! allRow ) { const tr = this . tableRoot ?. find ( 'tr' ) . eq ( begin . row ) ; if ( tr ) { const top = tr . get < HTMLElement > ( ) ! . offsetTop ; this . rowDeleteButton ?. show ( 'flex' ) ; this . rowDeleteButton ?. css ( 'top' , `${ top - this . rowDeleteButton . height ( ) }px` ) ; } } else { this . rowDeleteButton ?. hide ( ) ; } if ( ! allCol && allRow ) { let width = 0 ; for ( let c = begin . col ; c <= end . col ; c ++ ) { width += colBars ?. eq ( c ) ?. width ( ) || 0 ; } const left = colBars ?. eq ( begin . col ) ?. get < HTMLElement > ( ) ?. offsetLeft || 0 ; this . colDeleteButton ?. show ( 'flex' ) ; this . colDeleteButton ?. css ( 'left' , `${ left + width / 2 }px` ) ; } else { this . colDeleteButton ?. hide ( ) ; } } /**
     * 清楚表头活动状态
     */ clearActiveStatus ( ) { const colBars = this . colsHeader ?. find ( Template . COLS_HEADER_ITEM_CLASS ) ; const rowBars = this . rowsHeader ?. find ( Template . ROWS_HEADER_ITEM_CLASS ) ; colBars ?. removeClass ( 'selected' ) ; colBars ?. removeClass ( 'no-dragger' ) ; rowBars ?. removeClass ( 'selected' ) ; rowBars ?. removeClass ( 'no-dragger' ) ; this . tableHeader ?. removeClass ( 'selected' ) ; } /**
     * 刷新控制UI
     */ refresh ( ) { this . renderColBars ( ) ; this . renderRowBars ( ) ; this . activeHeader ( ) ; } param col param event startChangeCol ( trigger , event ) { event . stopPropagation ( ) ; event . preventDefault ( ) ; const col = trigger . parent ( ) ! ; const colElement = col . get < HTMLTableColElement > ( ) ! ; this . table . selection . clearSelect ( ) ; this . dragging = { x : event instanceof MouseEvent ? event . clientX : event . touches [ 0 ] . clientX , y : - 1 , } ; const index = this . colsHeader ?. find ( Template . COLS_HEADER_ITEM_CLASS ) . toArray ( ) . findIndex ( ( item ) => item . equal ( col ) ) || 0 ; this . changeSize = { trigger : { element : trigger , height : trigger . height ( ) , width : trigger . width ( ) , } , element : col , width : colElement . offsetWidth , height : - 1 , index , table : { width : this . table . selection . tableModel ?. width || 0 , height : this . table . selection . tableModel ?. height || 0 , } , } ; this . bindChangeSizeEvent ( ) ; } param col param event startChangeRow ( trigger , event ) { event . stopPropagation ( ) ; event . preventDefault ( ) ; const row = trigger . parent ( ) ! ; const rowElement = row . get < HTMLTableColElement > ( ) ! ; this . table . selection . clearSelect ( ) ; this . dragging = { x : - 1 , y : event instanceof MouseEvent ? event . clientY : event . touches [ 0 ] . clientY , } ; const index = this . rowsHeader ?. find ( Template . ROWS_HEADER_ITEM_CLASS ) . toArray ( ) . findIndex ( ( item ) => item . equal ( row ) ) || 0 ; this . changeSize = { trigger : { element : trigger , height : trigger . height ( ) , width : trigger . width ( ) , } , element : row , width : - 1 , height : rowElement . offsetHeight , index , table : { width : this . table . selection . tableModel ?. width || 0 , height : this . table . selection . tableModel ?. height || 0 , } , } ; this . bindChangeSizeEvent ( ) ; } /**
     * 绑定改变大小事件
     */ bindChangeSizeEvent ( ) { this . colsHeader ?. addClass ( 'resize' ) ; this . rowsHeader ?. addClass ( 'resize' ) ; document . addEventListener ( isMobile ? 'touchmove' : 'mousemove' , this . onChangeSize ) ; document . addEventListener ( isMobile ? 'touchend' : 'mouseup' , this . onChangeSizeEnd ) ; if ( ! isMobile ) document . addEventListener ( 'mouseleave' , this . onChangeSizeEnd ) ; } /**
     * 移除绑定改变不大小事件
     */ unbindChangeSizeEvent ( ) { this . colsHeader ?. removeClass ( 'resize' ) ; this . rowsHeader ?. removeClass ( 'resize' ) ; document . removeEventListener ( isMobile ? 'touchmove' : 'mousemove' , this . onChangeSize ) ; document . removeEventListener ( isMobile ? 'touchend' : 'mouseup' , this . onChangeSizeEnd ) ; if ( ! isMobile ) document . removeEventListener ( 'mouseleave' , this . onChangeSizeEnd ) ; } onChangeSize = ( event ) => { if ( ! this . dragging ) return ; if ( this . dragging . y > - 1 ) { this . onChangeRowHeight ( event ) ; } else if ( this . dragging . x > - 1 ) { this . onChangeColWidth ( event ) ; } this . emit ( 'sizeChanging' ) ; } ; param event returns onChangeColWidth ( event ) { if ( ! this . dragging || ! this . changeSize ) return ; let width = ( event instanceof MouseEvent ? event . clientX : event . touches [ 0 ] . clientX ) - this . dragging . x ; const colWidth = Math . max ( this . COL_MIN_WIDTH , this . changeSize . width + width ) ; width = colWidth - this . changeSize . width ; const tableWidth = this . changeSize . table . width + width ; this . changeSize . element . css ( 'width' , colWidth + 'px' ) ; const currentElement = this . changeSize . element . get < HTMLElement > ( ) ! ; this . colsHeader ?. css ( 'width' , tableWidth + 'px' ) ; const viewportElement = this . viewport ?. get < HTMLElement > ( ) ! ; const currentColRightSide = currentElement . offsetLeft + currentElement . offsetWidth ; if ( currentColRightSide - viewportElement . scrollLeft + 20 > viewportElement . offsetWidth ) { viewportElement . scrollLeft = currentColRightSide + 20 - viewportElement . offsetWidth ; } else if ( viewportElement . scrollLeft + viewportElement . offsetWidth === viewportElement . scrollWidth ) { viewportElement . scrollLeft = Math . max ( 0 , tableWidth + 34 - viewportElement . offsetWidth ) ; } this . clearActiveStatus ( ) ; this . hideContextMenu ( ) ; this . renderRowBars ( ) ; this . renderColSplitBars ( this . changeSize . element , this . changeSize . trigger . element ) ; this . tableRoot ?. find ( 'col' ) . eq ( this . changeSize . index ) ?. attributes ( 'width' , colWidth ) ; this . tableRoot ?. css ( 'width' , `${ tableWidth }px` ) ; } onChangeRowHeight ( event ) { if ( ! this . dragging || ! this . changeSize ) return ; let height = ( event instanceof MouseEvent ? event . clientY : event . touches [ 0 ] . clientY ) - this . dragging . y ; const rowHeight = Math . max ( this . ROW_MIN_HEIGHT , this . changeSize . height + height ) ; height = rowHeight - this . changeSize . height ; this . changeSize . element . css ( 'height' , rowHeight + 'px' ) ; this . clearActiveStatus ( ) ; this . hideContextMenu ( ) ; this . renderRowSplitBars ( this . changeSize . element , this . changeSize . trigger . element ) ; this . tableRoot ?. find ( 'tr' ) . eq ( this . changeSize . index ) ?. css ( 'height' , `${ rowHeight }px` ) ; } renderColSplitBars ( col , trigger ) { const tableHeight = this . table . selection . tableModel ?. height || 0 ; trigger . addClass ( 'dragging' ) . css ( 'height' , `${ tableHeight + col . height ( ) }px` ) ; } renderRowSplitBars ( row , trigger ) { const viewportElement = this . viewport ?. get < HTMLElement > ( ) ! ; const tableWidth = this . table . selection . tableModel ?. width || 0 ; const width = Math . min ( viewportElement . offsetWidth , tableWidth ) ; trigger . addClass ( 'dragging' ) . css ( 'width' , `${ width + row . width ( ) }px` ) ; } onChangeSizeEnd = ( event ) => { if ( event . type === 'mouseleave' && this . table . getCenter ( ) . contains ( event [ 'toElement' ] ) ) { return ; } if ( this . dragging && this . changeSize ) { const { width , height , element } = this . changeSize . trigger ; element . removeClass ( 'dragging' ) ; if ( this . dragging . x > - 1 ) element . css ( 'height' , `${ height }px` ) ; if ( this . dragging . y > - 1 ) element . css ( 'width' , `${ width }px` ) ; this . dragging = undefined ; this . renderRowBars ( ) ; this . emit ( 'sizeChanged' ) ; } this . unbindChangeSizeEvent ( ) ; } ; onDragStartColsHeader = ( event ) => { event . stopPropagation ( ) ; const { selection } = this . table ; const selectArea = selection . getSelectArea ( ) ; if ( ! event . target || ! selectArea . allRow ) return ; const colBar = $ ( event . target ) . closest ( Template . COLS_HEADER_ITEM_CLASS ) ; if ( colBar . length === 0 ) return ; const index = this . colsHeader ?. find ( Template . COLS_HEADER_ITEM_CLASS ) . toArray ( ) . findIndex ( ( item ) => item . equal ( colBar ) ) ; if ( index === undefined ) return ; const drag_col = index ; if ( drag_col < selectArea . begin . col || drag_col > selectArea . end . col ) return ; this . draggingHeader = { element : colBar , minIndex : selectArea . begin . col , maxIndex : selectArea . end . col , count : selectArea . end . col - selectArea . begin . col + 1 , } ; colBar . addClass ( 'dragging' ) ; colBar . find ( '.drag-info' ) . html ( this . editor . language . get < string > ( 'table' , 'draggingCol' ) . replace ( '$data' , this . draggingHeader . count . toString ( ) ) ) ; this . colsHeader ?. addClass ( 'dragging' ) ; this . table . helper . fixDragEvent ( event ) ; this . bindDragColEvent ( ) ; } ; onDragStartRowsHeader = ( event ) => { event . stopPropagation ( ) ; const { selection } = this . table ; const selectArea = selection . getSelectArea ( ) ; if ( ! event . target || ! selectArea . allCol ) return ; const rowBar = $ ( event . target ) . closest ( Template . ROWS_HEADER_ITEM_CLASS ) ; if ( rowBar . length === 0 ) return ; const index = this . rowsHeader ?. find ( Template . ROWS_HEADER_ITEM_CLASS ) . toArray ( ) . findIndex ( ( item ) => item . equal ( rowBar ) ) ; if ( index === undefined ) return ; const drag_row = index ; if ( drag_row < selectArea . begin . row || drag_row > selectArea . end . row ) return ; this . draggingHeader = { element : rowBar , minIndex : selectArea . begin . row , maxIndex : selectArea . end . row , count : selectArea . end . row - selectArea . begin . row + 1 , } ; rowBar . addClass ( 'dragging' ) ; rowBar . find ( '.drag-info' ) . html ( this . editor . language . get < string > ( 'table' , 'draggingRow' ) . replace ( '$data' , this . draggingHeader . count . toString ( ) ) ) ; this . rowsHeader ?. addClass ( 'dragging' ) ; this . table . helper . fixDragEvent ( event ) ; this . bindDragRowEvent ( ) ; } ; bindDragColEvent ( ) { const { wrapper } = this . table ; wrapper ?. on ( 'dragover' , this . onDragCol ) ; wrapper ?. on ( 'drop' , this . onDragColEnd ) ; wrapper ?. on ( 'dragend' , this . onDragColEnd ) ; } unbindDragColEvent ( ) { const { wrapper } = this . table ; const colBars = this . colsHeader ?. find ( Template . COLS_HEADER_ITEM_CLASS ) ; colBars ?. removeClass ( 'dragging' ) ; this . colsHeader ?. removeClass ( 'dragging' ) ; wrapper ?. off ( 'dragover' , this . onDragCol ) ; wrapper ?. off ( 'drop' , this . onDragColEnd ) ; wrapper ?. off ( 'dragend' , this . onDragColEnd ) ; } bindDragRowEvent ( ) { const { wrapper } = this . table ; wrapper ?. on ( 'dragover' , this . onDragRow ) ; wrapper ?. on ( 'drop' , this . onDragRowEnd ) ; wrapper ?. on ( 'dragend' , this . onDragRowEnd ) ; } unbindDragRowEvent ( ) { const { wrapper } = this . table ; const rowBars = this . rowsHeader ?. find ( Template . ROWS_HEADER_ITEM_CLASS ) ; rowBars ?. removeClass ( 'dragging' ) ; this . rowsHeader ?. removeClass ( 'dragging' ) ; wrapper ?. off ( 'dragover' , this . onDragRow ) ; wrapper ?. off ( 'drop' , this . onDragRowEnd ) ; wrapper ?. off ( 'dragend' , this . onDragRowEnd ) ; } showPlaceHolder ( dropIndex , isNext ? ) { if ( ! this . draggingHeader ) return ; const { element , minIndex , maxIndex } = this . draggingHeader ; if ( element . closest ( Template . COLS_HEADER_CLASS ) . length > 0 ) { if ( dropIndex === this . draggingHeader . index ) return ; if ( minIndex <= dropIndex && dropIndex <= maxIndex + 1 ) { delete this . draggingHeader . index ; delete this . draggingHeader . isNext ; this . placeholder ?. css ( 'display' , 'none' ) ; return ; } this . draggingHeader . isNext = isNext ; this . draggingHeader . index = dropIndex ; const colBars = this . colsHeader ?. find ( Template . COLS_HEADER_ITEM_CLASS ) ; if ( ! colBars ) return ; const left = this . draggingHeader . index !== colBars . length ? colBars . eq ( this . draggingHeader . index ) ! . get < HTMLElement > ( ) ! . offsetLeft + 2 : colBars . eq ( this . draggingHeader . index - 1 ) ! . get < HTMLElement > ( ) ! . offsetLeft + colBars . eq ( this . draggingHeader . index - 1 ) ! . get < HTMLElement > ( ) ! . offsetWidth + 2 ; const viewportElement = this . viewport ?. get < HTMLElement > ( ) ! ; const { scrollLeft , offsetWidth } = viewportElement ; if ( left < scrollLeft ) { viewportElement . scrollLeft = left - 5 ; } if ( left > scrollLeft + offsetWidth ) { viewportElement . scrollLeft = left - offsetWidth + 5 ; } const height = ( this . table . selection . tableModel ?. height || 0 ) + colBars . height ( ) ; const paddingTop = this . viewport ?. css ( 'padding-top' ) ; const paddingLeft = this . viewport ?. css ( 'padding-left' ) || '0' ; this . placeholder ?. css ( 'width' , '2px' ) ; this . placeholder ?. css ( 'height' , `${ height }px` ) ; this . placeholder ?. css ( 'left' , left - 4 + removeUnit ( paddingLeft ) + 'px' ) ; this . placeholder ?. css ( 'top' , paddingTop ) ; this . placeholder ?. css ( 'display' , 'block' ) ; } else if ( element . closest ( Template . ROWS_HEADER_CLASS ) . length > 0 ) { if ( dropIndex === this . draggingHeader . index ) return ; if ( minIndex <= dropIndex && dropIndex <= maxIndex + 1 ) { delete this . draggingHeader . index ; delete this . draggingHeader . isNext ; this . placeholder ?. css ( 'display' , 'none' ) ; return ; } this . draggingHeader . index = dropIndex ; this . draggingHeader . isNext = isNext ; const rowBars = this . rowsHeader ?. find ( Template . ROWS_HEADER_ITEM_CLASS ) ; if ( ! rowBars ) return ; const top = this . draggingHeader . index !== rowBars . length ? rowBars . eq ( this . draggingHeader . index ) ! . get < HTMLElement > ( ) ! . offsetTop + 2 : rowBars . eq ( this . draggingHeader . index - 1 ) ! . get < HTMLElement > ( ) ! . offsetTop + rowBars . eq ( this . draggingHeader . index - 1 ) ! . get < HTMLElement > ( ) ! . offsetHeight - 2 ; const width = this . table . selection . tableModel ?. width || 0 ; const paddingTop = this . viewport ?. css ( 'padding-top' ) ; const paddingLeft = this . viewport ?. css ( 'padding-left' ) || '0' ; const colBars = this . colsHeader ?. find ( Template . COLS_HEADER_ITEM_CLASS ) ; this . placeholder ?. css ( 'height' , '2px' ) ; this . placeholder ?. css ( 'width' , `${ width }px` ) ; this . placeholder ?. css ( 'left' , paddingLeft ) ; this . placeholder ?. css ( 'top' , top + removeUnit ( paddingTop || '0' ) + ( colBars ?. height ( ) || 0 ) - 2 + 'px' ) ; this . placeholder ?. css ( 'display' , 'block' ) ; } } onDragCol = ( event ) => { event . stopPropagation ( ) ; if ( ! this . draggingHeader || ! event . target ) return ; if ( undefined === this . dragging ) { this . dragging = { x : event . offsetX , y : event . offsetY , } ; } if ( event . dataTransfer ) event . dataTransfer . dropEffect = 'move' ; if ( Math . abs ( this . dragging . x - event . offsetX ) < 3 ) return ; this . dragging . x = event . offsetX ; this . draggingHeader . element . removeClass ( 'dragging' ) ; const td = $ ( event . target ) . closest ( 'td' ) ; const colBar = $ ( event . target ) . closest ( Template . COLS_HEADER_ITEM_CLASS ) ; if ( td . length === 0 && colBar . length === 0 ) return ; if ( colBar . length > 0 ) { const index = this . colsHeader ?. find ( Template . COLS_HEADER_ITEM_CLASS ) . toArray ( ) . findIndex ( ( item ) => item . equal ( colBar ) ) ; if ( index === undefined ) return ; const currentCol = index ; const _dropCol = event . offsetX > colBar . get < HTMLElement > ( ) ! . offsetWidth / 2 ? currentCol + 1 : currentCol ; this . showPlaceHolder ( _dropCol , _dropCol !== currentCol ) ; return ; } const colBars = this . colsHeader ?. find ( Template . COLS_HEADER_ITEM_CLASS ) ; if ( ! colBars ) return ; const tdElement = td . get < HTMLTableCellElement > ( ) ! ; const colSpan = tdElement . colSpan ; const [ row , col ] = this . table . selection . getCellPoint ( td ) ; let dropCol = col ; let _passWidth = 0 ; for ( let i = 0 ; i < colSpan ; i ++ ) { const colElement = colBars . eq ( col + i ) ! . get < HTMLElement > ( ) ! ; if ( _passWidth + colElement . offsetWidth / 2 > event . offsetX ) { dropCol = col + i ; break ; } if ( _passWidth + colElement . offsetWidth > event . offsetX ) { dropCol = col + i + 1 ; break ; } _passWidth += colElement . offsetWidth ; } this . showPlaceHolder ( dropCol , dropCol !== col ) ; } ; onDragColEnd = ( ) => { this . unbindDragColEvent ( ) ; const { index , count , isNext } = this . draggingHeader || { } ; if ( ! this . draggingHeader || index === undefined || count === undefined ) return ; const { command , selection } = this . table ; const selectArea = selection . getSelectArea ( ) ; const colBars = this . table . wrapper ?. find ( Template . COLS_HEADER_ITEM_CLASS ) ; if ( ! colBars ) return ; let widths = [ ] ; for ( let c = selectArea . begin . col ; c <= selectArea . end . col ; c ++ ) { widths . push ( colBars . eq ( c ) ?. get < HTMLElement > ( ) ?. offsetWidth || 0 ) ; } command . mockCopy ( ) ; if ( selectArea . begin . col > index ) { command . insertColAt ( isNext ? index - 1 : index , count , isNext , widths , true ) ; selection . selectCol ( index , index + count - 1 ) ; command . mockPaste ( true ) ; setTimeout ( ( ) => { selection . selectCol ( selectArea . begin . col + count , selectArea . end . col + count ) ; command . removeCol ( ) ; selection . selectCol ( index , index + count - 1 ) ; } , 10 ) ; } else { command . insertColAt ( isNext ? index - 1 : index , count , isNext , widths , true ) ; selection . selectCol ( index , index + count - 1 ) ; command . mockPaste ( true ) ; setTimeout ( ( ) => { selection . selectCol ( selectArea . begin . col , selectArea . end . col ) ; command . removeCol ( ) ; selection . selectCol ( index - count , index - 1 ) ; } , 10 ) ; } this . placeholder ?. css ( 'display' , 'none' ) ; this . draggingHeader = undefined ; this . dragging = undefined ; } ; onDragRow = ( event ) => { event . stopPropagation ( ) ; if ( ! this . draggingHeader || ! event . target ) return ; if ( undefined === this . dragging ) { this . dragging = { x : event . offsetX , y : event . offsetY , } ; } if ( Math . abs ( this . dragging . y - event . offsetY ) < 3 ) return ; this . dragging . y = event . offsetY ; this . draggingHeader . element . removeClass ( 'dragging' ) ; const td = $ ( event . target ) . closest ( 'td' ) ; const rowBar = $ ( event . target ) . closest ( Template . ROWS_HEADER_ITEM_CLASS ) ; if ( td . length === 0 && rowBar . length === 0 ) return ; if ( rowBar . length > 0 ) { const index = this . rowsHeader ?. find ( Template . ROWS_HEADER_ITEM_CLASS ) . toArray ( ) . findIndex ( ( item ) => item . equal ( rowBar ) ) ; if ( index === undefined ) return ; const currentRow = index ; const _dropRow = event . offsetY > rowBar . get < HTMLElement > ( ) ! . offsetHeight / 2 ? currentRow + 1 : currentRow ; this . showPlaceHolder ( _dropRow , _dropRow !== currentRow ) ; return ; } const rowBars = this . rowsHeader ?. find ( Template . ROWS_HEADER_ITEM_CLASS ) ; if ( ! rowBars ) return ; const rowSpan = td . get < HTMLTableCellElement > ( ) ! . rowSpan ; const [ row ] = this . table . selection . getCellPoint ( td ) ; let dropRow = row ; let _passHeight = 0 ; for ( let i = 0 ; i < rowSpan ; i ++ ) { const rowElement = rowBars [ row + i ] as HTMLTableRowElement ; if ( _passHeight + rowElement . offsetHeight / 2 > event . offsetY ) { dropRow = row + i ; break ; } if ( _passHeight + rowElement . offsetHeight > event . offsetY ) { dropRow = row + i + 1 ; break ; } _passHeight += rowElement . offsetHeight ; } this . showPlaceHolder ( dropRow , dropRow !== row ) ; } ; onDragRowEnd = ( ) => { this . unbindDragRowEvent ( ) ; const { index , count , isNext } = this . draggingHeader || { } ; if ( ! this . draggingHeader || index === undefined || count === undefined ) return ; const { command , selection } = this . table ; const selectArea = selection . getSelectArea ( ) ; const { begin , end } = selectArea ; command . mockCopy ( ) ; if ( begin . row > index ) { command . insertRowAt ( isNext ? index - 1 : index , count , ! isNext , true ) ; selection . selectRow ( index , index + count - 1 ) ; setTimeout ( ( ) => { command . mockPaste ( true ) ; selection . selectRow ( begin . row + count , end . row + count ) ; command . removeRow ( ) ; selection . selectRow ( index , index + count - 1 ) ; } , 10 ) ; } else { command . insertRowAt ( isNext ? index - 1 : index , count , ! isNext , true ) ; selection . selectRow ( index , index + count - 1 ) ; setTimeout ( ( ) => { command . mockPaste ( true ) ; selection . selectRow ( begin . row , end . row ) ; command . removeRow ( ) ; selection . selectRow ( index - count , index - 1 ) ; } , 10 ) ; } this . placeholder ?. css ( 'display' , 'none' ) ; this . draggingHeader = undefined ; this . dragging = undefined ; } ; removeRow ( index ) { const rowsHeaderItem = this . rowsHeader ?. find ( Template . ROWS_HEADER_ITEM_CLASS ) ; const item = rowsHeaderItem ?. eq ( index ) ?. get < HTMLElement > ( ) ; if ( item ) this . rowsHeader ?. get < HTMLElement > ( ) ?. removeChild ( item ) ; } removeCol ( index ) { const colsHeaderItem = this . colsHeader ?. find ( Template . COLS_HEADER_ITEM_CLASS ) ; const headerElement = this . colsHeader ?. get < HTMLElement > ( ) ; const item = colsHeaderItem ?. eq ( index ) ?. get < HTMLElement > ( ) ; if ( ! headerElement || ! item ) return ; this . colsHeader ?. css ( 'width' , headerElement . offsetWidth - item . offsetWidth + 'px' ) ; headerElement . removeChild ( item ) ; this . tableRoot ?. css ( 'width' , this . colsHeader ?. css ( 'width' ) ) ; } showContextMenu ( event ) { if ( ! this . menuBar || ! event . target ) return ; event . preventDefault ( ) ; const { selection } = this . table ; const menuItems = this . menuBar . find ( Template . MENUBAR_ITEM_CLASS ) ; menuItems . removeClass ( 'disabled' ) ; menuItems . each ( ( menu ) => { const menuNode = $ ( menu ) ; const action = menuNode . attributes ( 'data-action' ) ; if ( this . getMenuDisabled ( action ) ) { menuNode . addClass ( 'disabled' ) ; } else { const inputNode = menuNode . find ( `input${ Template . MENUBAR_ITEM_INPUT_CALSS }` ) ; if ( inputNode . length === 0 ) return ; const inputElement = inputNode . get < HTMLInputElement > ( ) ! ; inputNode . on ( 'blur' , ( ) => { inputElement . value = ( parseInt ( inputElement . value , 10 ) || 1 ) . toString ( ) ; } ) . on ( 'keydown' , ( event ) => { if ( isHotkey ( 'enter' , event ) ) { this . handleTriggerMenu ( menuNode ) ; } } ) ; const selectArea = selection . getSelectArea ( ) ; const isInsertCol = [ 'insertColLeft' , 'insertColRight' ] . indexOf ( action ) > - 1 ; const isInsertRow = [ 'insertRowUp' , 'insertRowDown' ] . indexOf ( action ) > - 1 ; if ( isInsertCol ) { inputElement . value = `${ selectArea . end . col - selectArea . begin . col + 1 }` ; } if ( isInsertRow ) { inputElement . value = `${ selectArea . end . row - selectArea . begin . row + 1 }` ; } inputNode . on ( 'mousedown' , this . onMenuInputMousedown ) ; } } ) ; const splits = this . menuBar . find ( 'div.split' ) ; splits . each ( ( splitNode ) => { const split = $ ( splitNode ) ; let prev = split . prev ( ) ; while ( prev ) { if ( prev . hasClass ( 'split' ) ) { split . remove ( ) ; break ; } if ( ! prev . hasClass ( 'disabled' ) ) break ; prev = prev . prev ( ) ; } if ( ! prev ) split . remove ( ) ; } ) ; const tartgetNode = $ ( event . target ) ; let prevRect = tartgetNode . getBoundingClientRect ( ) || { top : 0 , left : 0 , } ; let parentNode = tartgetNode . parent ( ) ; let top = 0 , left = 0 ; while ( parentNode && parentNode . closest ( Template . TABLE_WRAPPER_CLASS ) . length > 0 ) { const rect = parentNode . getBoundingClientRect ( ) || { top : 0 , left : 0 , } ; top += prevRect . top - rect . top ; left += prevRect . left - rect . left ; prevRect = rect ; parentNode = parentNode . parent ( ) ; } this . menuBar . css ( 'left' , left + event . offsetX + 'px' ) ; this . menuBar . css ( 'top' , top + event . offsetY + 'px' ) ; this . menuBar . css ( 'display' , 'block' ) ; this . contextVisible = true ; } onMenuInputMousedown = ( event ) => { event . stopPropagation ( ) ; } ; hideContextMenu ( ) { if ( ! this . contextVisible ) { return ; } const menuItems = this . menuBar ?. find ( Template . MENUBAR_ITEM_CLASS ) ; menuItems ?. removeClass ( 'disabled' ) ; menuItems ?. each ( ( menu ) => { const menuNode = $ ( menu ) ; const inputNode = menuNode . find ( `input${ Template . MENUBAR_ITEM_INPUT_CALSS }` ) ; if ( inputNode . length === 0 ) return ; inputNode . removeAllEvents ( ) ; } ) ; this . contextVisible = false ; this . menuBar ?. hide ( ) ; } getMenuDisabled ( action ) { const { selection , command } = this . table ; switch ( action ) { case 'cut' : case 'copy' : return ! selection . selectArea || selection . selectArea . count <= 1 ; case 'splitCell' : return ! selection . hasMergeCell ( ) ; case 'mergeCell' : return ! selection . selectArea ; case 'mockPaste' : return ! command . hasCopyData ( ) ; case 'removeCol' : case 'insertColLeft' : case 'insertColRight' : return selection . isColSelected ( ) ; case 'removeRow' : case 'insertRowUp' : case 'insertRowDown' : return selection . isRowSelected ( ) ; default : return false ; } } handleClickMenu ( event ) { if ( ! event . target ) return ; const targetNode = $ ( event . target ) ; const menu = targetNode . closest ( '.table-menubar-item' ) ; if ( menu . length === 0 || targetNode . name === 'input' ) return ; event . stopPropagation ( ) ; this . handleTriggerMenu ( menu ) ; } handleTriggerMenu ( menu ) { if ( ! menu . hasClass ( 'disabled' ) ) { const action = menu . attributes ( 'data-action' ) ; const inputNode = menu . find ( `input${ Template . MENUBAR_ITEM_INPUT_CALSS }` ) ; let args = undefined ; if ( inputNode . length > 0 ) { args = parseInt ( inputNode . get < HTMLInputElement > ( ) ?. value || '1' , 10 ) ; } this . table . command [ action ] ( args ) ; } this . hideContextMenu ( ) ; } handleHoverMenu ( event ) { if ( ! event . target ) return ; const menu = $ ( event . target ) . closest ( '.table-menubar-item' ) ; if ( menu . length === 0 ) return ; event . stopPropagation ( ) ; const { selection } = this . table ; if ( ! menu . hasClass ( 'disabled' ) ) { const action = menu . attributes ( 'data-action' ) ; switch ( action ) { case 'removeCol' : this . handleHighlightCol ( ) ; break ; case 'removeRow' : this . handleHighlightRow ( ) ; break ; case 'removeTable' : this . handleHighlightTable ( ) ; break ; default : selection . hideHighlight ( ) ; } } } hideHighlight ( event ) { event . stopPropagation ( ) ; this . table . selection . hideHighlight ( ) ; } handleHighlightRow = ( ) => { const { selection } = this . table ; const { tableModel } = selection ; if ( ! tableModel ) return ; const selectArea = { ... selection . getSelectArea ( ) } ; selectArea . allCol = true ; selectArea . begin = { row : selectArea . begin . row , col : 0 } ; selectArea . end = { row : selectArea . end . row , col : tableModel . cols - 1 } ; selection . showHighlight ( selectArea ) ; } ; handleHighlightCol = ( ) => { const { selection } = this . table ; const { tableModel } = selection ; if ( ! tableModel ) return ; const selectArea = { ... selection . getSelectArea ( ) } ; selectArea . allRow = true ; selectArea . begin = { row : 0 , col : selectArea . begin . col } ; selectArea . end = { row : tableModel . rows - 1 , col : selectArea . end . col } ; selection . showHighlight ( selectArea ) ; } ; handleHighlightTable = ( ) => { const { selection } = this . table ; const { tableModel } = selection ; if ( ! tableModel ) return ; const selectArea = { ... selection . getSelectArea ( ) } ; selectArea . allRow = true ; selectArea . allCol = true ; selectArea . begin = { row : 0 , col : 0 } ; selectArea . end = { row : tableModel . rows - 1 , col : tableModel . cols - 1 } ; selection . showHighlight ( selectArea ) ; } ; drawBackgroundColor ( color ? ) { const { selection , helper } = this . table ; selection . each ( ( cell ) => { if ( ! helper . isEmptyModelCol ( cell ) && cell . element ) { if ( ! color || color === 'transparent' ) cell . element . style . removeProperty ( 'background-color' ) ; else cell . element . style . backgroundColor = color ; } } ) ; } setAlign ( align ? ) { const { selection , helper } = this . table ; selection . each ( ( cell ) => { if ( ! helper . isEmptyModelCol ( cell ) && cell . element ) { if ( ! align || align === 'top' ) cell . element . style . removeProperty ( 'vertical-align' ) ; else cell . element . style . verticalAlign = align ; } } ) ; } destroy ( ) { this . colsHeader ?. removeAllEvents ( ) ; this . rowsHeader ?. removeAllEvents ( ) ; this . tableHeader ?. removeAllEvents ( ) ; this . table . wrapper ?. removeAllEvents ( ) ; this . tableRoot ?. removeAllEvents ( ) ; this . menuBar ?. removeAllEvents ( ) ; this . viewport ?. removeAllEvents ( ) ; this . rowDeleteButton ?. removeAllEvents ( ) ; this . colDeleteButton ?. removeAllEvents ( ) ; this . colAddButton ?. removeAllEvents ( ) ; this . colsHeader ?. removeAllEvents ( ) ; this . rowAddButton ?. removeAllEvents ( ) ; this . rowsHeader ?. removeAllEvents ( ) ; } } export default ControllBar ;