From 96809e226db2b5b891547030b7ea14dc1dcd8dbc Mon Sep 17 00:00:00 2001 From: Jan Prochazka Date: Sat, 20 Nov 2021 21:01:48 +0100 Subject: [PATCH] copy formats --- packages/web/src/datagrid/DataGridCore.svelte | 81 +++++++++++++++---- packages/web/src/stores.ts | 1 + .../utility/{clipboard.js => clipboard.ts} | 64 ++++++++++++++- 3 files changed, 128 insertions(+), 18 deletions(-) rename packages/web/src/utility/{clipboard.js => clipboard.ts} (60%) diff --git a/packages/web/src/datagrid/DataGridCore.svelte b/packages/web/src/datagrid/DataGridCore.svelte index fcd93f346..3bb4fd83e 100644 --- a/packages/web/src/datagrid/DataGridCore.svelte +++ b/packages/web/src/datagrid/DataGridCore.svelte @@ -228,9 +228,14 @@ import DataFilterControl from './DataFilterControl.svelte'; import createReducer from '../utility/createReducer'; import keycodes from '../utility/keycodes'; - import { selectedCellsCallback } from '../stores'; + import { copyRowsFormat, selectedCellsCallback } from '../stores'; import axiosInstance from '../utility/axiosInstance'; - import { copyTextToClipboard, extractRowCopiedValue } from '../utility/clipboard'; + import { + copyRowsFormatDefs, + copyRowsToClipboard, + copyTextToClipboard, + extractRowCopiedValue, + } from '../utility/clipboard'; import invalidateCommands from '../commands/invalidateCommands'; import createRef from '../utility/createRef'; import openReferenceForm, { openPrimaryKeyForm } from '../formview/openReferenceForm'; @@ -360,21 +365,33 @@ display.reload(); } - export function copyToClipboard() { + function copyToClipboardCore(format) { const cells = cellsToRegularCells(selectedCells); const rowIndexes = _.sortBy(_.uniq(cells.map(x => x[0]))); - const lines = rowIndexes.map(rowIndex => { - let colIndexes = _.sortBy(cells.filter(x => x[0] == rowIndex).map(x => x[1])); - const rowData = grider.getRowData(rowIndex); - if (!rowData) return ''; - const line = colIndexes - .map(col => realColumnUniqueNames[col]) - .map(col => extractRowCopiedValue(rowData, col)) - .join('\t'); - return line; - }); - const text = lines.join('\r\n'); - copyTextToClipboard(text); + const colIndexes = _.sortBy(_.uniq(cells.map(x => x[1]))); + const rows = rowIndexes.map(rowIndex => grider.getRowData(rowIndex)); + // @ts-ignore + const columns = colIndexes.map(col => realColumnUniqueNames[col]); + copyRowsToClipboard(columns, rows, format); + if (domFocusField) domFocusField.focus(); + } + + export function copyToClipboard() { + copyToClipboardCore($copyRowsFormat); + // const cells = cellsToRegularCells(selectedCells); + // const rowIndexes = _.sortBy(_.uniq(cells.map(x => x[0]))); + // const lines = rowIndexes.map(rowIndex => { + // let colIndexes = _.sortBy(cells.filter(x => x[0] == rowIndex).map(x => x[1])); + // const rowData = grider.getRowData(rowIndex); + // if (!rowData) return ''; + // const line = colIndexes + // .map(col => realColumnUniqueNames[col]) + // .map(col => extractRowCopiedValue(rowData, col)) + // .join('\t'); + // return line; + // }); + // const text = lines.join('\r\n'); + // copyTextToClipboard(text); // if (domFocusField) domFocusField.focus(); } @@ -1121,7 +1138,25 @@ registerMenu( { command: 'dataGrid.refresh' }, - { command: 'dataGrid.copyToClipboard' }, + { placeTag: 'copy' }, + { + text: 'Copy advanced', + submenu: [ + _.keys(copyRowsFormatDefs).map(format => ({ + text: copyRowsFormatDefs[format].label, + onClick: () => copyToClipboardCore(format), + })), + { divider: true }, + _.keys(copyRowsFormatDefs).map(format => ({ + text: `Set format: ${copyRowsFormatDefs[format].name}`, + onClick: () => ($copyRowsFormat = format), + })), + + // { text: 'Copy as text', onClick: () => copyToClipboardCore('text') }, + // { text: 'Copy as CSV', onClick: () => copyToClipboardCore('csv') }, + // { text: 'Copy as JSON', onClick: () => copyToClipboardCore('json') }, + ], + }, { command: 'dataGrid.copyJsonDocument', hideDisabled: true }, { placeTag: 'switch' }, { divider: true }, @@ -1149,6 +1184,18 @@ ); const menu = getContextMenu(); + + function buildMenu() { + return [ + menu, + { + text: copyRowsFormatDefs[$copyRowsFormat].label, + onClick: () => copyToClipboardCore($copyRowsFormat), + keyText: 'Ctrl+C', + tag: 'copy', + }, + ]; + } {#if !display || (!isDynamicStructure && (!columns || columns.length == 0))} @@ -1173,7 +1220,7 @@ class="container" bind:clientWidth={containerWidth} bind:clientHeight={containerHeight} - use:contextMenu={menu} + use:contextMenu={buildMenu} on:wheel={handleGridWheel} > ([], 'openedTabs'); +export const copyRowsFormat = writableWithStorage('textWithoutHeaders', 'copyRowsFormat'); export const extensions = writable(null); export const visibleCommandPalette = writable(null); export const commands = writable({}); diff --git a/packages/web/src/utility/clipboard.js b/packages/web/src/utility/clipboard.ts similarity index 60% rename from packages/web/src/utility/clipboard.js rename to packages/web/src/utility/clipboard.ts index 045af4e98..c04397a46 100644 --- a/packages/web/src/utility/clipboard.js +++ b/packages/web/src/utility/clipboard.ts @@ -59,7 +59,10 @@ export function copyTextToClipboard(text) { document.body.removeChild(textArea); - if (oldFocus) oldFocus.focus(); + if (oldFocus) { + // @ts-ignore + oldFocus.focus(); + } } export function extractRowCopiedValue(row, col) { @@ -71,3 +74,62 @@ export function extractRowCopiedValue(row, col) { if (_.isPlainObject(value) || _.isArray(value)) return JSON.stringify(value); return value; } + +const clipboardTextFormatter = (delimiter, headers) => (columns, rows) => { + const lines = []; + if (headers) lines.push(columns.join(delimiter)); + lines.push( + ...rows.map(row => { + if (!row) return ''; + const line = columns.map(col => extractRowCopiedValue(row, col)).join(delimiter); + return line; + }) + ); + return lines.join('\r\n'); +}; + +const clipboardJsonFormatter = () => (columns, rows) => { + return JSON.stringify( + rows.map(row => _.pick(row, columns)), + undefined, + 2 + ); +}; + +// export function formatClipboardSqlInsert(columns, rows) { +// } + +export function formatClipboardRows(columns, rows, format) { + if (format in copyRowsFormatDefs) { + return copyRowsFormatDefs[format].formatter(columns, rows); + } + return ''; +} + +export function copyRowsToClipboard(columns, rows, format) { + const formatted = formatClipboardRows(columns, rows, format); + copyTextToClipboard(formatted); +} + +export const copyRowsFormatDefs = { + textWithHeaders: { + label: 'Copy with headers', + name: 'With headers', + formatter: clipboardTextFormatter('\t', true), + }, + textWithoutHeaders: { + label: 'Copy without headers', + name: 'Without headers', + formatter: clipboardTextFormatter('\t', false), + }, + csv: { + label: 'Copy as CSV', + name: 'CSV', + formatter: clipboardTextFormatter(',', true), + }, + json: { + label: 'Copy as JSON', + name: 'JSON', + formatter: clipboardJsonFormatter(), + }, +};