mirror of
https://github.com/DeNNiiInc/dbgate.git
synced 2026-05-02 14:53:58 +00:00
form view - inplace editor
This commit is contained in:
@@ -291,9 +291,10 @@ function DataGridRow(props) {
|
|||||||
inplaceEditorState={inplaceEditorState}
|
inplaceEditorState={inplaceEditorState}
|
||||||
dispatchInsplaceEditor={dispatchInsplaceEditor}
|
dispatchInsplaceEditor={dispatchInsplaceEditor}
|
||||||
cellValue={rowData[col.uniqueName]}
|
cellValue={rowData[col.uniqueName]}
|
||||||
grider={grider}
|
// grider={grider}
|
||||||
rowIndex={rowIndex}
|
// rowIndex={rowIndex}
|
||||||
uniqueName={col.uniqueName}
|
// uniqueName={col.uniqueName}
|
||||||
|
onSetValue={(value) => grider.setCellValue(rowIndex, col.uniqueName, value)}
|
||||||
/>
|
/>
|
||||||
) : (
|
) : (
|
||||||
<>
|
<>
|
||||||
|
|||||||
@@ -14,12 +14,13 @@ const StyledInput = styled.input`
|
|||||||
|
|
||||||
export default function InplaceEditor({
|
export default function InplaceEditor({
|
||||||
widthPx,
|
widthPx,
|
||||||
rowIndex,
|
// rowIndex,
|
||||||
uniqueName,
|
// uniqueName,
|
||||||
grider,
|
// grider,
|
||||||
cellValue,
|
cellValue,
|
||||||
inplaceEditorState,
|
inplaceEditorState,
|
||||||
dispatchInsplaceEditor,
|
dispatchInsplaceEditor,
|
||||||
|
onSetValue,
|
||||||
}) {
|
}) {
|
||||||
const editorRef = React.useRef();
|
const editorRef = React.useRef();
|
||||||
const isChangedRef = React.useRef(!!inplaceEditorState.text);
|
const isChangedRef = React.useRef(!!inplaceEditorState.text);
|
||||||
@@ -34,7 +35,8 @@ export default function InplaceEditor({
|
|||||||
function handleBlur() {
|
function handleBlur() {
|
||||||
if (isChangedRef.current) {
|
if (isChangedRef.current) {
|
||||||
const editor = editorRef.current;
|
const editor = editorRef.current;
|
||||||
grider.setCellValue(rowIndex, uniqueName, editor.value);
|
onSetValue(editor.value);
|
||||||
|
// grider.setCellValue(rowIndex, uniqueName, editor.value);
|
||||||
isChangedRef.current = false;
|
isChangedRef.current = false;
|
||||||
}
|
}
|
||||||
dispatchInsplaceEditor({ type: 'close' });
|
dispatchInsplaceEditor({ type: 'close' });
|
||||||
@@ -42,7 +44,8 @@ export default function InplaceEditor({
|
|||||||
if (inplaceEditorState.shouldSave) {
|
if (inplaceEditorState.shouldSave) {
|
||||||
const editor = editorRef.current;
|
const editor = editorRef.current;
|
||||||
if (isChangedRef.current) {
|
if (isChangedRef.current) {
|
||||||
grider.setCellValue(rowIndex, uniqueName, editor.value);
|
onSetValue(editor.value);
|
||||||
|
// grider.setCellValue(rowIndex, uniqueName, editor.value);
|
||||||
isChangedRef.current = false;
|
isChangedRef.current = false;
|
||||||
}
|
}
|
||||||
editor.blur();
|
editor.blur();
|
||||||
@@ -57,7 +60,8 @@ export default function InplaceEditor({
|
|||||||
break;
|
break;
|
||||||
case keycodes.enter:
|
case keycodes.enter:
|
||||||
if (isChangedRef.current) {
|
if (isChangedRef.current) {
|
||||||
grider.setCellValue(rowIndex, uniqueName, editor.value);
|
// grider.setCellValue(rowIndex, uniqueName, editor.value);
|
||||||
|
onSetValue(editor.value);
|
||||||
isChangedRef.current = false;
|
isChangedRef.current = false;
|
||||||
}
|
}
|
||||||
editor.blur();
|
editor.blur();
|
||||||
@@ -66,7 +70,8 @@ export default function InplaceEditor({
|
|||||||
case keycodes.s:
|
case keycodes.s:
|
||||||
if (event.ctrlKey) {
|
if (event.ctrlKey) {
|
||||||
if (isChangedRef.current) {
|
if (isChangedRef.current) {
|
||||||
grider.setCellValue(rowIndex, uniqueName, editor.value);
|
onSetValue(editor.value);
|
||||||
|
// grider.setCellValue(rowIndex, uniqueName, editor.value);
|
||||||
isChangedRef.current = false;
|
isChangedRef.current = false;
|
||||||
}
|
}
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
|
|||||||
@@ -12,6 +12,7 @@ import FormViewContextMenu from './FormViewContextMenu';
|
|||||||
import keycodes from '../utility/keycodes';
|
import keycodes from '../utility/keycodes';
|
||||||
import { CellFormattedValue } from '../datagrid/DataGridRow';
|
import { CellFormattedValue } from '../datagrid/DataGridRow';
|
||||||
import { cellFromEvent } from '../datagrid/selection';
|
import { cellFromEvent } from '../datagrid/selection';
|
||||||
|
import InplaceEditor from '../datagrid/InplaceEditor';
|
||||||
|
|
||||||
const Table = styled.table`
|
const Table = styled.table`
|
||||||
border-collapse: collapse;
|
border-collapse: collapse;
|
||||||
@@ -73,15 +74,6 @@ const TableBodyCell = styled.td`
|
|||||||
color: ${props.theme.gridbody_invfont1};`}
|
color: ${props.theme.gridbody_invfont1};`}
|
||||||
`;
|
`;
|
||||||
|
|
||||||
const HintSpan = styled.span`
|
|
||||||
color: gray;
|
|
||||||
margin-left: 5px;
|
|
||||||
`;
|
|
||||||
const NullSpan = styled.span`
|
|
||||||
color: gray;
|
|
||||||
font-style: italic;
|
|
||||||
`;
|
|
||||||
|
|
||||||
const FocusField = styled.input`
|
const FocusField = styled.input`
|
||||||
// visibility: hidden
|
// visibility: hidden
|
||||||
position: absolute;
|
position: absolute;
|
||||||
@@ -89,6 +81,10 @@ const FocusField = styled.input`
|
|||||||
top: -1000px;
|
top: -1000px;
|
||||||
`;
|
`;
|
||||||
|
|
||||||
|
function isDataCell(cell) {
|
||||||
|
return cell[1] % 2 == 1;
|
||||||
|
}
|
||||||
|
|
||||||
export default function FormView(props) {
|
export default function FormView(props) {
|
||||||
const { rowData, toolbarPortalRef, tabVisible, config, setConfig, onNavigate } = props;
|
const { rowData, toolbarPortalRef, tabVisible, config, setConfig, onNavigate } = props;
|
||||||
/** @type {import('dbgate-datalib').FormViewDisplay} */
|
/** @type {import('dbgate-datalib').FormViewDisplay} */
|
||||||
@@ -131,7 +127,7 @@ export default function FormView(props) {
|
|||||||
}
|
}
|
||||||
}, [tabVisible, focusFieldRef.current]);
|
}, [tabVisible, focusFieldRef.current]);
|
||||||
|
|
||||||
const moveCursor = (row, col) => {
|
const checkMoveCursorBounds = (row, col) => {
|
||||||
if (row < 0) row = 0;
|
if (row < 0) row = 0;
|
||||||
if (col < 0) col = 0;
|
if (col < 0) col = 0;
|
||||||
if (col >= columnChunks.length * 2) col = columnChunks.length * 2 - 1;
|
if (col >= columnChunks.length * 2) col = columnChunks.length * 2 - 1;
|
||||||
@@ -144,28 +140,28 @@ export default function FormView(props) {
|
|||||||
if (event.ctrlKey) {
|
if (event.ctrlKey) {
|
||||||
switch (event.keyCode) {
|
switch (event.keyCode) {
|
||||||
case keycodes.leftArrow:
|
case keycodes.leftArrow:
|
||||||
return moveCursor(currentCell[0], 0);
|
return checkMoveCursorBounds(currentCell[0], 0);
|
||||||
case keycodes.rightArrow:
|
case keycodes.rightArrow:
|
||||||
return moveCursor(currentCell[0], columnChunks.length * 2 - 1);
|
return checkMoveCursorBounds(currentCell[0], columnChunks.length * 2 - 1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
switch (event.keyCode) {
|
switch (event.keyCode) {
|
||||||
case keycodes.leftArrow:
|
case keycodes.leftArrow:
|
||||||
return moveCursor(currentCell[0], currentCell[1] - 1);
|
return checkMoveCursorBounds(currentCell[0], currentCell[1] - 1);
|
||||||
case keycodes.rightArrow:
|
case keycodes.rightArrow:
|
||||||
return moveCursor(currentCell[0], currentCell[1] + 1);
|
return checkMoveCursorBounds(currentCell[0], currentCell[1] + 1);
|
||||||
case keycodes.upArrow:
|
case keycodes.upArrow:
|
||||||
return moveCursor(currentCell[0] - 1, currentCell[1]);
|
return checkMoveCursorBounds(currentCell[0] - 1, currentCell[1]);
|
||||||
case keycodes.downArrow:
|
case keycodes.downArrow:
|
||||||
return moveCursor(currentCell[0] + 1, currentCell[1]);
|
return checkMoveCursorBounds(currentCell[0] + 1, currentCell[1]);
|
||||||
case keycodes.pageUp:
|
case keycodes.pageUp:
|
||||||
return moveCursor(0, currentCell[1]);
|
return checkMoveCursorBounds(0, currentCell[1]);
|
||||||
case keycodes.pageDown:
|
case keycodes.pageDown:
|
||||||
return moveCursor(rowCount - 1, currentCell[1]);
|
return checkMoveCursorBounds(rowCount - 1, currentCell[1]);
|
||||||
case keycodes.home:
|
case keycodes.home:
|
||||||
return moveCursor(0, 0);
|
return checkMoveCursorBounds(0, 0);
|
||||||
case keycodes.end:
|
case keycodes.end:
|
||||||
return moveCursor(rowCount - 1, columnChunks.length * 2 - 1);
|
return checkMoveCursorBounds(rowCount - 1, columnChunks.length * 2 - 1);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -193,6 +189,12 @@ export default function FormView(props) {
|
|||||||
scrollIntoView(currentCell);
|
scrollIntoView(currentCell);
|
||||||
}, [rowData]);
|
}, [rowData]);
|
||||||
|
|
||||||
|
const moveCurrentCell = (row, col) => {
|
||||||
|
const moved = checkMoveCursorBounds(row, col);
|
||||||
|
setCurrentCell(moved);
|
||||||
|
scrollIntoView(moved);
|
||||||
|
};
|
||||||
|
|
||||||
const handleKeyDown = (event) => {
|
const handleKeyDown = (event) => {
|
||||||
const navigation = handleKeyNavigation(event);
|
const navigation = handleKeyNavigation(event);
|
||||||
if (navigation) {
|
if (navigation) {
|
||||||
@@ -207,6 +209,22 @@ export default function FormView(props) {
|
|||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
if (
|
||||||
|
!event.ctrlKey &&
|
||||||
|
!event.altKey &&
|
||||||
|
((event.keyCode >= keycodes.a && event.keyCode <= keycodes.z) ||
|
||||||
|
(event.keyCode >= keycodes.n0 && event.keyCode <= keycodes.n9) ||
|
||||||
|
event.keyCode == keycodes.dash)
|
||||||
|
) {
|
||||||
|
// @ts-ignore
|
||||||
|
dispatchInsplaceEditor({ type: 'show', text: event.nativeEvent.key, cell: currentCell });
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (event.keyCode == keycodes.f2) {
|
||||||
|
// @ts-ignore
|
||||||
|
dispatchInsplaceEditor({ type: 'show', cell: currentCell, selectAll: true });
|
||||||
|
return;
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleTableMouseDown = (event) => {
|
const handleTableMouseDown = (event) => {
|
||||||
@@ -221,10 +239,52 @@ export default function FormView(props) {
|
|||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
if (focusFieldRef.current) focusFieldRef.current.focus();
|
if (focusFieldRef.current) focusFieldRef.current.focus();
|
||||||
const cell = cellFromEvent(event);
|
const cell = cellFromEvent(event);
|
||||||
|
|
||||||
|
if (isDataCell(cell) && !_.isEqual(cell, inplaceEditorState.cell) && _.isEqual(cell, currentCell)) {
|
||||||
|
// @ts-ignore
|
||||||
|
dispatchInsplaceEditor({ type: 'show', cell, selectAll: true });
|
||||||
|
} else if (!_.isEqual(cell, inplaceEditorState.cell)) {
|
||||||
|
// @ts-ignore
|
||||||
|
dispatchInsplaceEditor({ type: 'close' });
|
||||||
|
}
|
||||||
|
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
setCurrentCell(cell);
|
setCurrentCell(cell);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const getCellWidth = (row, col) => {
|
||||||
|
const element = cellRefs.current[`${row},${col}`];
|
||||||
|
if (element) return element.getBoundingClientRect().width;
|
||||||
|
return 100;
|
||||||
|
};
|
||||||
|
|
||||||
|
const [inplaceEditorState, dispatchInsplaceEditor] = React.useReducer((state, action) => {
|
||||||
|
switch (action.type) {
|
||||||
|
case 'show':
|
||||||
|
// if (!grider.editable) return {};
|
||||||
|
return {
|
||||||
|
cell: action.cell,
|
||||||
|
text: action.text,
|
||||||
|
selectAll: action.selectAll,
|
||||||
|
};
|
||||||
|
case 'close': {
|
||||||
|
const [row, col] = currentCell || [];
|
||||||
|
if (focusFieldRef.current) focusFieldRef.current.focus();
|
||||||
|
// @ts-ignore
|
||||||
|
if (action.mode == 'enter' && row) setTimeout(() => moveCurrentCell(row + 1, col), 0);
|
||||||
|
// if (action.mode == 'save') setTimeout(handleSave, 0);
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
case 'shouldSave': {
|
||||||
|
return {
|
||||||
|
...state,
|
||||||
|
shouldSave: true,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return {};
|
||||||
|
}, {});
|
||||||
|
|
||||||
const toolbar =
|
const toolbar =
|
||||||
toolbarPortalRef &&
|
toolbarPortalRef &&
|
||||||
toolbarPortalRef.current &&
|
toolbarPortalRef.current &&
|
||||||
@@ -260,7 +320,24 @@ export default function FormView(props) {
|
|||||||
isSelected={currentCell[0] == rowIndex && currentCell[1] == chunkIndex * 2 + 1}
|
isSelected={currentCell[0] == rowIndex && currentCell[1] == chunkIndex * 2 + 1}
|
||||||
ref={(element) => setCellRef(rowIndex, chunkIndex * 2 + 1, element)}
|
ref={(element) => setCellRef(rowIndex, chunkIndex * 2 + 1, element)}
|
||||||
>
|
>
|
||||||
<CellFormattedValue value={rowData && rowData[col.columnName]} dataType={col.dataType} />
|
{inplaceEditorState.cell &&
|
||||||
|
rowIndex == inplaceEditorState.cell[0] &&
|
||||||
|
chunkIndex * 2 + 1 == inplaceEditorState.cell[1] ? (
|
||||||
|
<InplaceEditor
|
||||||
|
widthPx={getCellWidth(rowIndex, chunkIndex * 2 + 1)}
|
||||||
|
inplaceEditorState={inplaceEditorState}
|
||||||
|
dispatchInsplaceEditor={dispatchInsplaceEditor}
|
||||||
|
cellValue={rowData[col.uniqueName]}
|
||||||
|
onSetValue={(value) => {}}
|
||||||
|
// grider={grider}
|
||||||
|
// rowIndex={rowIndex}
|
||||||
|
// uniqueName={col.uniqueName}
|
||||||
|
/>
|
||||||
|
) : (
|
||||||
|
<>
|
||||||
|
<CellFormattedValue value={rowData && rowData[col.columnName]} dataType={col.dataType} />
|
||||||
|
</>
|
||||||
|
)}
|
||||||
</TableBodyCell>
|
</TableBodyCell>
|
||||||
</TableRow>
|
</TableRow>
|
||||||
))}
|
))}
|
||||||
|
|||||||
Reference in New Issue
Block a user