diff --git a/packages/datalib/src/GridConfig.ts b/packages/datalib/src/GridConfig.ts index ff94e31e5..d38a468cf 100644 --- a/packages/datalib/src/GridConfig.ts +++ b/packages/datalib/src/GridConfig.ts @@ -20,7 +20,7 @@ export type GroupFunc = 'GROUP' | 'MAX' | 'MIN' | 'SUM' | 'AVG' | 'COUNT' | 'COU export interface GridConfig extends GridConfigColumns { filters: { [uniqueName: string]: string }; - focusedColumn?: string; + focusedColumns?: string[]; columnWidths: { [uniqueName: string]: number }; sort: { uniqueName: string; @@ -48,7 +48,7 @@ export function createGridConfig(): GridConfig { filters: {}, columnWidths: {}, sort: [], - focusedColumn: null, + focusedColumns: null, grouping: {}, formFilterColumns: [], }; diff --git a/packages/datalib/src/GridDisplay.ts b/packages/datalib/src/GridDisplay.ts index 8a32913d5..e347af3e8 100644 --- a/packages/datalib/src/GridDisplay.ts +++ b/packages/datalib/src/GridDisplay.ts @@ -104,10 +104,10 @@ export abstract class GridDisplay { this.includeInColumnSet('addedColumns', name, true); } - focusColumn(uniqueName: string) { + focusColumns(uniqueNames: string[]) { this.setConfig(cfg => ({ ...cfg, - focusedColumn: uniqueName, + focusedColumns: uniqueNames, })); } @@ -115,8 +115,8 @@ export abstract class GridDisplay { return false; } - get focusedColumn() { - return this.config.focusedColumn; + get focusedColumns() { + return this.config.focusedColumns; } get engine() { diff --git a/packages/web/src/datagrid/ColumnManager.svelte b/packages/web/src/datagrid/ColumnManager.svelte index df1cfe2a7..20713a65e 100644 --- a/packages/web/src/datagrid/ColumnManager.svelte +++ b/packages/web/src/datagrid/ColumnManager.svelte @@ -26,48 +26,62 @@ let selectedColumns = []; let currentColumnUniqueName = null; let dragStartColumnIndex = null; + let shiftOriginColumnIndex = null; $: items = display?.getColumns(filter)?.filter(column => filterName(filter, column.columnName)) || []; - function selectColumn(uniqueName) { + function selectColumnIndexCore(index, e) { + const uniqueName = items[index].uniqueName; + if (e.shiftKey) { + const curIndex = _.findIndex(items, x => x.uniqueName == currentColumnUniqueName); + if (curIndex >= 0 && shiftOriginColumnIndex == null) shiftOriginColumnIndex = curIndex; + + selectedColumns = _.range( + Math.min(shiftOriginColumnIndex, index), + Math.max(shiftOriginColumnIndex, index) + 1 + ).map(i => items[i].uniqueName); + } else { + selectedColumns = [uniqueName]; + shiftOriginColumnIndex = null; + } + currentColumnUniqueName = uniqueName; - selectedColumns = [uniqueName]; if (!isJsonView) { - display.focusColumn(uniqueName); + display.focusColumns(selectedColumns); } } - function selectColumnIndex(index) { + function selectColumnIndex(index, e) { if (index >= 0 && index < items.length) { - selectColumn(items[index].uniqueName); + selectColumnIndexCore(index, e); return; } if (items.length == 0) { return; } if (index < 0) { - selectColumn(items[0].uniqueName); + selectColumnIndexCore(0, e); return; } else if (index >= items.length) { - selectColumn(items[items.length - 1].uniqueName); + selectColumnIndexCore(items.length - 1, e); return; } } - function moveIndex(indexFunc) { + function moveIndex(indexFunc, e) { const index = _.findIndex(items, x => x.uniqueName == currentColumnUniqueName); if (index >= 0) { - selectColumnIndex(indexFunc(index)); + selectColumnIndex(indexFunc(index), e); } } function handleKeyDown(e) { - if (e.keyCode == keycodes.upArrow) moveIndex(i => i - 1); - else if (e.keyCode == keycodes.downArrow) moveIndex(i => i + 1); - else if (e.keyCode == keycodes.home) moveIndex(() => 0); - else if (e.keyCode == keycodes.end) moveIndex(() => items.length - 1); - else if (e.keyCode == keycodes.pageUp) moveIndex(i => i - 10); - else if (e.keyCode == keycodes.pageDown) moveIndex(i => i + 10); + if (e.keyCode == keycodes.upArrow) moveIndex(i => i - 1, e); + else if (e.keyCode == keycodes.downArrow) moveIndex(i => i + 1, e); + else if (e.keyCode == keycodes.home) moveIndex(() => 0, e); + else if (e.keyCode == keycodes.end) moveIndex(() => items.length - 1, e); + else if (e.keyCode == keycodes.pageUp) moveIndex(i => i - 10, e); + else if (e.keyCode == keycodes.pageDown) moveIndex(i => i + 10, e); else if (e.keyCode == keycodes.space) { let checked = null; for (const name of selectedColumns) { @@ -143,7 +157,7 @@ ).map(i => items[i].uniqueName); currentColumnUniqueName = column.uniqueName; if (!isJsonView) { - display.focusColumn(column.uniqueName); + display.focusColumns([currentColumnUniqueName, ...selectedColumns]); } } } @@ -154,7 +168,7 @@ if (domFocusField) domFocusField.focus(); currentColumnUniqueName = column.uniqueName; if (!isJsonView) { - display.focusColumn(column.uniqueName); + display.focusColumns(selectedColumns); } }} on:mouseup={e => { diff --git a/packages/web/src/datagrid/ColumnManagerRow.svelte b/packages/web/src/datagrid/ColumnManagerRow.svelte index 63b028e1f..7e722b2ba 100644 --- a/packages/web/src/datagrid/ColumnManagerRow.svelte +++ b/packages/web/src/datagrid/ColumnManagerRow.svelte @@ -19,7 +19,7 @@ // @ts-ignore if (e.target.closest('.expandColumnIcon')) return; if (isJsonView) display.showFilter(column.uniqueName); - else display.focusColumn(column.uniqueName); + else display.focusColumns([column.uniqueName]); }} class:isSelected on:click diff --git a/packages/web/src/datagrid/DataGridCore.svelte b/packages/web/src/datagrid/DataGridCore.svelte index 5a5725b0d..6ef9b98f0 100644 --- a/packages/web/src/datagrid/DataGridCore.svelte +++ b/packages/web/src/datagrid/DataGridCore.svelte @@ -740,9 +740,9 @@ $: { tick().then(() => { - if (display && display.focusedColumn) { + if (display?.focusedColumns?.length > 0) { const invMap = _.invert(realColumnUniqueNames); - const colIndex = invMap[display.focusedColumn]; + const colIndex = invMap[display.focusedColumns[0]]; if (colIndex) { scrollIntoView([null, colIndex]); } @@ -908,7 +908,7 @@ } } - if (display.focusedColumn) display.focusColumn(null); + if (display.focusedColumns) display.focusColumns(null); } function handleGridMouseMove(event) { @@ -1490,7 +1490,7 @@ {isDynamicStructure} selectedCells={filterCellsForRow(selectedCells, rowIndex)} autofillMarkerCell={filterCellForRow(autofillMarkerCell, rowIndex)} - focusedColumn={display.focusedColumn} + focusedColumns={display.focusedColumns} inplaceEditorState={$inplaceEditorState} currentCellColumn={currentCell && currentCell[0] == rowIndex ? currentCell[1] : null} {dispatchInsplaceEditor} diff --git a/packages/web/src/datagrid/DataGridRow.svelte b/packages/web/src/datagrid/DataGridRow.svelte index 1bdb36634..a2c7652ac 100644 --- a/packages/web/src/datagrid/DataGridRow.svelte +++ b/packages/web/src/datagrid/DataGridRow.svelte @@ -17,7 +17,7 @@ export let selectedCells = undefined; export let autofillSelectedCells = undefined; export let autofillMarkerCell = undefined; - export let focusedColumn = undefined; + export let focusedColumns = undefined; export let inplaceEditorState; export let dispatchInsplaceEditor; export let onSetFormView; @@ -75,7 +75,7 @@ isCurrentCell={col.colIndex == currentCellColumn} isFrameSelected={frameSelection ? cellIsSelected(rowIndex, col.colIndex, selectedCells) : false} isAutofillSelected={cellIsSelected(rowIndex, col.colIndex, autofillSelectedCells)} - isFocusedColumn={col.uniqueName == focusedColumn} + isFocusedColumn={focusedColumns?.includes(col.uniqueName)} isModifiedCell={rowStatus.modifiedFields && rowStatus.modifiedFields.has(col.uniqueName)} isModifiedRow={rowStatus.status == 'updated'} isInserted={rowStatus.status == 'inserted' ||