mirror of
https://github.com/DeNNiiInc/dbgate.git
synced 2026-04-29 08:43:57 +00:00
key handling
This commit is contained in:
@@ -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" />
|
||||||
|
|||||||
@@ -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);
|
||||||
|
|||||||
@@ -4,4 +4,5 @@ export interface DataGridProps {
|
|||||||
conid: number;
|
conid: number;
|
||||||
database: string;
|
database: string;
|
||||||
display: GridDisplay;
|
display: GridDisplay;
|
||||||
|
isMainGrid?: boolean;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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,
|
||||||
|
|||||||
Reference in New Issue
Block a user