mirror of
https://github.com/DeNNiiInc/dbgate.git
synced 2026-04-18 00:56:02 +00:00
SYNC: improved data grid navigation
This commit is contained in:
committed by
Diflow
parent
a57063adf7
commit
76ae2e0e5a
@@ -25,6 +25,7 @@
|
|||||||
export let setFilter;
|
export let setFilter;
|
||||||
export let showResizeSplitter = false;
|
export let showResizeSplitter = false;
|
||||||
export let onFocusGrid = null;
|
export let onFocusGrid = null;
|
||||||
|
export let onFocusGridHeader = null;
|
||||||
export let onGetReference = null;
|
export let onGetReference = null;
|
||||||
export let foreignKey = null;
|
export let foreignKey = null;
|
||||||
export let conid = null;
|
export let conid = null;
|
||||||
@@ -204,6 +205,11 @@
|
|||||||
// ev.stopPropagation();
|
// ev.stopPropagation();
|
||||||
ev.preventDefault();
|
ev.preventDefault();
|
||||||
}
|
}
|
||||||
|
if (ev.keyCode == keycodes.upArrow) {
|
||||||
|
if (onFocusGridHeader) onFocusGridHeader();
|
||||||
|
// ev.stopPropagation();
|
||||||
|
ev.preventDefault();
|
||||||
|
}
|
||||||
// if (ev.keyCode == KeyCodes.DownArrow || ev.keyCode == KeyCodes.UpArrow) {
|
// if (ev.keyCode == KeyCodes.DownArrow || ev.keyCode == KeyCodes.UpArrow) {
|
||||||
// if (this.props.onControlKey) this.props.onControlKey(ev.keyCode);
|
// if (this.props.onControlKey) this.props.onControlKey(ev.keyCode);
|
||||||
// }
|
// }
|
||||||
|
|||||||
@@ -380,7 +380,17 @@
|
|||||||
filterCellsForRow,
|
filterCellsForRow,
|
||||||
} from './gridutil';
|
} from './gridutil';
|
||||||
import HorizontalScrollBar from './HorizontalScrollBar.svelte';
|
import HorizontalScrollBar from './HorizontalScrollBar.svelte';
|
||||||
import { cellFromEvent, emptyCellArray, getCellRange, isRegularCell, nullCell, topLeftCell } from './selection';
|
import {
|
||||||
|
cellFromEvent,
|
||||||
|
emptyCellArray,
|
||||||
|
getCellRange,
|
||||||
|
isColumnHeaderCell,
|
||||||
|
isRegularCell,
|
||||||
|
isRowHeaderCell,
|
||||||
|
isTableHeaderCell,
|
||||||
|
nullCell,
|
||||||
|
topLeftCell,
|
||||||
|
} from './selection';
|
||||||
import VerticalScrollBar from './VerticalScrollBar.svelte';
|
import VerticalScrollBar from './VerticalScrollBar.svelte';
|
||||||
import LoadingInfo from '../elements/LoadingInfo.svelte';
|
import LoadingInfo from '../elements/LoadingInfo.svelte';
|
||||||
import InlineButton from '../buttons/InlineButton.svelte';
|
import InlineButton from '../buttons/InlineButton.svelte';
|
||||||
@@ -1305,7 +1315,7 @@
|
|||||||
function scrollIntoView(cell) {
|
function scrollIntoView(cell) {
|
||||||
const [row, col] = cell;
|
const [row, col] = cell;
|
||||||
|
|
||||||
if (row != null) {
|
if (_.isNumber(row)) {
|
||||||
let newRow = null;
|
let newRow = null;
|
||||||
const rowCount = grider.rowCount;
|
const rowCount = grider.rowCount;
|
||||||
if (rowCount == 0) return;
|
if (rowCount == 0) return;
|
||||||
@@ -1323,7 +1333,7 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (col != null) {
|
if (_.isNumber(col)) {
|
||||||
if (col >= columnSizes.frozenCount) {
|
if (col >= columnSizes.frozenCount) {
|
||||||
let newColumn = columnSizes.scrollInView(
|
let newColumn = columnSizes.scrollInView(
|
||||||
firstVisibleColumnScrollIndex,
|
firstVisibleColumnScrollIndex,
|
||||||
@@ -1553,7 +1563,11 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (event.shiftKey) {
|
if (event.shiftKey) {
|
||||||
if (!isRegularCell(shiftDragStartCell)) {
|
if (
|
||||||
|
!isRegularCell(shiftDragStartCell) &&
|
||||||
|
!isColumnHeaderCell(shiftDragStartCell) &&
|
||||||
|
!isRowHeaderCell(shiftDragStartCell)
|
||||||
|
) {
|
||||||
shiftDragStartCell = currentCell;
|
shiftDragStartCell = currentCell;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
@@ -1581,7 +1595,13 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
function handleCursorMove(event) {
|
function handleCursorMove(event) {
|
||||||
if (!isRegularCell(currentCell)) return null;
|
if (
|
||||||
|
!isRegularCell(currentCell) &&
|
||||||
|
!isColumnHeaderCell(currentCell) &&
|
||||||
|
!isRowHeaderCell(currentCell) &&
|
||||||
|
!isTableHeaderCell(currentCell)
|
||||||
|
)
|
||||||
|
return null;
|
||||||
let rowCount = grider.rowCount;
|
let rowCount = grider.rowCount;
|
||||||
if (isCtrlOrCommandKey(event)) {
|
if (isCtrlOrCommandKey(event)) {
|
||||||
switch (event.keyCode) {
|
switch (event.keyCode) {
|
||||||
@@ -1608,24 +1628,36 @@
|
|||||||
switch (event.keyCode) {
|
switch (event.keyCode) {
|
||||||
case keycodes.upArrow:
|
case keycodes.upArrow:
|
||||||
if (currentCell[0] == 0) return focusFilterEditor(currentCell[1]);
|
if (currentCell[0] == 0) return focusFilterEditor(currentCell[1]);
|
||||||
return moveCurrentCell(currentCell[0] - 1, currentCell[1], event);
|
return _.isNumber(currentCell[0]) ? moveCurrentCell(currentCell[0] - 1, currentCell[1], event) : null;
|
||||||
case keycodes.downArrow:
|
case keycodes.downArrow:
|
||||||
return moveCurrentCell(currentCell[0] + 1, currentCell[1], event);
|
if (currentCell[0] == 'header') return focusFilterEditor(currentCell[1]);
|
||||||
|
return _.isNumber(currentCell[0]) ? moveCurrentCell(currentCell[0] + 1, currentCell[1], event) : null;
|
||||||
case keycodes.enter:
|
case keycodes.enter:
|
||||||
if (!grider.editable) return moveCurrentCell(currentCell[0] + 1, currentCell[1], event);
|
if (!grider.editable)
|
||||||
|
return _.isNumber(currentCell[0]) ? moveCurrentCell(currentCell[0] + 1, currentCell[1], event) : null;
|
||||||
break;
|
break;
|
||||||
case keycodes.leftArrow:
|
case keycodes.leftArrow:
|
||||||
return moveCurrentCell(currentCell[0], currentCell[1] - 1, event);
|
return _.isNumber(currentCell[1])
|
||||||
|
? moveCurrentCell(currentCell[0], currentCell[1] == 0 ? 'header' : currentCell[1] - 1, event)
|
||||||
|
: null;
|
||||||
case keycodes.rightArrow:
|
case keycodes.rightArrow:
|
||||||
return moveCurrentCell(currentCell[0], currentCell[1] + 1, event);
|
return currentCell[1] == 'header'
|
||||||
|
? moveCurrentCell(currentCell[0], 0, event)
|
||||||
|
: _.isNumber(currentCell[1])
|
||||||
|
? moveCurrentCell(currentCell[0], currentCell[1] + 1, event)
|
||||||
|
: null;
|
||||||
case keycodes.home:
|
case keycodes.home:
|
||||||
return moveCurrentCell(currentCell[0], 0, event);
|
return moveCurrentCell(currentCell[0], 0, event);
|
||||||
case keycodes.end:
|
case keycodes.end:
|
||||||
return moveCurrentCell(currentCell[0], columnSizes.realCount - 1, event);
|
return moveCurrentCell(currentCell[0], columnSizes.realCount - 1, event);
|
||||||
case keycodes.pageUp:
|
case keycodes.pageUp:
|
||||||
return moveCurrentCell(currentCell[0] - visibleRowCountLowerBound, currentCell[1], event);
|
return _.isNumber(currentCell[0])
|
||||||
|
? moveCurrentCell(currentCell[0] - visibleRowCountLowerBound, currentCell[1], event)
|
||||||
|
: null;
|
||||||
case keycodes.pageDown:
|
case keycodes.pageDown:
|
||||||
return moveCurrentCell(currentCell[0] + visibleRowCountLowerBound, currentCell[1], event);
|
return _.isNumber(currentCell[0])
|
||||||
|
? moveCurrentCell(currentCell[0] + visibleRowCountLowerBound, currentCell[1], event)
|
||||||
|
: null;
|
||||||
case keycodes.tab: {
|
case keycodes.tab: {
|
||||||
return moveCurrentCellWithTabKey(event.shiftKey);
|
return moveCurrentCellWithTabKey(event.shiftKey);
|
||||||
}
|
}
|
||||||
@@ -1659,10 +1691,14 @@
|
|||||||
function moveCurrentCell(row, col, event = null) {
|
function moveCurrentCell(row, col, event = null) {
|
||||||
const rowCount = grider.rowCount;
|
const rowCount = grider.rowCount;
|
||||||
|
|
||||||
if (row < 0) row = 0;
|
if (_.isNumber(row)) {
|
||||||
if (row >= rowCount) row = rowCount - 1;
|
if (row < 0) row = 0;
|
||||||
if (col < 0) col = 0;
|
if (row >= rowCount) row = rowCount - 1;
|
||||||
if (col >= columnSizes.realCount) col = columnSizes.realCount - 1;
|
}
|
||||||
|
if (_.isNumber(col)) {
|
||||||
|
if (col < 0) col = 0;
|
||||||
|
if (col >= columnSizes.realCount) col = columnSizes.realCount - 1;
|
||||||
|
}
|
||||||
currentCell = [row, col];
|
currentCell = [row, col];
|
||||||
// setSelectedCells([...(event.ctrlKey ? selectedCells : []), [row, col]]);
|
// setSelectedCells([...(event.ctrlKey ? selectedCells : []), [row, col]]);
|
||||||
selectedCells = [[row, col]];
|
selectedCells = [[row, col]];
|
||||||
@@ -1782,6 +1818,17 @@
|
|||||||
if (domFocusField) domFocusField.focus();
|
if (domFocusField) domFocusField.focus();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const selectColumnHeaderCell = uniquePath => {
|
||||||
|
const modelIndex = columns.findIndex(x => x.uniquePath == uniquePath);
|
||||||
|
const realIndex = columnSizes.modelToReal(modelIndex);
|
||||||
|
let cell = ['header', realIndex];
|
||||||
|
// @ts-ignore
|
||||||
|
currentCell = cell;
|
||||||
|
// @ts-ignore
|
||||||
|
selectedCells = [cell];
|
||||||
|
if (domFocusField) domFocusField.focus();
|
||||||
|
};
|
||||||
|
|
||||||
const [inplaceEditorState, dispatchInsplaceEditor] = createReducer((state, action) => {
|
const [inplaceEditorState, dispatchInsplaceEditor] = createReducer((state, action) => {
|
||||||
switch (action.type) {
|
switch (action.type) {
|
||||||
case 'show':
|
case 'show':
|
||||||
@@ -2031,6 +2078,7 @@
|
|||||||
data-row="header"
|
data-row="header"
|
||||||
data-col={col.colIndex}
|
data-col={col.colIndex}
|
||||||
style={`width:${col.width}px; min-width:${col.width}px; max-width:${col.width}px`}
|
style={`width:${col.width}px; min-width:${col.width}px; max-width:${col.width}px`}
|
||||||
|
class:active-header-cell={currentCell && currentCell[0] == 'header' && currentCell[1] == col.colIndex}
|
||||||
>
|
>
|
||||||
<ColumnHeaderControl
|
<ColumnHeaderControl
|
||||||
column={col}
|
column={col}
|
||||||
@@ -2105,6 +2153,9 @@
|
|||||||
onFocusGrid={() => {
|
onFocusGrid={() => {
|
||||||
selectTopmostCell(col.uniqueName);
|
selectTopmostCell(col.uniqueName);
|
||||||
}}
|
}}
|
||||||
|
onFocusGridHeader={() => {
|
||||||
|
selectColumnHeaderCell(col.uniqueName);
|
||||||
|
}}
|
||||||
dataType={col.dataType}
|
dataType={col.dataType}
|
||||||
filterDisabled={display.isFilterDisabled(col.uniqueName)}
|
filterDisabled={display.isFilterDisabled(col.uniqueName)}
|
||||||
/>
|
/>
|
||||||
@@ -2231,6 +2282,9 @@
|
|||||||
background-color: var(--theme-bg-1);
|
background-color: var(--theme-bg-1);
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
}
|
}
|
||||||
|
:global(.data-grid-focused) .active-header-cell {
|
||||||
|
background-color: var(--theme-bg-selected);
|
||||||
|
}
|
||||||
.filter-cell {
|
.filter-cell {
|
||||||
text-align: left;
|
text-align: left;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
|
|||||||
@@ -76,6 +76,7 @@
|
|||||||
onShowForm={onSetFormView && !overlayDefinition ? () => onSetFormView(rowData, null) : null}
|
onShowForm={onSetFormView && !overlayDefinition ? () => onSetFormView(rowData, null) : null}
|
||||||
extraIcon={overlayDefinition ? OVERLAY_STATUS_ICONS[rowStatus.status] : null}
|
extraIcon={overlayDefinition ? OVERLAY_STATUS_ICONS[rowStatus.status] : null}
|
||||||
extraIconTooltip={overlayDefinition ? OVERLAY_STATUS_TOOLTIPS[rowStatus.status] : null}
|
extraIconTooltip={overlayDefinition ? OVERLAY_STATUS_TOOLTIPS[rowStatus.status] : null}
|
||||||
|
isSelected={frameSelection ? false : !!selectedCells?.find(cell => cell[0] == rowIndex && cell[1] == 'header')}
|
||||||
/>
|
/>
|
||||||
{#each visibleRealColumns as col (col.uniqueName)}
|
{#each visibleRealColumns as col (col.uniqueName)}
|
||||||
{#if inplaceEditorState.cell && rowIndex == inplaceEditorState.cell[0] && col.colIndex == inplaceEditorState.cell[1]}
|
{#if inplaceEditorState.cell && rowIndex == inplaceEditorState.cell[0] && col.colIndex == inplaceEditorState.cell[1]}
|
||||||
|
|||||||
@@ -7,6 +7,7 @@
|
|||||||
|
|
||||||
export let extraIcon = null;
|
export let extraIcon = null;
|
||||||
export let extraIconTooltip = null;
|
export let extraIconTooltip = null;
|
||||||
|
export let isSelected = false;
|
||||||
|
|
||||||
let mouseIn = false;
|
let mouseIn = false;
|
||||||
</script>
|
</script>
|
||||||
@@ -14,6 +15,7 @@
|
|||||||
<td
|
<td
|
||||||
data-row={rowIndex}
|
data-row={rowIndex}
|
||||||
data-col="header"
|
data-col="header"
|
||||||
|
class:selected={isSelected}
|
||||||
on:mouseenter={() => (mouseIn = true)}
|
on:mouseenter={() => (mouseIn = true)}
|
||||||
on:mouseleave={() => (mouseIn = false)}
|
on:mouseleave={() => (mouseIn = false)}
|
||||||
>
|
>
|
||||||
@@ -43,4 +45,7 @@
|
|||||||
right: 0px;
|
right: 0px;
|
||||||
top: 1px;
|
top: 1px;
|
||||||
}
|
}
|
||||||
|
:global(.data-grid-focused) td.selected {
|
||||||
|
background-color: var(--theme-bg-selected);
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|||||||
@@ -13,6 +13,24 @@ export function isRegularCell(cell: CellAddress): cell is RegularCellAddress {
|
|||||||
return _.isNumber(row) && _.isNumber(col);
|
return _.isNumber(row) && _.isNumber(col);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function isRowHeaderCell(cell: CellAddress): boolean {
|
||||||
|
if (!cell) return false;
|
||||||
|
const [row, col] = cell;
|
||||||
|
return col === 'header' && _.isNumber(row);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function isColumnHeaderCell(cell: CellAddress): boolean {
|
||||||
|
if (!cell) return false;
|
||||||
|
const [row, col] = cell;
|
||||||
|
return row === 'header' && _.isNumber(col);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function isTableHeaderCell(cell: CellAddress): boolean {
|
||||||
|
if (!cell) return false;
|
||||||
|
const [row, col] = cell;
|
||||||
|
return row === 'header' && col === 'header';
|
||||||
|
}
|
||||||
|
|
||||||
function normalizeHeaderForSelection(addr: CellAddress): CellAddress {
|
function normalizeHeaderForSelection(addr: CellAddress): CellAddress {
|
||||||
if (addr[0] == 'filter') return ['header', addr[1]];
|
if (addr[0] == 'filter') return ['header', addr[1]];
|
||||||
return addr;
|
return addr;
|
||||||
|
|||||||
Reference in New Issue
Block a user