mirror of
https://github.com/dbgate/dbgate
synced 2024-11-07 20:26:23 +00:00
data grid - copy to clipboard
This commit is contained in:
parent
e49c0169da
commit
ec2acebdc9
@ -97,6 +97,15 @@
|
||||
onClick: () => get(currentDataGrid).reconnect(),
|
||||
});
|
||||
|
||||
registerCommand({
|
||||
id: 'dataGrid.copyToClipboard',
|
||||
category: 'Data grid',
|
||||
name: 'Copy to clipboard',
|
||||
keyText: 'Ctrl+C',
|
||||
enabledStore: derived(currentDataGrid, grid => grid != null),
|
||||
onClick: () => get(currentDataGrid).copyToClipboard(),
|
||||
});
|
||||
|
||||
function getRowCountInfo(selectedCells, grider, realColumnUniqueNames, selectedRowData, allRowCount) {
|
||||
if (selectedCells.length > 1 && selectedCells.every(x => _.isNumber(x[0]) && _.isNumber(x[1]))) {
|
||||
let sum = _.sumBy(selectedCells, cell => {
|
||||
@ -153,6 +162,7 @@
|
||||
import { nullStore } from '../stores';
|
||||
import memberStore from '../utility/memberStore';
|
||||
import axios from '../utility/axios';
|
||||
import { copyTextToClipboard } from '../utility/clipboard';
|
||||
|
||||
export let loadNextData = undefined;
|
||||
export let grider = undefined;
|
||||
@ -259,6 +269,23 @@
|
||||
display.reload();
|
||||
}
|
||||
|
||||
export function copyToClipboard() {
|
||||
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 => (rowData[col] == null ? '(NULL)' : rowData[col]))
|
||||
.join('\t');
|
||||
return line;
|
||||
});
|
||||
const text = lines.join('\r\n');
|
||||
copyTextToClipboard(text);
|
||||
}
|
||||
|
||||
$: autofillMarkerCell =
|
||||
selectedCells && selectedCells.length > 0 && _.uniq(selectedCells.map(x => x[0])).length == 1
|
||||
? [_.max(selectedCells.map(x => x[0])), _.max(selectedCells.map(x => x[1]))]
|
||||
@ -662,6 +689,26 @@
|
||||
return [row, col];
|
||||
}
|
||||
|
||||
function cellsToRegularCells(cells) {
|
||||
cells = _.flatten(
|
||||
cells.map(cell => {
|
||||
if (cell[1] == 'header') {
|
||||
return _.range(0, columnSizes.count).map(col => [cell[0], col]);
|
||||
}
|
||||
return [cell];
|
||||
})
|
||||
);
|
||||
cells = _.flatten(
|
||||
cells.map(cell => {
|
||||
if (cell[0] == 'header') {
|
||||
return _.range(0, grider.rowCount).map(row => [row, cell[1]]);
|
||||
}
|
||||
return [cell];
|
||||
})
|
||||
);
|
||||
return cells.filter(isRegularCell);
|
||||
}
|
||||
|
||||
const [inplaceEditorState, dispatchInsplaceEditor] = createReducer((state, action) => {
|
||||
switch (action.type) {
|
||||
case 'show':
|
||||
@ -692,6 +739,7 @@
|
||||
function createMenu() {
|
||||
return [
|
||||
{ command: 'dataGrid.refresh' },
|
||||
{ command: 'dataGrid.copyToClipboard' },
|
||||
{ divider: true },
|
||||
{ command: 'dataGrid.save' },
|
||||
{ command: 'dataGrid.revertRowChanges' },
|
||||
|
56
packages/web/src/utility/clipboard.js
Normal file
56
packages/web/src/utility/clipboard.js
Normal file
@ -0,0 +1,56 @@
|
||||
export function copyTextToClipboard(text) {
|
||||
const textArea = document.createElement('textarea');
|
||||
|
||||
//
|
||||
// *** This styling is an extra step which is likely not required. ***
|
||||
//
|
||||
// Why is it here? To ensure:
|
||||
// 1. the element is able to have focus and selection.
|
||||
// 2. if element was to flash render it has minimal visual impact.
|
||||
// 3. less flakyness with selection and copying which **might** occur if
|
||||
// the textarea element is not visible.
|
||||
//
|
||||
// The likelihood is the element won't even render, not even a flash,
|
||||
// so some of these are just precautions. However in IE the element
|
||||
// is visible whilst the popup box asking the user for permission for
|
||||
// the web page to copy to the clipboard.
|
||||
//
|
||||
|
||||
// Place in top-left corner of screen regardless of scroll position.
|
||||
textArea.style.position = 'fixed';
|
||||
textArea.style.top = '0';
|
||||
textArea.style.left = '0';
|
||||
|
||||
// Ensure it has a small width and height. Setting to 1px / 1em
|
||||
// doesn't work as this gives a negative w/h on some browsers.
|
||||
textArea.style.width = '2em';
|
||||
textArea.style.height = '2em';
|
||||
|
||||
// We don't need padding, reducing the size if it does flash render.
|
||||
textArea.style.padding = '0';
|
||||
|
||||
// Clean up any borders.
|
||||
textArea.style.border = 'none';
|
||||
textArea.style.outline = 'none';
|
||||
textArea.style.boxShadow = 'none';
|
||||
|
||||
// Avoid flash of white box if rendered for any reason.
|
||||
textArea.style.background = 'transparent';
|
||||
|
||||
textArea.value = text;
|
||||
|
||||
document.body.appendChild(textArea);
|
||||
|
||||
textArea.select();
|
||||
|
||||
try {
|
||||
let successful = document.execCommand('copy');
|
||||
if (!successful) {
|
||||
console.log('Failed copy to clipboard');
|
||||
}
|
||||
} catch (err) {
|
||||
console.log('Failed copy to clipboard: ' + err);
|
||||
}
|
||||
|
||||
document.body.removeChild(textArea);
|
||||
}
|
Loading…
Reference in New Issue
Block a user