key handling

This commit is contained in:
Jan Prochazka
2020-03-21 11:49:56 +01:00
parent 20933cec8b
commit 9b5a508eb9
5 changed files with 130 additions and 8 deletions

View File

@@ -11,7 +11,16 @@ import axios from '../utility/axios';
import ColumnLabel from './ColumnLabel'; import ColumnLabel from './ColumnLabel';
import DataFilterControl from './DataFilterControl'; import DataFilterControl from './DataFilterControl';
import { getFilterType } from '@dbgate/filterparser'; 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` const GridContainer = styled.div`
position: absolute; position: absolute;
@@ -30,6 +39,7 @@ const Table = styled.table`
right: 20px; right: 20px;
overflow: scroll; overflow: scroll;
border-collapse: collapse; border-collapse: collapse;
outline: none;
`; `;
const TableHead = styled.thead` const TableHead = styled.thead`
// display: block; // display: block;
@@ -100,7 +110,7 @@ function CellFormattedValue({ value }) {
/** @param props {import('./types').DataGridProps} */ /** @param props {import('./types').DataGridProps} */
export default function DataGridCore(props) { export default function DataGridCore(props) {
const { conid, database, display } = props; const { conid, database, display, isMainGrid } = props;
const columns = display.getGridColumns(); const columns = display.getGridColumns();
// console.log(`GRID, conid=${conid}, database=${database}, sql=${sql}`); // console.log(`GRID, conid=${conid}, database=${database}, sql=${sql}`);
@@ -114,9 +124,9 @@ export default function DataGridCore(props) {
const loadedTimeRef = React.useRef(0); const loadedTimeRef = React.useRef(0);
const [currentCell, setCurrentCell] = React.useState([undefined, undefined]); const [currentCell, setCurrentCell] = React.useState(topLeftCell);
const [selectedCells, setSelectedCells] = React.useState([]); const [selectedCells, setSelectedCells] = React.useState(emptyCellArray);
const [dragStartCell, setDragStartCell] = React.useState(null); const [dragStartCell, setDragStartCell] = React.useState(nullCell);
const loadNextData = async () => { const loadNextData = async () => {
if (isLoading) return; if (isLoading) return;
@@ -176,6 +186,7 @@ export default function DataGridCore(props) {
const [headerRowRef, { height: rowHeight }] = useDimensions(); const [headerRowRef, { height: rowHeight }] = useDimensions();
const [tableBodyRef] = useDimensions(); const [tableBodyRef] = useDimensions();
const [containerRef, { height: containerHeight, width: containerWidth }] = useDimensions(); const [containerRef, { height: containerHeight, width: containerWidth }] = useDimensions();
const tableRef = React.useRef();
const columnSizes = React.useMemo(() => countColumnSizes(), [loadedRows, containerWidth, display]); 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; if (!loadedRows || !columns) return null;
const rowCountNewIncluded = loadedRows.length; const rowCountNewIncluded = loadedRows.length;
@@ -287,6 +305,7 @@ export default function DataGridCore(props) {
} }
function handleGridMouseDown(event) { function handleGridMouseDown(event) {
event.target.closest('table').focus();
const cell = cellFromEvent(event); const cell = cellFromEvent(event);
setCurrentCell(cell); setCurrentCell(cell);
setSelectedCells(getCellRange(cell, cell)); setSelectedCells(getCellRange(cell, cell));
@@ -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) { function cellIsSelected(row, col) {
const [currentRow, currentCol] = currentCell; const [currentRow, currentCol] = currentCell;
if (row == currentRow && col == currentCol) return true; if (row == currentRow && col == currentCol) return true;
@@ -318,6 +414,7 @@ export default function DataGridCore(props) {
if (row == selectedRow && col == selectedCol) return true; if (row == selectedRow && col == selectedCol) return true;
if (selectedRow == 'header' && col == selectedCol) return true; if (selectedRow == 'header' && col == selectedCol) return true;
if (row == selectedRow && selectedCol == 'header') return true; if (row == selectedRow && selectedCol == 'header') return true;
if (selectedRow == 'header' && selectedCol == 'header') return true;
} }
return false; return false;
} }
@@ -372,7 +469,15 @@ export default function DataGridCore(props) {
// console.log('visibleRealColumnIndexes', visibleRealColumnIndexes); // console.log('visibleRealColumnIndexes', visibleRealColumnIndexes);
return ( return (
<GridContainer ref={containerRef}> <GridContainer ref={containerRef}>
<Table onMouseDown={handleGridMouseDown} onMouseMove={handleGridMouseMove} onMouseUp={handleGridMouseUp}> <Table
onMouseDown={handleGridMouseDown}
onMouseMove={handleGridMouseMove}
onMouseUp={handleGridMouseUp}
onKeyDown={handleGridKeyDown}
// table can be focused
tabIndex={-1}
ref={tableRef}
>
<TableHead> <TableHead>
<TableHeaderRow ref={headerRowRef}> <TableHeaderRow ref={headerRowRef}>
<TableHeaderCell data-row="header" data-col="header" /> <TableHeaderCell data-row="header" data-col="header" />

View File

@@ -1,5 +1,16 @@
import _ from 'lodash'; import _ from 'lodash';
export type CellAddress = [number | 'header' | 'filter' | undefined, number | 'header' | undefined]; 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[] { export function getCellRange(a: CellAddress, b: CellAddress): CellAddress[] {
const [rowA, colA] = a; const [rowA, colA] = a;
@@ -36,6 +47,9 @@ export function getCellRange(a: CellAddress, b: CellAddress): CellAddress[] {
} }
return res; return res;
} }
if (colA == 'header' && colB == 'header' && rowA == 'header' && rowB == 'header') {
return [['header', 'header']];
}
return []; return [];
} }
@@ -47,6 +61,7 @@ export function convertCellAddress(row, col): CellAddress {
export function cellFromEvent(event): CellAddress { export function cellFromEvent(event): CellAddress {
const cell = event.target.closest('td'); const cell = event.target.closest('td');
if (!cell) return undefinedCell;
const col = cell.getAttribute('data-col'); const col = cell.getAttribute('data-col');
const row = cell.getAttribute('data-row'); const row = cell.getAttribute('data-row');
return convertCellAddress(row, col); return convertCellAddress(row, col);

View File

@@ -4,4 +4,5 @@ export interface DataGridProps {
conid: number; conid: number;
database: string; database: string;
display: GridDisplay; display: GridDisplay;
isMainGrid?: boolean;
} }

View File

@@ -24,6 +24,7 @@ export default function TableDataTab({ conid, database, schemaName, pureName })
conid={conid} conid={conid}
database={database} database={database}
display={display} display={display}
isMainGrid
/> />
); );
} }

View File

@@ -13,7 +13,7 @@ export default {
end: 35, end: 35,
home: 36, home: 36,
leftArrow: 37, leftArrow: 37,
ppArrow: 38, upArrow: 38,
rightArrow: 39, rightArrow: 39,
downArrow: 40, downArrow: 40,
insert: 45, insert: 45,