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 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 (
<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>
<TableHeaderRow ref={headerRowRef}>
<TableHeaderCell data-row="header" data-col="header" />

View File

@@ -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);

View File

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

View File

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

View File

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