diff --git a/packages/web/src/datagrid/DataGridCore.js b/packages/web/src/datagrid/DataGridCore.js index cdba11272..ebd97e068 100644 --- a/packages/web/src/datagrid/DataGridCore.js +++ b/packages/web/src/datagrid/DataGridCore.js @@ -11,7 +11,16 @@ import axios from '../utility/axios'; import ColumnLabel from './ColumnLabel'; import DataFilterControl from './DataFilterControl'; import { getFilterType } from '@dbgate/filterparser'; -import { convertCellAddress, cellFromEvent, getCellRange } from './selection'; +import { + convertCellAddress, + cellFromEvent, + getCellRange, + topLeftCell, + isRegularCell, + nullCell, + emptyCellArray, +} from './selection'; +import keycodes from '../utility/keycodes'; const GridContainer = styled.div` position: absolute; @@ -30,6 +39,7 @@ const Table = styled.table` right: 20px; overflow: scroll; border-collapse: collapse; + outline: none; `; const TableHead = styled.thead` // display: block; @@ -100,7 +110,7 @@ function CellFormattedValue({ value }) { /** @param props {import('./types').DataGridProps} */ export default function DataGridCore(props) { - const { conid, database, display } = props; + const { conid, database, display, isMainGrid } = props; const columns = display.getGridColumns(); // console.log(`GRID, conid=${conid}, database=${database}, sql=${sql}`); @@ -114,9 +124,9 @@ export default function DataGridCore(props) { const loadedTimeRef = React.useRef(0); - const [currentCell, setCurrentCell] = React.useState([undefined, undefined]); - const [selectedCells, setSelectedCells] = React.useState([]); - const [dragStartCell, setDragStartCell] = React.useState(null); + const [currentCell, setCurrentCell] = React.useState(topLeftCell); + const [selectedCells, setSelectedCells] = React.useState(emptyCellArray); + const [dragStartCell, setDragStartCell] = React.useState(nullCell); const loadNextData = async () => { if (isLoading) return; @@ -176,6 +186,7 @@ export default function DataGridCore(props) { const [headerRowRef, { height: rowHeight }] = useDimensions(); const [tableBodyRef] = useDimensions(); const [containerRef, { height: containerHeight, width: containerWidth }] = useDimensions(); + const tableRef = React.useRef(); const columnSizes = React.useMemo(() => countColumnSizes(), [loadedRows, containerWidth, display]); @@ -209,6 +220,13 @@ export default function DataGridCore(props) { } }); + React.useEffect(() => { + if (isMainGrid) { + // @ts-ignore + if (tableRef.current) tableRef.current.focus(); + } + }, []); + if (!loadedRows || !columns) return null; const rowCountNewIncluded = loadedRows.length; @@ -287,11 +305,12 @@ export default function DataGridCore(props) { } function handleGridMouseDown(event) { + event.target.closest('table').focus(); const cell = cellFromEvent(event); setCurrentCell(cell); setSelectedCells(getCellRange(cell, cell)); setDragStartCell(cell); - console.log('START',cell); + console.log('START', cell); } function handleGridMouseMove(event) { @@ -311,6 +330,83 @@ export default function DataGridCore(props) { } } + function handleGridKeyDown(event) { + handleCursorMove(event); + } + + function handleCursorMove(event) { + if (!isRegularCell(currentCell)) return false; + let rowCount = rowCountNewIncluded; + if (event.ctrlKey) { + switch (event.keyCode) { + case keycodes.upArrow: + case keycodes.pageUp: + return moveCurrentCell(0, currentCell[1], event); + case keycodes.downArrow: + case keycodes.pageDown: + return moveCurrentCell(rowCount - 1, currentCell[1], event); + case keycodes.leftArrow: + return moveCurrentCell(currentCell[0], 0, event); + case keycodes.rightArrow: + return moveCurrentCell(currentCell[0], columnSizes.realCount - 1, event); + case keycodes.home: + return moveCurrentCell(0, 0, event); + case keycodes.end: + return moveCurrentCell(rowCount - 1, columnSizes.realCount - 1, event); + case keycodes.a: + setSelectedCells([['header', 'header']]); + event.preventDefault(); + return true; + } + } else { + switch (event.keyCode) { + case keycodes.upArrow: + if (currentCell[0] == 0) return focusFilterEditor(currentCell[1]); + return moveCurrentCell(currentCell[0] - 1, currentCell[1], event); + case keycodes.downArrow: + case keycodes.enter: + return moveCurrentCell(currentCell[0] + 1, currentCell[1], event); + case keycodes.leftArrow: + return moveCurrentCell(currentCell[0], currentCell[1] - 1, event); + case keycodes.rightArrow: + return moveCurrentCell(currentCell[0], currentCell[1] + 1, event); + case keycodes.home: + return moveCurrentCell(currentCell[0], 0, event); + case keycodes.end: + return moveCurrentCell(currentCell[0], columnSizes.realCount - 1, event); + case keycodes.pageUp: + return moveCurrentCell(currentCell[0] - visibleRowCountLowerBound, currentCell[1], event); + case keycodes.pageDown: + return moveCurrentCell(currentCell[0] + visibleRowCountLowerBound, currentCell[1], event); + } + } + return false; + } + + function focusFilterEditor(columnRealIndex) { + // let modelIndex = this.columnSizes.realToModel(columnRealIndex); + // this.headerFilters[this.columns[modelIndex].uniquePath].focus(); + return true; + } + + function moveCurrentCell(row, col, event) { + let rowCount = rowCountNewIncluded; + + if (row < 0) row = 0; + if (row >= rowCount) row = rowCount - 1; + if (col < 0) col = 0; + if (col >= columnSizes.realCount) col = columnSizes.realCount - 1; + setCurrentCell([row, col]); + if (!event.shiftKey) { + setSelectedCells([]); + } + // this.selectedCells.push(this.currentCell); + // this.scrollIntoView(this.currentCell); + + if (event) event.preventDefault(); + return true; + } + function cellIsSelected(row, col) { const [currentRow, currentCol] = currentCell; if (row == currentRow && col == currentCol) return true; @@ -318,6 +414,7 @@ export default function DataGridCore(props) { if (row == selectedRow && col == selectedCol) return true; if (selectedRow == 'header' && col == selectedCol) return true; if (row == selectedRow && selectedCol == 'header') return true; + if (selectedRow == 'header' && selectedCol == 'header') return true; } return false; } @@ -372,7 +469,15 @@ export default function DataGridCore(props) { // console.log('visibleRealColumnIndexes', visibleRealColumnIndexes); return ( - +
diff --git a/packages/web/src/datagrid/selection.ts b/packages/web/src/datagrid/selection.ts index a8fcb0e50..573274dce 100644 --- a/packages/web/src/datagrid/selection.ts +++ b/packages/web/src/datagrid/selection.ts @@ -1,5 +1,16 @@ import _ from 'lodash'; export type CellAddress = [number | 'header' | 'filter' | undefined, number | 'header' | undefined]; +export type RegularCellAddress = [number, number]; + +export const topLeftCell: CellAddress = [0, 0]; +export const undefinedCell: CellAddress = [undefined, undefined]; +export const nullCell: CellAddress = null; +export const emptyCellArray: CellAddress[] = []; + +export function isRegularCell(cell: CellAddress): cell is RegularCellAddress { + const [row, col] = cell; + return _.isNumber(row) && _.isNumber(col); +} export function getCellRange(a: CellAddress, b: CellAddress): CellAddress[] { const [rowA, colA] = a; @@ -36,6 +47,9 @@ export function getCellRange(a: CellAddress, b: CellAddress): CellAddress[] { } return res; } + if (colA == 'header' && colB == 'header' && rowA == 'header' && rowB == 'header') { + return [['header', 'header']]; + } return []; } @@ -47,6 +61,7 @@ export function convertCellAddress(row, col): CellAddress { export function cellFromEvent(event): CellAddress { const cell = event.target.closest('td'); + if (!cell) return undefinedCell; const col = cell.getAttribute('data-col'); const row = cell.getAttribute('data-row'); return convertCellAddress(row, col); diff --git a/packages/web/src/datagrid/types.ts b/packages/web/src/datagrid/types.ts index 8b22c2514..beb92d6af 100644 --- a/packages/web/src/datagrid/types.ts +++ b/packages/web/src/datagrid/types.ts @@ -4,4 +4,5 @@ export interface DataGridProps { conid: number; database: string; display: GridDisplay; + isMainGrid?: boolean; } diff --git a/packages/web/src/tabs/TableDataTab.js b/packages/web/src/tabs/TableDataTab.js index ebf9433fb..eafd5a0c6 100644 --- a/packages/web/src/tabs/TableDataTab.js +++ b/packages/web/src/tabs/TableDataTab.js @@ -24,6 +24,7 @@ export default function TableDataTab({ conid, database, schemaName, pureName }) conid={conid} database={database} display={display} + isMainGrid /> ); } diff --git a/packages/web/src/utility/keycodes.js b/packages/web/src/utility/keycodes.js index db92af3b0..4c02d1af1 100644 --- a/packages/web/src/utility/keycodes.js +++ b/packages/web/src/utility/keycodes.js @@ -13,7 +13,7 @@ export default { end: 35, home: 36, leftArrow: 37, - ppArrow: 38, + upArrow: 38, rightArrow: 39, downArrow: 40, insert: 45,