Simplify and improve bulk pasting logic
This commit is contained in:
parent
9c360a1f02
commit
70fd643431
|
@ -95,9 +95,6 @@
|
|||
selectedCells.actions.stopSelecting()
|
||||
return
|
||||
}
|
||||
if ($focusedCellId) {
|
||||
focusedCellId.set(null)
|
||||
}
|
||||
selectedCells.actions.updateTarget(cellId)
|
||||
}
|
||||
|
||||
|
@ -109,7 +106,6 @@
|
|||
if (e.shiftKey && $focusedCellId) {
|
||||
// If we have a focused cell, select the range from that cell to here
|
||||
selectedCells.actions.setRange($focusedCellId, cellId)
|
||||
focusedCellId.set(null)
|
||||
} else if (e.shiftKey && $selectedCellCount) {
|
||||
// If we already have a selected range of cell, update it
|
||||
selectedCells.actions.updateTarget(cellId)
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
import { derived, writable, get } from "svelte/store"
|
||||
import { Helpers } from "@budibase/bbui"
|
||||
import { parseCellID } from "../lib/utils"
|
||||
import { parseCellID, getCellID } from "../lib/utils"
|
||||
|
||||
export const createStores = () => {
|
||||
const clipboard = writable({
|
||||
|
@ -62,6 +62,9 @@ export const createActions = context => {
|
|||
rowLookupMap,
|
||||
rowChangeCache,
|
||||
rows,
|
||||
focusedCellId,
|
||||
columnLookupMap,
|
||||
allVisibleColumns,
|
||||
} = context
|
||||
|
||||
// Copies the currently selected value (or values)
|
||||
|
@ -125,57 +128,86 @@ export const createActions = context => {
|
|||
return
|
||||
}
|
||||
const { value, multiCellCopy } = get(clipboard)
|
||||
const $focusedCellAPI = get(focusedCellAPI)
|
||||
const $selectedCells = get(selectedCells)
|
||||
const $selectedCellCount = get(selectedCellCount)
|
||||
const multiCellPaste = $selectedCellCount > 1
|
||||
const multiCellPaste = get(selectedCellCount) > 1
|
||||
|
||||
// Choose paste strategy
|
||||
if (multiCellCopy) {
|
||||
if (multiCellPaste) {
|
||||
// Multi to multi (only paste selected cells)
|
||||
// Find the extent at which we can paste
|
||||
const rowExtent = Math.min(value.length, $selectedCells.length)
|
||||
const colExtent = Math.min(value[0].length, $selectedCells[0].length)
|
||||
|
||||
// Build change map
|
||||
let changeMap = {}
|
||||
for (let rowIdx = 0; rowIdx < rowExtent; rowIdx++) {
|
||||
for (let colIdx = 0; colIdx < colExtent; colIdx++) {
|
||||
const cellId = $selectedCells[rowIdx][colIdx]
|
||||
const { id, field } = parseCellID(cellId)
|
||||
if (!changeMap[id]) {
|
||||
changeMap[id] = {}
|
||||
}
|
||||
changeMap[id][field] = value[rowIdx][colIdx]
|
||||
}
|
||||
}
|
||||
await rows.actions.bulkUpdate(changeMap)
|
||||
await pasteIntoSelectedCells(value)
|
||||
} else {
|
||||
// Multi to single (expand to paste all values)
|
||||
// TODO
|
||||
// Get indices of focused cell
|
||||
const $focusedCellId = get(focusedCellId)
|
||||
const { id, field } = parseCellID($focusedCellId)
|
||||
const $rowLookupMap = get(rowLookupMap)
|
||||
const $columnLookupMap = get(columnLookupMap)
|
||||
const rowIdx = $rowLookupMap[id]
|
||||
const colIdx = $columnLookupMap[field]
|
||||
|
||||
// Get limits of how many rows and columns we're able to paste into
|
||||
const $rows = get(rows)
|
||||
const $allVisibleColumns = get(allVisibleColumns)
|
||||
const colCount = $allVisibleColumns.length
|
||||
const rowCount = $rows.length
|
||||
const selectedRows = value.length
|
||||
const selectedColumns = value[0].length
|
||||
const rowExtent = Math.min(selectedRows, rowCount - rowIdx) - 1
|
||||
const colExtent = Math.min(selectedColumns, colCount - colIdx) - 1
|
||||
|
||||
// Get the target cell ID (bottom right of our pastable extent)
|
||||
const targetRowId = $rows[rowIdx + rowExtent]._id
|
||||
const targetColName = $allVisibleColumns[colIdx + colExtent].name
|
||||
const targetCellId = getCellID(targetRowId, targetColName)
|
||||
|
||||
// Paste into target cell range
|
||||
if (targetCellId === $focusedCellId) {
|
||||
// Single cell edge case
|
||||
get(focusedCellAPI).setValue(value[0][0])
|
||||
} else {
|
||||
// Select the new cells to paste into, then paste
|
||||
selectedCells.actions.updateTarget(targetCellId)
|
||||
await pasteIntoSelectedCells(value)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (multiCellPaste) {
|
||||
// Single to multi (duplicate value in all selected cells)
|
||||
let changeMap = {}
|
||||
for (let row of $selectedCells) {
|
||||
for (let cellId of row) {
|
||||
const { id, field } = parseCellID(cellId)
|
||||
if (!changeMap[id]) {
|
||||
changeMap[id] = {}
|
||||
}
|
||||
changeMap[id][field] = value
|
||||
}
|
||||
}
|
||||
await rows.actions.bulkUpdate(changeMap)
|
||||
const $selectedCells = get(selectedCells)
|
||||
const pastableValue = $selectedCells.map(row => {
|
||||
return row.map(() => value)
|
||||
})
|
||||
await pasteIntoSelectedCells(pastableValue)
|
||||
} else {
|
||||
// Single to single
|
||||
$focusedCellAPI.setValue(value)
|
||||
get(focusedCellAPI).setValue(value)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Paste the specified value into the currently selected cells
|
||||
const pasteIntoSelectedCells = async value => {
|
||||
const $selectedCells = get(selectedCells)
|
||||
|
||||
// Find the extent at which we can paste
|
||||
const rowExtent = Math.min(value.length, $selectedCells.length)
|
||||
const colExtent = Math.min(value[0].length, $selectedCells[0].length)
|
||||
|
||||
// Build change map
|
||||
let changeMap = {}
|
||||
for (let rowIdx = 0; rowIdx < rowExtent; rowIdx++) {
|
||||
for (let colIdx = 0; colIdx < colExtent; colIdx++) {
|
||||
const cellId = $selectedCells[rowIdx][colIdx]
|
||||
const { id, field } = parseCellID(cellId)
|
||||
if (!changeMap[id]) {
|
||||
changeMap[id] = {}
|
||||
}
|
||||
changeMap[id][field] = value[rowIdx][colIdx]
|
||||
}
|
||||
}
|
||||
await rows.actions.bulkUpdate(changeMap)
|
||||
}
|
||||
|
||||
return {
|
||||
clipboard: {
|
||||
...clipboard,
|
||||
|
|
|
@ -217,9 +217,8 @@ export const createActions = context => {
|
|||
toggleSelectedRow(id)
|
||||
return
|
||||
}
|
||||
// There should always be a last selected index
|
||||
if (lastSelectedIndex == null) {
|
||||
throw "NO LAST SELECTED INDEX"
|
||||
return
|
||||
}
|
||||
const thisIndex = get(rowLookupMap)[id]
|
||||
|
||||
|
@ -417,10 +416,15 @@ export const initialise = context => {
|
|||
}
|
||||
})
|
||||
|
||||
// Clear selected rows when selecting cells
|
||||
// Clear state when selecting cells
|
||||
selectedCellCount.subscribe($selectedCellCount => {
|
||||
if ($selectedCellCount && get(selectedRowCount)) {
|
||||
selectedRows.set({})
|
||||
if ($selectedCellCount) {
|
||||
if (get(selectedRowCount)) {
|
||||
selectedRows.set({})
|
||||
}
|
||||
if (get(focusedCellId)) {
|
||||
focusedCellId.set(null)
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue