Simplify and improve bulk pasting logic
This commit is contained in:
parent
9c360a1f02
commit
70fd643431
|
@ -95,9 +95,6 @@
|
||||||
selectedCells.actions.stopSelecting()
|
selectedCells.actions.stopSelecting()
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if ($focusedCellId) {
|
|
||||||
focusedCellId.set(null)
|
|
||||||
}
|
|
||||||
selectedCells.actions.updateTarget(cellId)
|
selectedCells.actions.updateTarget(cellId)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -109,7 +106,6 @@
|
||||||
if (e.shiftKey && $focusedCellId) {
|
if (e.shiftKey && $focusedCellId) {
|
||||||
// If we have a focused cell, select the range from that cell to here
|
// If we have a focused cell, select the range from that cell to here
|
||||||
selectedCells.actions.setRange($focusedCellId, cellId)
|
selectedCells.actions.setRange($focusedCellId, cellId)
|
||||||
focusedCellId.set(null)
|
|
||||||
} else if (e.shiftKey && $selectedCellCount) {
|
} else if (e.shiftKey && $selectedCellCount) {
|
||||||
// If we already have a selected range of cell, update it
|
// If we already have a selected range of cell, update it
|
||||||
selectedCells.actions.updateTarget(cellId)
|
selectedCells.actions.updateTarget(cellId)
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
import { derived, writable, get } from "svelte/store"
|
import { derived, writable, get } from "svelte/store"
|
||||||
import { Helpers } from "@budibase/bbui"
|
import { Helpers } from "@budibase/bbui"
|
||||||
import { parseCellID } from "../lib/utils"
|
import { parseCellID, getCellID } from "../lib/utils"
|
||||||
|
|
||||||
export const createStores = () => {
|
export const createStores = () => {
|
||||||
const clipboard = writable({
|
const clipboard = writable({
|
||||||
|
@ -62,6 +62,9 @@ export const createActions = context => {
|
||||||
rowLookupMap,
|
rowLookupMap,
|
||||||
rowChangeCache,
|
rowChangeCache,
|
||||||
rows,
|
rows,
|
||||||
|
focusedCellId,
|
||||||
|
columnLookupMap,
|
||||||
|
allVisibleColumns,
|
||||||
} = context
|
} = context
|
||||||
|
|
||||||
// Copies the currently selected value (or values)
|
// Copies the currently selected value (or values)
|
||||||
|
@ -125,57 +128,86 @@ export const createActions = context => {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
const { value, multiCellCopy } = get(clipboard)
|
const { value, multiCellCopy } = get(clipboard)
|
||||||
const $focusedCellAPI = get(focusedCellAPI)
|
const multiCellPaste = get(selectedCellCount) > 1
|
||||||
const $selectedCells = get(selectedCells)
|
|
||||||
const $selectedCellCount = get(selectedCellCount)
|
|
||||||
const multiCellPaste = $selectedCellCount > 1
|
|
||||||
|
|
||||||
// Choose paste strategy
|
// Choose paste strategy
|
||||||
if (multiCellCopy) {
|
if (multiCellCopy) {
|
||||||
if (multiCellPaste) {
|
if (multiCellPaste) {
|
||||||
// Multi to multi (only paste selected cells)
|
// Multi to multi (only paste selected cells)
|
||||||
// Find the extent at which we can paste
|
await pasteIntoSelectedCells(value)
|
||||||
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)
|
|
||||||
} else {
|
} else {
|
||||||
// Multi to single (expand to paste all values)
|
// 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 {
|
} else {
|
||||||
if (multiCellPaste) {
|
if (multiCellPaste) {
|
||||||
// Single to multi (duplicate value in all selected cells)
|
// Single to multi (duplicate value in all selected cells)
|
||||||
let changeMap = {}
|
const $selectedCells = get(selectedCells)
|
||||||
for (let row of $selectedCells) {
|
const pastableValue = $selectedCells.map(row => {
|
||||||
for (let cellId of row) {
|
return row.map(() => value)
|
||||||
const { id, field } = parseCellID(cellId)
|
})
|
||||||
if (!changeMap[id]) {
|
await pasteIntoSelectedCells(pastableValue)
|
||||||
changeMap[id] = {}
|
|
||||||
}
|
|
||||||
changeMap[id][field] = value
|
|
||||||
}
|
|
||||||
}
|
|
||||||
await rows.actions.bulkUpdate(changeMap)
|
|
||||||
} else {
|
} else {
|
||||||
// Single to single
|
// 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 {
|
return {
|
||||||
clipboard: {
|
clipboard: {
|
||||||
...clipboard,
|
...clipboard,
|
||||||
|
|
|
@ -217,9 +217,8 @@ export const createActions = context => {
|
||||||
toggleSelectedRow(id)
|
toggleSelectedRow(id)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
// There should always be a last selected index
|
|
||||||
if (lastSelectedIndex == null) {
|
if (lastSelectedIndex == null) {
|
||||||
throw "NO LAST SELECTED INDEX"
|
return
|
||||||
}
|
}
|
||||||
const thisIndex = get(rowLookupMap)[id]
|
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 => {
|
selectedCellCount.subscribe($selectedCellCount => {
|
||||||
if ($selectedCellCount && get(selectedRowCount)) {
|
if ($selectedCellCount) {
|
||||||
selectedRows.set({})
|
if (get(selectedRowCount)) {
|
||||||
|
selectedRows.set({})
|
||||||
|
}
|
||||||
|
if (get(focusedCellId)) {
|
||||||
|
focusedCellId.set(null)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue