Add multi to multi pasting
This commit is contained in:
parent
ad0d300ff9
commit
9657781df6
|
@ -5,9 +5,8 @@ import { parseCellID } from "../lib/utils"
|
||||||
export const createStores = () => {
|
export const createStores = () => {
|
||||||
const clipboard = writable({
|
const clipboard = writable({
|
||||||
value: null,
|
value: null,
|
||||||
multiCellMode: false,
|
multiCellCopy: false,
|
||||||
})
|
})
|
||||||
|
|
||||||
return {
|
return {
|
||||||
clipboard,
|
clipboard,
|
||||||
}
|
}
|
||||||
|
@ -16,10 +15,12 @@ export const createStores = () => {
|
||||||
export const deriveStores = context => {
|
export const deriveStores = context => {
|
||||||
const { clipboard, focusedCellAPI, selectedCellCount } = context
|
const { clipboard, focusedCellAPI, selectedCellCount } = context
|
||||||
|
|
||||||
|
// Derive whether or not we're able to copy
|
||||||
const copyAllowed = derived(focusedCellAPI, $focusedCellAPI => {
|
const copyAllowed = derived(focusedCellAPI, $focusedCellAPI => {
|
||||||
return $focusedCellAPI != null
|
return $focusedCellAPI != null
|
||||||
})
|
})
|
||||||
|
|
||||||
|
// Derive whether or not we're able to paste
|
||||||
const pasteAllowed = derived(
|
const pasteAllowed = derived(
|
||||||
[clipboard, focusedCellAPI, selectedCellCount],
|
[clipboard, focusedCellAPI, selectedCellCount],
|
||||||
([$clipboard, $focusedCellAPI, $selectedCellCount]) => {
|
([$clipboard, $focusedCellAPI, $selectedCellCount]) => {
|
||||||
|
@ -30,7 +31,7 @@ export const deriveStores = context => {
|
||||||
// this cell is readonly
|
// this cell is readonly
|
||||||
const multiCellPaste = $selectedCellCount > 1
|
const multiCellPaste = $selectedCellCount > 1
|
||||||
if (
|
if (
|
||||||
!$clipboard.multiCellMode &&
|
!$clipboard.multiCellCopy &&
|
||||||
!multiCellPaste &&
|
!multiCellPaste &&
|
||||||
$focusedCellAPI.isReadonly()
|
$focusedCellAPI.isReadonly()
|
||||||
) {
|
) {
|
||||||
|
@ -49,33 +50,80 @@ export const deriveStores = context => {
|
||||||
export const createActions = context => {
|
export const createActions = context => {
|
||||||
const {
|
const {
|
||||||
clipboard,
|
clipboard,
|
||||||
selectedCellCount,
|
|
||||||
focusedCellAPI,
|
focusedCellAPI,
|
||||||
copyAllowed,
|
copyAllowed,
|
||||||
pasteAllowed,
|
pasteAllowed,
|
||||||
rows,
|
|
||||||
selectedCells,
|
selectedCells,
|
||||||
|
rowLookupMap,
|
||||||
|
rowChangeCache,
|
||||||
|
rows,
|
||||||
|
columnLookupMap,
|
||||||
} = context
|
} = context
|
||||||
|
|
||||||
|
// Copies the currently selected value (or values)
|
||||||
const copy = () => {
|
const copy = () => {
|
||||||
if (!get(copyAllowed)) {
|
if (!get(copyAllowed)) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
const $selectedCellCount = get(selectedCellCount)
|
const cellIds = Object.keys(get(selectedCells))
|
||||||
const $focusedCellAPI = get(focusedCellAPI)
|
const $focusedCellAPI = get(focusedCellAPI)
|
||||||
const multiCellMode = $selectedCellCount > 1
|
const multiCellCopy = cellIds.length > 1
|
||||||
|
|
||||||
// Multiple values to copy
|
// Multiple values to copy
|
||||||
if (multiCellMode) {
|
if (multiCellCopy) {
|
||||||
// TODO
|
const $rowLookupMap = get(rowLookupMap)
|
||||||
return
|
const $rowChangeCache = get(rowChangeCache)
|
||||||
|
const $rows = get(rows)
|
||||||
|
const $columnLookupMap = get(columnLookupMap)
|
||||||
|
|
||||||
|
// Go through each selected cell and group all selected cell values by
|
||||||
|
// their row ID. Order is important for pasting, so we store the index of
|
||||||
|
// both rows and values.
|
||||||
|
let map = {}
|
||||||
|
for (let cellId of cellIds) {
|
||||||
|
const { id, field } = parseCellID(cellId)
|
||||||
|
const index = $rowLookupMap[id]
|
||||||
|
if (!map[id]) {
|
||||||
|
map[id] = {
|
||||||
|
order: index,
|
||||||
|
values: [],
|
||||||
|
}
|
||||||
|
}
|
||||||
|
const row = {
|
||||||
|
...$rows[index],
|
||||||
|
...$rowChangeCache[id],
|
||||||
|
}
|
||||||
|
const columnIndex = $columnLookupMap[field]
|
||||||
|
map[id].values.push({
|
||||||
|
value: row[field],
|
||||||
|
order: columnIndex,
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Sort rows by order
|
||||||
|
let value = []
|
||||||
|
const sortedRowValues = Object.values(map)
|
||||||
|
.toSorted((a, b) => a.order - b.order)
|
||||||
|
.map(x => x.values)
|
||||||
|
|
||||||
|
// Sort all values in each row by order
|
||||||
|
for (let rowValues of sortedRowValues) {
|
||||||
|
value.push(
|
||||||
|
rowValues.toSorted((a, b) => a.order - b.order).map(x => x.value)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Update state
|
||||||
|
clipboard.set({
|
||||||
|
value,
|
||||||
|
multiCellCopy: true,
|
||||||
|
})
|
||||||
|
} else {
|
||||||
// Single value to copy
|
// Single value to copy
|
||||||
const value = $focusedCellAPI.getValue()
|
const value = $focusedCellAPI.getValue()
|
||||||
clipboard.set({
|
clipboard.set({
|
||||||
value,
|
value,
|
||||||
multiCellMode,
|
multiCellCopy,
|
||||||
})
|
})
|
||||||
|
|
||||||
// Also copy a stringified version to the clipboard
|
// Also copy a stringified version to the clipboard
|
||||||
|
@ -86,7 +134,9 @@ export const createActions = context => {
|
||||||
}
|
}
|
||||||
Helpers.copyToClipboard(stringified)
|
Helpers.copyToClipboard(stringified)
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Pastes the previously copied value(s) into the selected cell(s)
|
||||||
const paste = async () => {
|
const paste = async () => {
|
||||||
if (!get(pasteAllowed)) {
|
if (!get(pasteAllowed)) {
|
||||||
return
|
return
|
||||||
|
@ -98,14 +148,45 @@ export const createActions = context => {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check if we're pasting into one or more cells
|
// Check if we're pasting into one or more cells
|
||||||
const cellIds = Object.keys(get(selectedCells))
|
const $selectedCells = get(selectedCells)
|
||||||
|
const cellIds = Object.keys($selectedCells)
|
||||||
const multiCellPaste = cellIds.length > 1
|
const multiCellPaste = cellIds.length > 1
|
||||||
|
|
||||||
if ($clipboard.multiCellMode) {
|
if ($clipboard.multiCellCopy) {
|
||||||
if (multiCellPaste) {
|
if (multiCellPaste) {
|
||||||
// Multi to multi (only paste selected cells)
|
// Multi to multi (only paste selected cells)
|
||||||
|
const value = $clipboard.value
|
||||||
|
|
||||||
|
// Find the top left index so we can find the relative offset for each
|
||||||
|
// cell
|
||||||
|
let rowIndices = []
|
||||||
|
let columnIndices = []
|
||||||
|
for (let cellId of cellIds) {
|
||||||
|
rowIndices.push($selectedCells[cellId].rowIdx)
|
||||||
|
columnIndices.push($selectedCells[cellId].colIdx)
|
||||||
|
}
|
||||||
|
const minRowIdx = Math.min(...rowIndices)
|
||||||
|
const minColIdx = Math.min(...columnIndices)
|
||||||
|
|
||||||
|
// Build change map of values to patch
|
||||||
|
let changeMap = {}
|
||||||
|
const $rowLookupMap = get(rowLookupMap)
|
||||||
|
const $columnLookupMap = get(columnLookupMap)
|
||||||
|
for (let cellId of cellIds) {
|
||||||
|
const { id, field } = parseCellID(cellId)
|
||||||
|
const rowIdx = $rowLookupMap[id] - minRowIdx
|
||||||
|
const colIdx = $columnLookupMap[field] - minColIdx
|
||||||
|
if (colIdx in (value[rowIdx] || [])) {
|
||||||
|
if (!changeMap[id]) {
|
||||||
|
changeMap[id] = {}
|
||||||
|
}
|
||||||
|
changeMap[id][field] = value[rowIdx][colIdx]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
await rows.actions.bulkUpdate(changeMap)
|
||||||
} else {
|
} else {
|
||||||
// Multi to single (expand to paste all values)
|
// Multi to single (expand to paste all values)
|
||||||
|
// TODO
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (multiCellPaste) {
|
if (multiCellPaste) {
|
||||||
|
|
|
@ -60,7 +60,7 @@ export const deriveStores = context => {
|
||||||
rowId = $rows[rowIdx]._id
|
rowId = $rows[rowIdx]._id
|
||||||
colName = $allVisibleColumns[colIdx].name
|
colName = $allVisibleColumns[colIdx].name
|
||||||
cellId = getCellID(rowId, colName)
|
cellId = getCellID(rowId, colName)
|
||||||
map[cellId] = true
|
map[cellId] = { rowIdx, colIdx }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return map
|
return map
|
||||||
|
|
Loading…
Reference in New Issue