diff --git a/packages/web/src/datagrid/DataGridRow.js b/packages/web/src/datagrid/DataGridRow.js
index d213162ef..a4759f600 100644
--- a/packages/web/src/datagrid/DataGridRow.js
+++ b/packages/web/src/datagrid/DataGridRow.js
@@ -154,7 +154,7 @@ function highlightSpecialCharacters(value) {
const dateTimeRegex = /^\d\d\d\d-\d\d-\d\dT\d\d:\d\d:\d\d(\.\d\d\d)?Z?$/;
-function CellFormattedValue({ value, dataType }) {
+export function CellFormattedValue({ value, dataType }) {
if (value == null) return (NULL);
if (_.isDate(value)) return moment(value).format('YYYY-MM-DD HH:mm:ss');
if (value === true) return '1';
diff --git a/packages/web/src/formview/FormView.js b/packages/web/src/formview/FormView.js
index 48d3dfa00..95b2a2e14 100644
--- a/packages/web/src/formview/FormView.js
+++ b/packages/web/src/formview/FormView.js
@@ -7,6 +7,11 @@ import styled from 'styled-components';
import useTheme from '../theme/useTheme';
import useDimensions from '../utility/useDimensions';
import FormViewToolbar from './FormViewToolbar';
+import { useShowMenu } from '../modals/showMenu';
+import FormViewContextMenu from './FormViewContextMenu';
+import keycodes from '../utility/keycodes';
+import { CellFormattedValue } from '../datagrid/DataGridRow';
+import { cellFromEvent } from '../datagrid/selection';
const Table = styled.table`
border-collapse: collapse;
@@ -40,6 +45,14 @@ const TableHeaderCell = styled.td`
background-color: ${(props) => props.theme.gridheader_background};
overflow: hidden;
position: relative;
+
+ ${(props) =>
+ // @ts-ignore
+ props.isSelected &&
+ `
+ background: initial;
+ background-color: ${props.theme.gridbody_selection[4]};
+ color: ${props.theme.gridbody_invfont1};`}
`;
const TableBodyCell = styled.td`
@@ -50,6 +63,14 @@ const TableBodyCell = styled.td`
white-space: nowrap;
position: relative;
overflow: hidden;
+
+ ${(props) =>
+ // @ts-ignore
+ props.isSelected &&
+ `
+ background: initial;
+ background-color: ${props.theme.gridbody_selection[4]};
+ color: ${props.theme.gridbody_invfont1};`}
`;
const HintSpan = styled.span`
@@ -61,6 +82,13 @@ const NullSpan = styled.span`
font-style: italic;
`;
+const FocusField = styled.input`
+ // visibility: hidden
+ position: absolute;
+ left: -1000px;
+ top: -1000px;
+`;
+
export default function FormView(props) {
const { rowData, toolbarPortalRef, tabVisible, config, setConfig, onNavigate } = props;
/** @type {import('dbgate-datalib').FormViewDisplay} */
@@ -68,6 +96,12 @@ export default function FormView(props) {
const theme = useTheme();
const [headerRowRef, { height: rowHeight }] = useDimensions();
const [wrapperRef, { height: wrapperHeight }] = useDimensions();
+ const showMenu = useShowMenu();
+ const focusFieldRef = React.useRef(null);
+ const [currentCell, setCurrentCell] = React.useState([0, 0]);
+
+ const rowCount = Math.floor((wrapperHeight - 20) / rowHeight);
+ const columnChunks = _.chunk(formDisplay.columns, rowCount);
const handleSwitchToTable = () => {
setConfig((cfg) => ({
@@ -77,6 +111,99 @@ export default function FormView(props) {
}));
};
+ const handleContextMenu = (event) => {
+ event.preventDefault();
+ showMenu(
+ event.pageX,
+ event.pageY,
+
+ );
+ };
+
+ React.useEffect(() => {
+ if (tabVisible) {
+ if (focusFieldRef.current) focusFieldRef.current.focus();
+ }
+ }, [tabVisible, focusFieldRef.current]);
+
+ const moveCursor = (row, col) => {
+ if (row < 0) row = 0;
+ if (col < 0) col = 0;
+ if (col >= columnChunks.length * 2) col = columnChunks.length * 2 - 1;
+ const chunk = columnChunks[Math.floor(col / 2)];
+ if (chunk && row >= chunk.length) row = chunk.length - 1;
+ return [row, col];
+ };
+
+ const handleCursorMove = (event) => {
+ switch (event.keyCode) {
+ case keycodes.leftArrow:
+ return moveCursor(currentCell[0], currentCell[1] - 1);
+ case keycodes.rightArrow:
+ return moveCursor(currentCell[0], currentCell[1] + 1);
+ case keycodes.upArrow:
+ return moveCursor(currentCell[0] - 1, currentCell[1]);
+ case keycodes.downArrow:
+ return moveCursor(currentCell[0] + 1, currentCell[1]);
+ case keycodes.pageUp:
+ return moveCursor(0, currentCell[1]);
+ case keycodes.pageDown:
+ return moveCursor(rowCount - 1, currentCell[1]);
+ case keycodes.home:
+ return moveCursor(0, 0);
+ case keycodes.end:
+ return moveCursor(rowCount - 1, columnChunks.length * 2 - 1);
+ }
+ };
+
+ const handleKeyNavigation = (event) => {
+ if (event.ctrlKey) {
+ switch (event.keyCode) {
+ case keycodes.leftArrow:
+ case keycodes.upArrow:
+ return 'previous';
+ case keycodes.rightArrow:
+ case keycodes.downArrow:
+ return 'next';
+ case keycodes.home:
+ return 'begin';
+ case keycodes.end:
+ return 'end';
+ }
+ }
+ };
+
+ const handleKeyDown = (event) => {
+ const navigation = handleKeyNavigation(event);
+ if (navigation) {
+ event.preventDefault();
+ onNavigate(navigation);
+ return;
+ }
+ const moved = handleCursorMove(event);
+ if (moved) {
+ setCurrentCell(moved);
+ event.preventDefault();
+ return;
+ }
+ };
+
+ const handleTableMouseDown = (event) => {
+ event.preventDefault();
+ if (focusFieldRef.current) focusFieldRef.current.focus();
+
+ if (event.target.closest('.buttonLike')) return;
+ if (event.target.closest('.resizeHandleControl')) return;
+ if (event.target.closest('input')) return;
+
+ // event.target.closest('table').focus();
+ event.preventDefault();
+ if (focusFieldRef.current) focusFieldRef.current.focus();
+ const cell = cellFromEvent(event);
+ // @ts-ignore
+ setCurrentCell(cell);
+ };
+
const toolbar =
toolbarPortalRef &&
toolbarPortalRef.current &&
@@ -86,28 +213,39 @@ export default function FormView(props) {
toolbarPortalRef.current
);
- // console.log('display', display);
-
if (!formDisplay || !formDisplay.isLoadedCorrectly) return toolbar;
- const rowCount = Math.floor((wrapperHeight - 20) / rowHeight);
- const columnChunks = _.chunk(formDisplay.columns, rowCount);
-
return (
-
- {columnChunks.map((chunk, index) => (
-
- {chunk.map((col) => (
+
+ {columnChunks.map((chunk, chunkIndex) => (
+
+ {chunk.map((col, rowIndex) => (
-
+
- {rowData && rowData[col.columnName]}
+
+
+
))}
))}
+
+
{toolbar}
);
diff --git a/packages/web/src/formview/FormViewContextMenu.js b/packages/web/src/formview/FormViewContextMenu.js
new file mode 100644
index 000000000..44ff19400
--- /dev/null
+++ b/packages/web/src/formview/FormViewContextMenu.js
@@ -0,0 +1,15 @@
+import React from 'react';
+import { DropDownMenuItem, DropDownMenuDivider } from '../modals/DropDownMenu';
+
+export default function FormViewContextMenu({ switchToTable, onNavigate }) {
+ return (
+ <>
+ Table view
+
+ onNavigate('begin')}>Navigate to begin
+ onNavigate('previous')}>Navigate to previous
+ onNavigate('next')}>Navigate to next
+ onNavigate('end')}>Navigate to end
+ >
+ );
+}