Improvements to the Query Results grid:

- Improve the UI
- Allow copy/paste from sets of rows, columns or arbitrary blocks of cells

Patch by Matt, Shruti, Joao and Sarah @ Pivotal

Fixes #2476
This commit is contained in:
Sarah McAlear
2017-06-08 13:31:36 +01:00
committed by Dave Page
parent 2fddf750e6
commit 01bfa88309
62 changed files with 4513 additions and 829 deletions

View File

@@ -0,0 +1,18 @@
define(["slickgrid"], function () {
var Slick = window.Slick;
return function () {
this.init = function (grid) {
grid.onActiveCellChanged.subscribe(function (event, slickEvent) {
grid.getSelectionModel().setSelectedRanges([
new Slick.Range(
slickEvent.row,
slickEvent.cell,
slickEvent.row,
slickEvent.cell
)
]);
});
}
}
});

View File

@@ -0,0 +1,21 @@
define([
'sources/selection/copy_data',
'sources/selection/range_selection_helper'
],
function (copyData, RangeSelectionHelper) {
return function handleQueryOutputKeyboardEvent(event, args) {
var KEY_C = 67;
var KEY_A = 65;
var modifiedKey = event.keyCode;
var isModifierDown = event.ctrlKey || event.metaKey;
this.slickgrid = args.grid;
if (isModifierDown && modifiedKey == KEY_C) {
copyData.apply(this);
}
if (isModifierDown && modifiedKey == KEY_A) {
RangeSelectionHelper.selectAll(this.slickgrid);
}
}
});

View File

@@ -0,0 +1,73 @@
define([
'jquery',
'slickgrid',
], function ($) {
/***
* Displays an overlay on top of a given cell range.
*
* TODO:
* Currently, it blocks mouse events to DOM nodes behind it.
* Use FF and WebKit-specific "pointer-events" CSS style, or some kind of event forwarding.
* Could also construct the borders separately using 4 individual DIVs.
*
* @param {Grid} grid
* @param {Object} options
*/
var PGCellRangeDecorator = function (grid, options) {
var _elem;
var _defaults = {
selectionCssClass: 'slick-range-decorator',
selectionCss: {
"zIndex": "9999",
"border": "2px dashed red"
}
};
options = $.extend(true, {}, _defaults, options);
function show(range) {
if (!_elem) {
_elem = $("<div></div>", {css: options.selectionCss})
.addClass(options.selectionCssClass)
.css("position", "absolute")
.appendTo(grid.getCanvasNode());
}
var from = grid.getCellNodeBox(range.fromRow, range.fromCell);
var to = grid.getCellNodeBox(range.toRow, range.toCell);
// TODO: This is the original Slickgrid code temporary fix to solve
// pgAdmin alignment of the selection box on the bottom right corner
// _elem.css({
// top: from.top - 1,
// left: from.left - 1,
// height: to.bottom - from.top - 2,
// width: to.right - from.left - 2
// });
_elem.css({
top: from.top - 1,
left: from.left - 1,
height: to.bottom - from.top + 2,
width: to.right - from.left + 1
});
return _elem;
}
function hide() {
if (_elem) {
_elem.remove();
_elem = null;
}
}
$.extend(this, {
"show": show,
"hide": hide
});
};
return PGCellRangeDecorator;
});

View File

@@ -0,0 +1,119 @@
define([
'jquery',
'sources/slickgrid/pgslick.cellrangedecorator',
'slickgrid',
], function ($, PGCellRangeDecorator) {
var PGCellRangeSelector = function (options) {
var _grid;
var _canvas;
var _currentlySelectedRange;
var _dragging;
var _decorator;
var _self = this;
var _handler = new Slick.EventHandler();
var _defaults = {
selectionCss: {
"border": "2px dashed blue"
}
};
function init(grid) {
options = $.extend(true, {}, _defaults, options);
_decorator = new PGCellRangeDecorator(grid, options);
_grid = grid;
_canvas = _grid.getCanvasNode();
_handler
.subscribe(_grid.onDragInit, handleDragInit)
.subscribe(_grid.onDragStart, handleDragStart)
.subscribe(_grid.onDrag, handleDrag)
.subscribe(_grid.onDragEnd, handleDragEnd);
}
function destroy() {
_handler.unsubscribeAll();
}
function handleDragInit(e, dd) {
// prevent the grid from cancelling drag'n'drop by default
e.stopImmediatePropagation();
}
function handleDragStart(e, dd) {
var cell = _grid.getCellFromEvent(e);
if (_self.onBeforeCellRangeSelected.notify(cell) !== false) {
if (_grid.canCellBeSelected(cell.row, cell.cell)) {
_dragging = true;
e.stopImmediatePropagation();
}
}
if (!_dragging) {
return;
}
_grid.focus();
var start = _grid.getCellFromPoint(
dd.startX - $(_canvas).offset().left,
dd.startY - $(_canvas).offset().top);
dd.range = {start: start, end: {}};
_currentlySelectedRange = dd.range;
return _decorator.show(new Slick.Range(start.row, start.cell));
}
function handleDrag(e, dd) {
if (!_dragging) {
return;
}
e.stopImmediatePropagation();
var end = _grid.getCellFromPoint(
e.pageX - $(_canvas).offset().left,
e.pageY - $(_canvas).offset().top);
if (!_grid.canCellBeSelected(end.row, end.cell)) {
return;
}
dd.range.end = end;
_currentlySelectedRange = dd.range;
_decorator.show(new Slick.Range(dd.range.start.row, dd.range.start.cell, end.row, end.cell));
}
function handleDragEnd(e, dd) {
if (!_dragging) {
return;
}
_dragging = false;
e.stopImmediatePropagation();
_decorator.hide();
_self.onCellRangeSelected.notify({
range: new Slick.Range(
dd.range.start.row,
dd.range.start.cell,
dd.range.end.row,
dd.range.end.cell
)
});
}
function getCurrentRange() {
return _currentlySelectedRange;
}
$.extend(this, {
"init": init,
"destroy": destroy,
"getCurrentRange": getCurrentRange,
"onBeforeCellRangeSelected": new Slick.Event(),
"onCellRangeSelected": new Slick.Event()
});
};
return PGCellRangeSelector;
});