mirror of
https://github.com/DeNNiiInc/dbgate.git
synced 2026-05-03 08:13:57 +00:00
datagrid selection
This commit is contained in:
@@ -31,6 +31,7 @@
|
|||||||
export let isModifiedCell = false;
|
export let isModifiedCell = false;
|
||||||
export let isInserted = false;
|
export let isInserted = false;
|
||||||
export let isDeleted = false;
|
export let isDeleted = false;
|
||||||
|
export let isAutofillSelected = false;
|
||||||
|
|
||||||
$: value = (rowData || {})[col.uniqueName];
|
$: value = (rowData || {})[col.uniqueName];
|
||||||
</script>
|
</script>
|
||||||
@@ -44,6 +45,7 @@
|
|||||||
class:isModifiedCell
|
class:isModifiedCell
|
||||||
class:isInserted
|
class:isInserted
|
||||||
class:isDeleted
|
class:isDeleted
|
||||||
|
class:isAutofillSelected
|
||||||
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`}
|
||||||
>
|
>
|
||||||
{#if value == null}
|
{#if value == null}
|
||||||
@@ -101,6 +103,10 @@
|
|||||||
outline: 3px solid var(--theme-bg-selected);
|
outline: 3px solid var(--theme-bg-selected);
|
||||||
outline-offset: -3px;
|
outline-offset: -3px;
|
||||||
}
|
}
|
||||||
|
td.isAutofillSelected {
|
||||||
|
outline: 3px solid var(--theme-bg-selected);
|
||||||
|
outline-offset: -3px;
|
||||||
|
}
|
||||||
td.isModifiedRow {
|
td.isModifiedRow {
|
||||||
background: var(--theme-bg-gold);
|
background: var(--theme-bg-gold);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,8 +3,15 @@
|
|||||||
import _ from 'lodash';
|
import _ from 'lodash';
|
||||||
import ColumnHeaderControl from './ColumnHeaderControl.svelte';
|
import ColumnHeaderControl from './ColumnHeaderControl.svelte';
|
||||||
import DataGridRow from './DataGridRow.svelte';
|
import DataGridRow from './DataGridRow.svelte';
|
||||||
import { countColumnSizes, countVisibleRealColumns } from './gridutil';
|
import {
|
||||||
|
cellIsSelected,
|
||||||
|
countColumnSizes,
|
||||||
|
countVisibleRealColumns,
|
||||||
|
filterCellForRow,
|
||||||
|
filterCellsForRow,
|
||||||
|
} from './gridutil';
|
||||||
import HorizontalScrollBar from './HorizontalScrollBar.svelte';
|
import HorizontalScrollBar from './HorizontalScrollBar.svelte';
|
||||||
|
import { cellFromEvent, emptyCellArray, getCellRange, isRegularCell, nullCell, topLeftCell } from './selection';
|
||||||
import VerticalScrollBar from './VerticalScrollBar.svelte';
|
import VerticalScrollBar from './VerticalScrollBar.svelte';
|
||||||
|
|
||||||
export let loadNextData = undefined;
|
export let loadNextData = undefined;
|
||||||
@@ -12,12 +19,32 @@
|
|||||||
export let display: GridDisplay = undefined;
|
export let display: GridDisplay = undefined;
|
||||||
export let conid = undefined;
|
export let conid = undefined;
|
||||||
export let database = undefined;
|
export let database = undefined;
|
||||||
|
export let frameSelection = undefined;
|
||||||
|
|
||||||
|
const wheelRowCount = 5;
|
||||||
|
|
||||||
let containerHeight = 0;
|
let containerHeight = 0;
|
||||||
let containerWidth = 0;
|
let containerWidth = 0;
|
||||||
let rowHeight = 0;
|
let rowHeight = 0;
|
||||||
let firstVisibleRowScrollIndex = 0;
|
let firstVisibleRowScrollIndex = 0;
|
||||||
let firstVisibleColumnScrollIndex = 0;
|
let firstVisibleColumnScrollIndex = 0;
|
||||||
|
|
||||||
|
let domFocusField;
|
||||||
|
let domHorizontalScroll;
|
||||||
|
let domVerticalScroll;
|
||||||
|
|
||||||
|
let currentCell = topLeftCell;
|
||||||
|
let selectedCells = [topLeftCell];
|
||||||
|
let dragStartCell = nullCell;
|
||||||
|
let shiftDragStartCell = nullCell;
|
||||||
|
let autofillDragStartCell = nullCell;
|
||||||
|
let autofillSelectedCells = emptyCellArray;
|
||||||
|
|
||||||
|
$: autofillMarkerCell =
|
||||||
|
selectedCells && selectedCells.length > 0 && _.uniq(selectedCells.map(x => x[0])).length == 1
|
||||||
|
? [_.max(selectedCells.map(x => x[0])), _.max(selectedCells.map(x => x[1]))]
|
||||||
|
: null;
|
||||||
|
|
||||||
// $: firstVisibleRowScrollIndex = 0;
|
// $: firstVisibleRowScrollIndex = 0;
|
||||||
// $: visibleRowCountUpperBound = 25;
|
// $: visibleRowCountUpperBound = 25;
|
||||||
|
|
||||||
@@ -57,11 +84,119 @@
|
|||||||
loadNextData();
|
loadNextData();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function handleGridMouseDown(event) {
|
||||||
|
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 (domFocusField) domFocusField.focus();
|
||||||
|
const cell = cellFromEvent(event);
|
||||||
|
|
||||||
|
if (event.button == 2 && cell && cellIsSelected(cell[0], cell[1], selectedCells)) return;
|
||||||
|
|
||||||
|
const autofill = event.target.closest('div.autofillHandleMarker');
|
||||||
|
if (autofill) {
|
||||||
|
autofillDragStartCell = cell;
|
||||||
|
} else {
|
||||||
|
currentCell = cell;
|
||||||
|
|
||||||
|
if (event.ctrlKey) {
|
||||||
|
if (isRegularCell(cell)) {
|
||||||
|
if (selectedCells.find(x => x[0] == cell[0] && x[1] == cell[1])) {
|
||||||
|
selectedCells = selectedCells.filter(x => x[0] != cell[0] || x[1] != cell[1]);
|
||||||
|
} else {
|
||||||
|
selectedCells = [...selectedCells, cell];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
selectedCells = getCellRange(cell, cell);
|
||||||
|
dragStartCell = cell;
|
||||||
|
|
||||||
|
// if (isRegularCell(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' });
|
||||||
|
// }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (display.focusedColumn) display.focusColumn(null);
|
||||||
|
}
|
||||||
|
|
||||||
|
function handleGridMouseMove(event) {
|
||||||
|
if (autofillDragStartCell) {
|
||||||
|
const cell = cellFromEvent(event);
|
||||||
|
if (isRegularCell(cell) && (cell[0] == autofillDragStartCell[0] || cell[1] == autofillDragStartCell[1])) {
|
||||||
|
const autoFillStart = [selectedCells[0][0], _.min(selectedCells.map(x => x[1]))];
|
||||||
|
// @ts-ignore
|
||||||
|
autofillSelectedCells = getCellRange(autoFillStart, cell);
|
||||||
|
}
|
||||||
|
} else if (dragStartCell) {
|
||||||
|
const cell = cellFromEvent(event);
|
||||||
|
currentCell = cell;
|
||||||
|
selectedCells = getCellRange(dragStartCell, cell);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function handleGridMouseUp(event) {
|
||||||
|
if (dragStartCell) {
|
||||||
|
const cell = cellFromEvent(event);
|
||||||
|
currentCell = cell;
|
||||||
|
selectedCells = getCellRange(dragStartCell, cell);
|
||||||
|
dragStartCell = null;
|
||||||
|
}
|
||||||
|
if (autofillDragStartCell) {
|
||||||
|
const currentRowNumber = currentCell[0];
|
||||||
|
if (_.isNumber(currentRowNumber)) {
|
||||||
|
const rowIndexes = _.uniq((autofillSelectedCells || []).map(x => x[0])).filter(x => x != currentRowNumber);
|
||||||
|
const colNames = selectedCells.map(cell => realColumnUniqueNames[cell[1]]);
|
||||||
|
const changeObject = _.pick(grider.getRowData(currentRowNumber), colNames);
|
||||||
|
grider.beginUpdate();
|
||||||
|
for (const index of rowIndexes) grider.updateRow(index, changeObject);
|
||||||
|
grider.endUpdate();
|
||||||
|
}
|
||||||
|
|
||||||
|
autofillDragStartCell = null;
|
||||||
|
autofillSelectedCells = [];
|
||||||
|
selectedCells = autofillSelectedCells;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function handleGridWheel(event) {
|
||||||
|
let newFirstVisibleRowScrollIndex = firstVisibleRowScrollIndex;
|
||||||
|
if (event.deltaY > 0) {
|
||||||
|
newFirstVisibleRowScrollIndex += wheelRowCount;
|
||||||
|
}
|
||||||
|
if (event.deltaY < 0) {
|
||||||
|
newFirstVisibleRowScrollIndex -= wheelRowCount;
|
||||||
|
}
|
||||||
|
let rowCount = grider.rowCount;
|
||||||
|
if (newFirstVisibleRowScrollIndex + visibleRowCountLowerBound > rowCount) {
|
||||||
|
newFirstVisibleRowScrollIndex = rowCount - visibleRowCountLowerBound + 1;
|
||||||
|
}
|
||||||
|
if (newFirstVisibleRowScrollIndex < 0) {
|
||||||
|
newFirstVisibleRowScrollIndex = 0;
|
||||||
|
}
|
||||||
|
firstVisibleRowScrollIndex = newFirstVisibleRowScrollIndex;
|
||||||
|
|
||||||
|
domVerticalScroll.scroll(newFirstVisibleRowScrollIndex);
|
||||||
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<div class="container" bind:clientWidth={containerWidth} bind:clientHeight={containerHeight}>
|
<div class="container" bind:clientWidth={containerWidth} bind:clientHeight={containerHeight}>
|
||||||
<input type="text" class="focus-field" />
|
<input type="text" class="focus-field" bind:this={domFocusField} />
|
||||||
<table class="table">
|
<table
|
||||||
|
class="table"
|
||||||
|
on:mousedown={handleGridMouseDown}
|
||||||
|
on:mousemove={handleGridMouseMove}
|
||||||
|
on:mouseup={handleGridMouseUp}
|
||||||
|
on:wheel={handleGridWheel}
|
||||||
|
>
|
||||||
<thead>
|
<thead>
|
||||||
<tr>
|
<tr>
|
||||||
<td
|
<td
|
||||||
@@ -85,7 +220,16 @@
|
|||||||
</thead>
|
</thead>
|
||||||
<tbody>
|
<tbody>
|
||||||
{#each _.range(firstVisibleRowScrollIndex, firstVisibleRowScrollIndex + visibleRowCountUpperBound) as rowIndex (rowIndex)}
|
{#each _.range(firstVisibleRowScrollIndex, firstVisibleRowScrollIndex + visibleRowCountUpperBound) as rowIndex (rowIndex)}
|
||||||
<DataGridRow {rowIndex} {grider} {visibleRealColumns} {rowHeight} />
|
<DataGridRow
|
||||||
|
{rowIndex}
|
||||||
|
{grider}
|
||||||
|
{visibleRealColumns}
|
||||||
|
{rowHeight}
|
||||||
|
{autofillSelectedCells}
|
||||||
|
selectedCells={filterCellsForRow(selectedCells, rowIndex)}
|
||||||
|
autofillMarkerCell={filterCellForRow(autofillMarkerCell, rowIndex)}
|
||||||
|
{frameSelection}
|
||||||
|
/>
|
||||||
{/each}
|
{/each}
|
||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
@@ -94,12 +238,14 @@
|
|||||||
maximum={maxScrollColumn}
|
maximum={maxScrollColumn}
|
||||||
viewportRatio={gridScrollAreaWidth / columnSizes.getVisibleScrollSizeSum()}
|
viewportRatio={gridScrollAreaWidth / columnSizes.getVisibleScrollSizeSum()}
|
||||||
on:scroll={e => (firstVisibleColumnScrollIndex = e.detail)}
|
on:scroll={e => (firstVisibleColumnScrollIndex = e.detail)}
|
||||||
|
bind:this={domHorizontalScroll}
|
||||||
/>
|
/>
|
||||||
<VerticalScrollBar
|
<VerticalScrollBar
|
||||||
minimum={0}
|
minimum={0}
|
||||||
maximum={grider.rowCount - visibleRowCountUpperBound + 2}
|
maximum={grider.rowCount - visibleRowCountUpperBound + 2}
|
||||||
viewportRatio={visibleRowCountUpperBound / grider.rowCount}
|
viewportRatio={visibleRowCountUpperBound / grider.rowCount}
|
||||||
on:scroll={e => (firstVisibleRowScrollIndex = e.detail)}
|
on:scroll={e => (firstVisibleRowScrollIndex = e.detail)}
|
||||||
|
bind:this={domVerticalScroll}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import DataGridCell from './DataGridCell.svelte';
|
import DataGridCell from './DataGridCell.svelte';
|
||||||
|
import { cellIsSelected } from './gridutil';
|
||||||
|
|
||||||
import RowHeaderCell from './RowHeaderCell.svelte';
|
import RowHeaderCell from './RowHeaderCell.svelte';
|
||||||
|
|
||||||
@@ -7,6 +8,9 @@
|
|||||||
export let rowIndex;
|
export let rowIndex;
|
||||||
export let visibleRealColumns: any[];
|
export let visibleRealColumns: any[];
|
||||||
export let grider;
|
export let grider;
|
||||||
|
export let frameSelection = undefined;
|
||||||
|
export let selectedCells = undefined;
|
||||||
|
export let autofillSelectedCells = undefined;
|
||||||
|
|
||||||
$: rowData = grider.getRowData(rowIndex);
|
$: rowData = grider.getRowData(rowIndex);
|
||||||
$: rowStatus = grider.getRowStatus(rowIndex);
|
$: rowStatus = grider.getRowStatus(rowIndex);
|
||||||
@@ -23,7 +27,15 @@
|
|||||||
<tr style={`height: ${rowHeight}px`}>
|
<tr style={`height: ${rowHeight}px`}>
|
||||||
<RowHeaderCell {rowIndex} />
|
<RowHeaderCell {rowIndex} />
|
||||||
{#each visibleRealColumns as col (col.uniqueName)}
|
{#each visibleRealColumns as col (col.uniqueName)}
|
||||||
<DataGridCell {rowIndex} {rowData} {col} {hintFieldsAllowed} />
|
<DataGridCell
|
||||||
|
{rowIndex}
|
||||||
|
{rowData}
|
||||||
|
{col}
|
||||||
|
{hintFieldsAllowed}
|
||||||
|
isSelected={frameSelection ? false : cellIsSelected(rowIndex, col.colIndex, selectedCells)}
|
||||||
|
isFrameSelected={frameSelection ? cellIsSelected(rowIndex, col.colIndex, selectedCells) : false}
|
||||||
|
isAutofillSelected={cellIsSelected(rowIndex, col.colIndex, autofillSelectedCells)}
|
||||||
|
/>
|
||||||
{/each}
|
{/each}
|
||||||
</tr>
|
</tr>
|
||||||
|
|
||||||
|
|||||||
@@ -17,6 +17,12 @@
|
|||||||
const res = ratio * (maximum - minimum + 1) + minimum;
|
const res = ratio * (maximum - minimum + 1) + minimum;
|
||||||
dispatch('scroll', Math.floor(res + 0.3));
|
dispatch('scroll', Math.floor(res + 0.3));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function scroll(value) {
|
||||||
|
const position01 = (value - minimum) / (maximum - minimum + 1);
|
||||||
|
const position = position01 * (contentSize - width);
|
||||||
|
if (node) node.scrollLeft = Math.floor(position);
|
||||||
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<div bind:clientWidth={width} bind:this={node} on:scroll={handleScroll} class="main">
|
<div bind:clientWidth={width} bind:this={node} on:scroll={handleScroll} class="main">
|
||||||
|
|||||||
@@ -17,6 +17,12 @@
|
|||||||
let res = ratio * (maximum - minimum + 1) + minimum;
|
let res = ratio * (maximum - minimum + 1) + minimum;
|
||||||
dispatch('scroll', Math.floor(res + 0.3));
|
dispatch('scroll', Math.floor(res + 0.3));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function scroll(value) {
|
||||||
|
const position01 = (value - minimum) / (maximum - minimum + 1);
|
||||||
|
const position = position01 * (contentSize - height);
|
||||||
|
if (node) node.scrollTop = Math.floor(position);
|
||||||
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<div bind:clientHeight={height} bind:this={node} on:scroll={handleScroll} class="main">
|
<div bind:clientHeight={height} bind:this={node} on:scroll={handleScroll} class="main">
|
||||||
|
|||||||
Reference in New Issue
Block a user