UNPKG

@platform/ui.datagrid

Version:

Isolated tabular DataGrid.

156 lines (155 loc) 5.61 kB
import { filter, map } from 'rxjs/operators'; import { coord, toClipboard } from '../common'; const CLIPBOARD_COMMANDS = ['CUT', 'COPY', 'PASTE']; export function init(args) { const { grid, command$, fire } = args; const clipboard$ = command$.pipe(filter((e) => CLIPBOARD_COMMANDS.includes(e.command)), filter((e) => !e.isCancelled), map((e) => e.command)); clipboard$.pipe(filter((e) => e === 'CUT')).subscribe((e) => read({ grid, fire, action: 'CUT' })); clipboard$ .pipe(filter((e) => e === 'COPY')) .subscribe((e) => read({ grid, fire, action: 'COPY' })); clipboard$.pipe(filter((e) => e === 'PASTE')).subscribe((e) => write({ grid, fire })); } async function read(args) { const { grid, action } = args; const wait = []; args.fire({ type: 'GRID/clipboard/before/read', payload: { action, wait: (promise) => wait.push(promise), }, }); if (wait.length > 0) { await Promise.all(wait); } const payload = toClipboard({ grid, action }); await navigator.clipboard.writeText(payload.text); grid.clipboard = Object.assign(Object.assign({}, payload), { pasted: 0 }); args.fire({ type: 'GRID/clipboard', payload }); } async function write(args) { const { grid } = args; const selection = grid.selection; const targetCell = selection.cell; if (!targetCell) { return; } let redraw = false; const text = await navigator.clipboard.readText(); let pending = grid.clipboard; const before = { text, pending, isModified: false, modify: (change) => { before.isModified = true; pending = Object.assign(Object.assign({}, (change || {})), { pasted: 0 }); }, }; args.fire({ type: 'GRID/clipboard/before/paste', payload: before }); const isPendingCurrent = pending ? pending.text === text : false; if (!isPendingCurrent) { grid.clipboard = undefined; pending = undefined; } if (pending && pending.action === 'CUT') { const empty = Object.keys(pending.cells).reduce((acc, key) => { acc[key] = { value: undefined }; return acc; }, {}); grid.changeCells(empty, { source: 'CLIPBOARD/cut' }); } const cellsFromString = () => coord.table .fromString({ key: targetCell, text }) .map(({ key, value }) => ({ key, value: { value } })); const items = pending && pending.selection.cell ? shiftCells({ sourceCell: pending.selection.cell, targetCell, data: pending.cells, }) : cellsFromString(); if (items.length === 0) { return; } const changedCells = items.reduce((acc, next) => { acc[next.key] = next.value; return acc; }, {}); grid.changeCells(changedCells, { source: 'CLIPBOARD/paste' }); const shiftedAxisData = (axis, data) => { if (!pending || Object.keys(data).length === 0) { return {}; } const source = firstAxisRange(axis, pending.selection); const target = firstAxisRange(axis, selection); if (!source || !target) { return {}; } return shiftAxisData({ axis, source, target, data }); }; const columns = pending ? shiftedAxisData('COLUMN', pending.columns) : {}; const rows = pending ? shiftedAxisData('ROW', pending.rows) : {}; if (Object.keys(columns).length > 0) { grid.changeColumns(columns, { source: 'CLIPBOARD/paste' }); redraw = true; } if (Object.keys(rows).length > 0) { grid.changeRows(rows, { source: 'CLIPBOARD/paste' }); redraw = true; } const square = coord.range.square(items.map((item) => item.key)); grid.select({ cell: square.left.key, ranges: [square.key] }); if (grid.clipboard) { grid.clipboard = Object.assign(Object.assign({}, grid.clipboard), { pasted: grid.clipboard.pasted + 1 }); } const cells = items.reduce((acc, next) => { acc[next.key] = next.value; return acc; }, {}); args.fire({ type: 'GRID/clipboard', payload: { action: 'PASTE', selection, text, cells, columns, rows }, }); if (redraw) { grid.redraw(); } } function shiftCells(args) { const pos = { start: coord.cell.fromKey(args.sourceCell), end: coord.cell.fromKey(args.targetCell), }; const diff = { row: pos.end.row - pos.start.row, column: pos.end.column - pos.start.column, }; const data = Object.assign({}, args.data); return Object.keys(data).map((cell) => { const pos = coord.cell.fromKey(cell); const key = coord.cell.toKey(pos.column + diff.column, pos.row + diff.row); return { key, value: data[cell] }; }); } function shiftAxisData(args) { const { axis } = args; const pos = { start: args.source.left, end: args.target.left, }; const diff = coord.cell.toAxisIndex(axis, pos.end) - coord.cell.toAxisIndex(axis, pos.start); const data = Object.assign({}, args.data); return Object.keys(data).reduce((acc, next) => { const index = coord.cell.toAxisIndex(axis, next) + diff; const key = coord.cell.toAxisKey(axis, index); if (key) { acc[key] = data[next]; } return acc; }, {}); } function firstAxisRange(axis, selection) { const key = selection.ranges.find((key) => coord.cell.isAxisRangeKey(key, axis)); return key ? coord.range.fromKey(key) : undefined; }