mirror of
https://github.com/ckaczor/azuredatastudio.git
synced 2026-02-16 18:46:40 -05:00
Rework slickgrid keyboard navigation (#1930)
* rewrite keybind nav to handle ctrl + home and end * testing different options * working on removed slickgrid changes we don't need * formatting * handle click handler to rowNumber * fixing various bugs * formatting * readd click column to select * add shift key to column select * added logic for additional keybindings on grid * add down and up arrow into keyboard navigation * update styling and update slickgrid * formatting * update angular-slickgrid version * remove index.js changes
This commit is contained in:
@@ -34,7 +34,7 @@
|
|||||||
"@angular/router": "~4.1.3",
|
"@angular/router": "~4.1.3",
|
||||||
"@angular/upgrade": "~4.1.3",
|
"@angular/upgrade": "~4.1.3",
|
||||||
"angular2-grid": "2.0.6",
|
"angular2-grid": "2.0.6",
|
||||||
"angular2-slickgrid": "git://github.com/Microsoft/angular2-slickgrid.git#1.3.11",
|
"angular2-slickgrid": "github:Microsoft/angular2-slickgrid#1.3.12",
|
||||||
"applicationinsights": "0.18.0",
|
"applicationinsights": "0.18.0",
|
||||||
"chart.js": "^2.6.0",
|
"chart.js": "^2.6.0",
|
||||||
"fast-plist": "0.1.2",
|
"fast-plist": "0.1.2",
|
||||||
@@ -60,7 +60,7 @@
|
|||||||
"reflect-metadata": "^0.1.8",
|
"reflect-metadata": "^0.1.8",
|
||||||
"rxjs": "5.4.0",
|
"rxjs": "5.4.0",
|
||||||
"semver": "4.3.6",
|
"semver": "4.3.6",
|
||||||
"slickgrid": "github:anthonydresser/SlickGrid#2.3.23",
|
"slickgrid": "github:anthonydresser/SlickGrid#2.3.24",
|
||||||
"spdlog": "0.6.0",
|
"spdlog": "0.6.0",
|
||||||
"sudo-prompt": "^8.0.0",
|
"sudo-prompt": "^8.0.0",
|
||||||
"svg.js": "^2.2.5",
|
"svg.js": "^2.2.5",
|
||||||
|
|||||||
@@ -0,0 +1,64 @@
|
|||||||
|
/*---------------------------------------------------------------------------------------------
|
||||||
|
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||||
|
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||||
|
*--------------------------------------------------------------------------------------------*/
|
||||||
|
|
||||||
|
'use strict';
|
||||||
|
|
||||||
|
import { StandardKeyboardEvent } from 'vs/base/browser/keyboardEvent';
|
||||||
|
import { KeyCode, KeyMod } from 'vs/base/common/keyCodes';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Implements the various additional navigation keybindings we want out of slickgrid
|
||||||
|
*/
|
||||||
|
export class AdditionalKeyBindings<T> implements Slick.Plugin<T> {
|
||||||
|
private grid: Slick.Grid<T>;
|
||||||
|
private handler = new Slick.EventHandler();
|
||||||
|
|
||||||
|
public init(grid: Slick.Grid<T>) {
|
||||||
|
this.grid = grid;
|
||||||
|
this.handler.subscribe(this.grid.onKeyDown, (e, args) => this.handleKeyDown(e, args));
|
||||||
|
}
|
||||||
|
|
||||||
|
public destroy() {
|
||||||
|
this.handler.unsubscribeAll();
|
||||||
|
}
|
||||||
|
|
||||||
|
private handleKeyDown(e: KeyboardEvent, args: Slick.OnKeyDownEventArgs<T>): void {
|
||||||
|
let event = new StandardKeyboardEvent(e);
|
||||||
|
let handled = true;
|
||||||
|
|
||||||
|
if (event.equals(KeyCode.RightArrow | KeyMod.CtrlCmd)) {
|
||||||
|
this.grid.setActiveCell(args.row, this.grid.getColumns().length - 1);
|
||||||
|
} else if (event.equals(KeyCode.LeftArrow | KeyMod.CtrlCmd)) {
|
||||||
|
// account for row column
|
||||||
|
if (this.grid.canCellBeActive(args.row, 0)) {
|
||||||
|
this.grid.setActiveCell(args.row, 0);
|
||||||
|
} else {
|
||||||
|
this.grid.setActiveCell(args.row, 1);
|
||||||
|
}
|
||||||
|
} else if (event.equals(KeyCode.UpArrow | KeyMod.CtrlCmd)) {
|
||||||
|
this.grid.setActiveCell(0, args.cell);
|
||||||
|
} else if (event.equals(KeyCode.DownArrow | KeyMod.CtrlCmd)) {
|
||||||
|
this.grid.setActiveCell(this.grid.getDataLength() - 1, args.cell);
|
||||||
|
} else if (event.equals(KeyCode.Home | KeyMod.CtrlCmd)) {
|
||||||
|
// account for row column
|
||||||
|
if (this.grid.canCellBeActive(0, 0)) {
|
||||||
|
this.grid.setActiveCell(0, 0);
|
||||||
|
} else {
|
||||||
|
this.grid.setActiveCell(0, 1);
|
||||||
|
}
|
||||||
|
} else if (event.equals(KeyCode.End | KeyMod.CtrlCmd)) {
|
||||||
|
this.grid.setActiveCell(this.grid.getDataLength() - 1, this.grid.getColumns().length - 1);
|
||||||
|
} else {
|
||||||
|
handled = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (handled) {
|
||||||
|
e.preventDefault();
|
||||||
|
e.stopPropagation();
|
||||||
|
e.stopImmediatePropagation();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -16,7 +16,7 @@ export class AutoColumnSize<T> implements Slick.Plugin<T> {
|
|||||||
private _context: CanvasRenderingContext2D;
|
private _context: CanvasRenderingContext2D;
|
||||||
private _options: IAutoColumnSizeOptions;
|
private _options: IAutoColumnSizeOptions;
|
||||||
|
|
||||||
constructor(options: IAutoColumnSizeOptions) {
|
constructor(options: IAutoColumnSizeOptions = defaultOptions) {
|
||||||
this._options = mixin(options, defaultOptions, false);
|
this._options = mixin(options, defaultOptions, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,192 @@
|
|||||||
|
// Drag select selection model gist taken from https://gist.github.com/skoon/5312536
|
||||||
|
// heavily modified
|
||||||
|
|
||||||
|
import { mixin } from 'vs/base/common/objects';
|
||||||
|
import { isUndefinedOrNull } from 'vs/base/common/types';
|
||||||
|
import { IThemeService } from 'vs/platform/theme/common/themeService';
|
||||||
|
|
||||||
|
require.__$__nodeRequire('slickgrid/plugins/slick.cellrangedecorator');
|
||||||
|
require.__$__nodeRequire('slickgrid/plugins/slick.cellrangeselector');
|
||||||
|
|
||||||
|
export interface ICellRangeSelector<T> extends Slick.Plugin<T> {
|
||||||
|
onCellRangeSelected: Slick.Event<{ range: Slick.Range }>;
|
||||||
|
onBeforeCellRangeSelected: Slick.Event<Slick.Cell>;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface ICellSelectionModelOptions {
|
||||||
|
cellRangeSelector?: any;
|
||||||
|
selectActiveCell?: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
const defaults: ICellSelectionModelOptions = {
|
||||||
|
selectActiveCell: true
|
||||||
|
};
|
||||||
|
|
||||||
|
export class CellSelectionModel<T> implements Slick.SelectionModel<T, Array<Slick.Range>> {
|
||||||
|
private grid: Slick.Grid<T>;
|
||||||
|
private selector: ICellRangeSelector<T>;
|
||||||
|
private ranges: Array<Slick.Range> = [];
|
||||||
|
|
||||||
|
public onSelectedRangesChanged = new Slick.Event<Array<Slick.Range>>();
|
||||||
|
|
||||||
|
constructor(private options: ICellSelectionModelOptions = defaults) {
|
||||||
|
this.options = mixin(this.options, defaults, false);
|
||||||
|
|
||||||
|
if (this.options.cellRangeSelector) {
|
||||||
|
this.selector = this.options.cellRangeSelector;
|
||||||
|
} else {
|
||||||
|
// this is added by the noderequires above
|
||||||
|
this.selector = new (<any>Slick).CellRangeSelector({ selectionCss: { 'border': '2px dashed grey' } });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public init(grid: Slick.Grid<T>) {
|
||||||
|
this.grid = grid;
|
||||||
|
this.grid.onActiveCellChanged.subscribe((e, args) => this.handleActiveCellChange(e, args));
|
||||||
|
this.grid.onKeyDown.subscribe(e => this.handleKeyDown(e));
|
||||||
|
this.grid.onHeaderClick.subscribe((e: MouseEvent, args) => this.handleHeaderClick(e, args));
|
||||||
|
this.grid.registerPlugin(this.selector);
|
||||||
|
this.selector.onCellRangeSelected.subscribe((e, args) => this.handleCellRangeSelected(e, args));
|
||||||
|
this.selector.onBeforeCellRangeSelected.subscribe((e, args) => this.handleBeforeCellRangeSelected(e, args));
|
||||||
|
}
|
||||||
|
|
||||||
|
public destroy() {
|
||||||
|
this.grid.onActiveCellChanged.unsubscribe((e, args) => this.handleActiveCellChange(e, args));
|
||||||
|
this.grid.onKeyDown.unsubscribe(e => this.handleKeyDown(e));
|
||||||
|
this.selector.onCellRangeSelected.unsubscribe((e, args) => this.handleCellRangeSelected(e, args));
|
||||||
|
this.selector.onBeforeCellRangeSelected.unsubscribe((e, args) => this.handleBeforeCellRangeSelected(e, args));
|
||||||
|
this.grid.unregisterPlugin(this.selector);
|
||||||
|
}
|
||||||
|
|
||||||
|
private removeInvalidRanges(ranges: Array<Slick.Range>): Array<Slick.Range> {
|
||||||
|
let result: Array<Slick.Range> = [];
|
||||||
|
|
||||||
|
for (let i = 0; i < ranges.length; i++) {
|
||||||
|
let r = ranges[i];
|
||||||
|
if (this.grid.canCellBeSelected(r.fromRow, r.fromCell) && this.grid.canCellBeSelected(r.toRow, r.toCell)) {
|
||||||
|
result.push(r);
|
||||||
|
} else if (this.grid.canCellBeSelected(r.fromRow, r.fromCell + 1) && this.grid.canCellBeSelected(r.toRow, r.toCell)) {
|
||||||
|
// account for number row
|
||||||
|
result.push(new Slick.Range(r.fromRow, r.fromCell + 1, r.toRow, r.toCell));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
public setSelectedRanges(ranges: Array<Slick.Range>): void {
|
||||||
|
// simple check for: empty selection didn't change, prevent firing onSelectedRangesChanged
|
||||||
|
if ((!this.ranges || this.ranges.length === 0) && (!ranges || ranges.length === 0)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.ranges = this.removeInvalidRanges(ranges);
|
||||||
|
this.onSelectedRangesChanged.notify(this.ranges);
|
||||||
|
}
|
||||||
|
|
||||||
|
public getSelectedRanges() {
|
||||||
|
return this.ranges;
|
||||||
|
}
|
||||||
|
|
||||||
|
private handleBeforeCellRangeSelected(e, args: Slick.Cell) {
|
||||||
|
if (this.grid.getEditorLock().isActive()) {
|
||||||
|
e.stopPropagation();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
private handleCellRangeSelected(e, args: { range: Slick.Range }) {
|
||||||
|
this.grid.setActiveCell(args.range.fromRow, args.range.fromCell, false, false, true);
|
||||||
|
this.setSelectedRanges([args.range]);
|
||||||
|
}
|
||||||
|
|
||||||
|
private handleActiveCellChange(e, args) {
|
||||||
|
if (this.options.selectActiveCell && !isUndefinedOrNull(args.row) && !isUndefinedOrNull(args.cell)) {
|
||||||
|
this.setSelectedRanges([new Slick.Range(args.row, args.cell)]);
|
||||||
|
} else if (!this.options.selectActiveCell) {
|
||||||
|
// clear the previous selection once the cell changes
|
||||||
|
this.setSelectedRanges([]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private handleHeaderClick(e: MouseEvent, args: Slick.OnHeaderClickEventArgs<T>) {
|
||||||
|
if (!isUndefinedOrNull(args.column)) {
|
||||||
|
let columnIndex = this.grid.getColumnIndex(args.column.id);
|
||||||
|
if (this.grid.canCellBeSelected(0, columnIndex)) {
|
||||||
|
let ranges: Array<Slick.Range>;
|
||||||
|
if (e.shiftKey) {
|
||||||
|
ranges = this.getSelectedRanges();
|
||||||
|
ranges.push(new Slick.Range(0, columnIndex, this.grid.getDataLength() - 1, columnIndex));
|
||||||
|
} else {
|
||||||
|
ranges = [new Slick.Range(0, columnIndex, this.grid.getDataLength() - 1, columnIndex)];
|
||||||
|
}
|
||||||
|
this.grid.setActiveCell(0, columnIndex);
|
||||||
|
this.setSelectedRanges(ranges);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private handleKeyDown(e) {
|
||||||
|
/***
|
||||||
|
* Кey codes
|
||||||
|
* 37 left
|
||||||
|
* 38 up
|
||||||
|
* 39 right
|
||||||
|
* 40 down
|
||||||
|
*/
|
||||||
|
let ranges, last;
|
||||||
|
let active = this.grid.getActiveCell();
|
||||||
|
let metaKey = e.ctrlKey || e.metaKey;
|
||||||
|
|
||||||
|
if (active && e.shiftKey && !metaKey && !e.altKey &&
|
||||||
|
(e.which === 37 || e.which === 39 || e.which === 38 || e.which === 40)) {
|
||||||
|
|
||||||
|
ranges = this.getSelectedRanges();
|
||||||
|
if (!ranges.length) {
|
||||||
|
ranges.push(new Slick.Range(active.row, active.cell));
|
||||||
|
}
|
||||||
|
|
||||||
|
// keyboard can work with last range only
|
||||||
|
last = ranges.pop();
|
||||||
|
|
||||||
|
// can't handle selection out of active cell
|
||||||
|
if (!last.contains(active.row, active.cell)) {
|
||||||
|
last = new Slick.Range(active.row, active.cell);
|
||||||
|
}
|
||||||
|
|
||||||
|
let dRow = last.toRow - last.fromRow,
|
||||||
|
dCell = last.toCell - last.fromCell,
|
||||||
|
// walking direction
|
||||||
|
dirRow = active.row === last.fromRow ? 1 : -1,
|
||||||
|
dirCell = active.cell === last.fromCell ? 1 : -1;
|
||||||
|
|
||||||
|
if (e.which === 37) {
|
||||||
|
dCell -= dirCell;
|
||||||
|
} else if (e.which === 39) {
|
||||||
|
dCell += dirCell;
|
||||||
|
} else if (e.which === 38) {
|
||||||
|
dRow -= dirRow;
|
||||||
|
} else if (e.which === 40) {
|
||||||
|
dRow += dirRow;
|
||||||
|
}
|
||||||
|
|
||||||
|
// define new selection range
|
||||||
|
let new_last = new Slick.Range(active.row, active.cell, active.row + dirRow * dRow, active.cell + dirCell * dCell);
|
||||||
|
if (this.removeInvalidRanges([new_last]).length) {
|
||||||
|
ranges.push(new_last);
|
||||||
|
let viewRow = dirRow > 0 ? new_last.toRow : new_last.fromRow;
|
||||||
|
let viewCell = dirCell > 0 ? new_last.toCell : new_last.fromCell;
|
||||||
|
this.grid.scrollRowIntoView(viewRow, false);
|
||||||
|
this.grid.scrollCellIntoView(viewRow, viewCell, false);
|
||||||
|
} else {
|
||||||
|
ranges.push(last);
|
||||||
|
}
|
||||||
|
|
||||||
|
this.setSelectedRanges(ranges);
|
||||||
|
|
||||||
|
e.preventDefault();
|
||||||
|
e.stopPropagation();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,364 +0,0 @@
|
|||||||
// Drag select selection model gist taken from https://gist.github.com/skoon/5312536
|
|
||||||
// heavily modified
|
|
||||||
|
|
||||||
import { clone } from 'sql/base/common/objects';
|
|
||||||
|
|
||||||
export class DragCellSelectionModel<T> implements Slick.SelectionModel<T, Array<Slick.Range>> {
|
|
||||||
private readonly keyColResizeIncr = 5;
|
|
||||||
|
|
||||||
private _grid: Slick.Grid<T>;
|
|
||||||
private _ranges: Array<Slick.Range> = [];
|
|
||||||
private _dragging = false;
|
|
||||||
private _handler = new Slick.EventHandler();
|
|
||||||
|
|
||||||
public onSelectedRangesChanged = new Slick.Event<Slick.Range[]>();
|
|
||||||
|
|
||||||
public init(grid: Slick.Grid<T>): void {
|
|
||||||
this._grid = grid;
|
|
||||||
this._handler.subscribe(this._grid.onActiveCellChanged, (e: Event, data: Slick.OnActiveCellChangedEventArgs<T>) => this.handleActiveCellChange(e, data));
|
|
||||||
this._handler.subscribe(this._grid.onKeyDown, (e: JQueryInputEventObject) => this.handleKeyDown(e));
|
|
||||||
this._handler.subscribe(this._grid.onClick, (e: MouseEvent) => this.handleClick(e));
|
|
||||||
this._handler.subscribe(this._grid.onDrag, (e: MouseEvent) => this.handleDrag(e));
|
|
||||||
this._handler.subscribe(this._grid.onDragInit, (e: MouseEvent) => this.handleDragInit(e));
|
|
||||||
this._handler.subscribe(this._grid.onDragStart, (e: MouseEvent) => this.handleDragStart(e));
|
|
||||||
this._handler.subscribe(this._grid.onDragEnd, (e: MouseEvent) => this.handleDragEnd(e));
|
|
||||||
this._handler.subscribe(this._grid.onHeaderClick, (e: MouseEvent, args: Slick.OnHeaderClickEventArgs<T>) => this.handleHeaderClick(e, args));
|
|
||||||
}
|
|
||||||
|
|
||||||
public destroy(): void {
|
|
||||||
this._handler.unsubscribeAll();
|
|
||||||
}
|
|
||||||
|
|
||||||
private rangesToRows(ranges: Array<Slick.Range>): Array<number> {
|
|
||||||
let rows = [];
|
|
||||||
for (let i = 0; i < ranges.length; i++) {
|
|
||||||
for (let j = ranges[i].fromRow; j <= ranges[i].toRow; j++) {
|
|
||||||
rows.push(j);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return rows;
|
|
||||||
}
|
|
||||||
|
|
||||||
private rowsToRanges(rows: Array<number>): Array<Slick.Range> {
|
|
||||||
let ranges = [];
|
|
||||||
let lastCell = this._grid.getColumns().length - 1;
|
|
||||||
for (let i = 0; i < rows.length; i++) {
|
|
||||||
ranges.push(new Slick.Range(rows[i], 0, rows[i], lastCell));
|
|
||||||
}
|
|
||||||
return ranges;
|
|
||||||
}
|
|
||||||
|
|
||||||
public getSelectedRows(): Array<number> {
|
|
||||||
return this.rangesToRows(this._ranges);
|
|
||||||
}
|
|
||||||
|
|
||||||
public setSelectedRows(rows: Array<number>) {
|
|
||||||
this.setSelectedRanges(this.rowsToRanges(rows));
|
|
||||||
}
|
|
||||||
|
|
||||||
public setSelectedRanges(ranges: Array<Slick.Range>) {
|
|
||||||
this._ranges = ranges;
|
|
||||||
this.onSelectedRangesChanged.notify(this._ranges);
|
|
||||||
}
|
|
||||||
|
|
||||||
public getSelectedRanges(): Array<Slick.Range> {
|
|
||||||
return this._ranges;
|
|
||||||
}
|
|
||||||
|
|
||||||
private handleActiveCellChange(e: Event, data: Slick.OnActiveCellChangedEventArgs<T>) { }
|
|
||||||
|
|
||||||
private isNavigationKey(e: BaseJQueryEventObject) {
|
|
||||||
// Nave keys (home, end, arrows) are all in sequential order so use a
|
|
||||||
switch (e.which) {
|
|
||||||
case $.ui.keyCode.HOME:
|
|
||||||
case $.ui.keyCode.END:
|
|
||||||
case $.ui.keyCode.LEFT:
|
|
||||||
case $.ui.keyCode.UP:
|
|
||||||
case $.ui.keyCode.RIGHT:
|
|
||||||
case $.ui.keyCode.DOWN:
|
|
||||||
return true;
|
|
||||||
default:
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private navigateLeft(e: JQueryInputEventObject, activeCell: Slick.Cell) {
|
|
||||||
if (activeCell.cell > 1) {
|
|
||||||
let isHome = e.which === $.ui.keyCode.HOME;
|
|
||||||
let newActiveCellColumn = isHome ? 1 : activeCell.cell - 1;
|
|
||||||
// Unsure why but for range, must record 1 index less than expected
|
|
||||||
let newRangeColumn = newActiveCellColumn - 1;
|
|
||||||
|
|
||||||
if (e.shiftKey) {
|
|
||||||
let last = this._ranges.pop();
|
|
||||||
|
|
||||||
// If we are on the rightmost edge of the range and we navigate left,
|
|
||||||
// we want to deselect the rightmost cell
|
|
||||||
if (last.fromCell <= newRangeColumn) { last.toCell -= 1; }
|
|
||||||
|
|
||||||
let fromRow = Math.min(activeCell.row, last.fromRow);
|
|
||||||
let fromCell = Math.min(newRangeColumn, last.fromCell);
|
|
||||||
let toRow = Math.max(activeCell.row, last.toRow);
|
|
||||||
let toCell = Math.max(newRangeColumn, last.toCell);
|
|
||||||
this._ranges = [new Slick.Range(fromRow, fromCell, toRow, toCell)];
|
|
||||||
} else {
|
|
||||||
this._ranges = [new Slick.Range(activeCell.row, newRangeColumn, activeCell.row, newRangeColumn)];
|
|
||||||
}
|
|
||||||
|
|
||||||
this._grid.setActiveCell(activeCell.row, newActiveCellColumn);
|
|
||||||
this.setSelectedRanges(this._ranges);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private navigateRight(e: JQueryInputEventObject, activeCell: Slick.Cell) {
|
|
||||||
let columnLength = this._grid.getColumns().length;
|
|
||||||
if (activeCell.cell < columnLength) {
|
|
||||||
let isEnd = e.which === $.ui.keyCode.END;
|
|
||||||
let newActiveCellColumn = isEnd ? columnLength : activeCell.cell + 1;
|
|
||||||
// Unsure why but for range, must record 1 index less than expected
|
|
||||||
let newRangeColumn = newActiveCellColumn - 1;
|
|
||||||
if (e.shiftKey) {
|
|
||||||
let last = this._ranges.pop();
|
|
||||||
|
|
||||||
// If we are on the leftmost edge of the range and we navigate right,
|
|
||||||
// we want to deselect the leftmost cell
|
|
||||||
if (newRangeColumn <= last.toCell) { last.fromCell += 1; }
|
|
||||||
|
|
||||||
let fromRow = Math.min(activeCell.row, last.fromRow);
|
|
||||||
let fromCell = Math.min(newRangeColumn, last.fromCell);
|
|
||||||
let toRow = Math.max(activeCell.row, last.toRow);
|
|
||||||
let toCell = Math.max(newRangeColumn, last.toCell);
|
|
||||||
|
|
||||||
this._ranges = [new Slick.Range(fromRow, fromCell, toRow, toCell)];
|
|
||||||
} else {
|
|
||||||
this._ranges = [new Slick.Range(activeCell.row, newRangeColumn, activeCell.row, newRangeColumn)];
|
|
||||||
}
|
|
||||||
this._grid.setActiveCell(activeCell.row, newActiveCellColumn);
|
|
||||||
this.setSelectedRanges(this._ranges);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private handleKeyDown(e: JQueryInputEventObject) {
|
|
||||||
let activeCell = this._grid.getActiveCell();
|
|
||||||
|
|
||||||
if (activeCell) {
|
|
||||||
// navigation keys
|
|
||||||
if (this.isNavigationKey(e)) {
|
|
||||||
e.stopImmediatePropagation();
|
|
||||||
if (e.ctrlKey || e.metaKey) {
|
|
||||||
let event = new CustomEvent('gridnav', {
|
|
||||||
detail: {
|
|
||||||
which: e.which,
|
|
||||||
ctrlKey: e.ctrlKey,
|
|
||||||
metaKey: e.metaKey,
|
|
||||||
shiftKey: e.shiftKey,
|
|
||||||
altKey: e.altKey
|
|
||||||
}
|
|
||||||
});
|
|
||||||
window.dispatchEvent(event);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
// end key
|
|
||||||
if (e.which === $.ui.keyCode.END) {
|
|
||||||
this.navigateRight(e, activeCell);
|
|
||||||
}
|
|
||||||
// home key
|
|
||||||
if (e.which === $.ui.keyCode.HOME) {
|
|
||||||
this.navigateLeft(e, activeCell);
|
|
||||||
}
|
|
||||||
// left arrow
|
|
||||||
if (e.which === $.ui.keyCode.LEFT) {
|
|
||||||
// column resize
|
|
||||||
if ((e.ctrlKey || e.metaKey) && e.shiftKey) {
|
|
||||||
let allColumns = clone(this._grid.getColumns());
|
|
||||||
allColumns[activeCell.cell - 1].width = allColumns[activeCell.cell - 1].width - this.keyColResizeIncr;
|
|
||||||
this._grid.setColumnWidths(allColumns);
|
|
||||||
} else {
|
|
||||||
this.navigateLeft(e, activeCell);
|
|
||||||
}
|
|
||||||
// up arrow
|
|
||||||
} else if (e.which === $.ui.keyCode.UP && activeCell.row > 0) {
|
|
||||||
if (e.shiftKey) {
|
|
||||||
let last = this._ranges.pop();
|
|
||||||
|
|
||||||
// If we are on the bottommost edge of the range and we navigate up,
|
|
||||||
// we want to deselect the bottommost row
|
|
||||||
let newRangeRow = activeCell.row - 1;
|
|
||||||
if (last.fromRow <= newRangeRow) { last.toRow -= 1; }
|
|
||||||
|
|
||||||
let fromRow = Math.min(activeCell.row - 1, last.fromRow);
|
|
||||||
let fromCell = Math.min(activeCell.cell - 1, last.fromCell);
|
|
||||||
let toRow = Math.max(newRangeRow, last.toRow);
|
|
||||||
let toCell = Math.max(activeCell.cell - 1, last.toCell);
|
|
||||||
this._ranges = [new Slick.Range(fromRow, fromCell, toRow, toCell)];
|
|
||||||
} else {
|
|
||||||
this._ranges = [new Slick.Range(activeCell.row - 1, activeCell.cell - 1, activeCell.row - 1, activeCell.cell - 1)];
|
|
||||||
}
|
|
||||||
this._grid.setActiveCell(activeCell.row - 1, activeCell.cell);
|
|
||||||
this.setSelectedRanges(this._ranges);
|
|
||||||
// right arrow
|
|
||||||
} else if (e.which === $.ui.keyCode.RIGHT) {
|
|
||||||
// column resize
|
|
||||||
if ((e.ctrlKey || e.metaKey) && e.shiftKey) {
|
|
||||||
let allColumns = clone(this._grid.getColumns());
|
|
||||||
allColumns[activeCell.cell - 1].width = allColumns[activeCell.cell - 1].width + this.keyColResizeIncr;
|
|
||||||
this._grid.setColumnWidths(allColumns);
|
|
||||||
} else {
|
|
||||||
this.navigateRight(e, activeCell);
|
|
||||||
}
|
|
||||||
// down arrow
|
|
||||||
} else if (e.which === $.ui.keyCode.DOWN && activeCell.row < this._grid.getDataLength() - 1) {
|
|
||||||
if (e.shiftKey) {
|
|
||||||
let last = this._ranges.pop();
|
|
||||||
|
|
||||||
// If we are on the topmost edge of the range and we navigate down,
|
|
||||||
// we want to deselect the topmost row
|
|
||||||
let newRangeRow = activeCell.row + 1;
|
|
||||||
if (newRangeRow <= last.toRow) { last.fromRow += 1; }
|
|
||||||
|
|
||||||
let fromRow = Math.min(activeCell.row + 1, last.fromRow);
|
|
||||||
let fromCell = Math.min(activeCell.cell - 1, last.fromCell);
|
|
||||||
let toRow = Math.max(activeCell.row + 1, last.toRow);
|
|
||||||
let toCell = Math.max(activeCell.cell - 1, last.toCell);
|
|
||||||
this._ranges = [new Slick.Range(fromRow, fromCell, toRow, toCell)];
|
|
||||||
} else {
|
|
||||||
this._ranges = [new Slick.Range(activeCell.row + 1, activeCell.cell - 1, activeCell.row + 1, activeCell.cell - 1)];
|
|
||||||
}
|
|
||||||
this._grid.setActiveCell(activeCell.row + 1, activeCell.cell);
|
|
||||||
this.setSelectedRanges(this._ranges);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private handleHeaderClick(e: MouseEvent, args: Slick.OnHeaderClickEventArgs<T>) {
|
|
||||||
let columnIndex = this._grid.getColumnIndex(args.column.id);
|
|
||||||
if (e.ctrlKey || e.metaKey) {
|
|
||||||
this._ranges.push(new Slick.Range(0, columnIndex, this._grid.getDataLength() - 1, columnIndex));
|
|
||||||
this._grid.setActiveCell(0, columnIndex + 1);
|
|
||||||
} else if (e.shiftKey && this._ranges.length) {
|
|
||||||
let last = this._ranges.pop().fromCell;
|
|
||||||
let from = Math.min(columnIndex, last);
|
|
||||||
let to = Math.max(columnIndex, last);
|
|
||||||
this._ranges = [];
|
|
||||||
for (let i = from; i <= to; i++) {
|
|
||||||
if (i !== last) {
|
|
||||||
this._ranges.push(new Slick.Range(0, i, this._grid.getDataLength() - 1, i));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
this._ranges.push(new Slick.Range(0, last, this._grid.getDataLength() - 1, last));
|
|
||||||
} else {
|
|
||||||
this._ranges = [new Slick.Range(0, columnIndex, this._grid.getDataLength() - 1, columnIndex)];
|
|
||||||
this._grid.resetActiveCell();
|
|
||||||
}
|
|
||||||
this.setSelectedRanges(this._ranges);
|
|
||||||
e.stopImmediatePropagation();
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
private handleClick(e: MouseEvent) {
|
|
||||||
let cell = this._grid.getCellFromEvent(e);
|
|
||||||
if (!cell || !this._grid.canCellBeActive(cell.row, cell.cell)) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!e.ctrlKey && !e.shiftKey && !e.metaKey) {
|
|
||||||
if (cell.cell !== 0) {
|
|
||||||
this._ranges = [new Slick.Range(cell.row, cell.cell - 1, cell.row, cell.cell - 1)];
|
|
||||||
this.setSelectedRanges(this._ranges);
|
|
||||||
this._grid.setActiveCell(cell.row, cell.cell);
|
|
||||||
return true;
|
|
||||||
} else {
|
|
||||||
this._ranges = [new Slick.Range(cell.row, 0, cell.row, this._grid.getColumns().length - 1)];
|
|
||||||
this.setSelectedRanges(this._ranges);
|
|
||||||
this._grid.setActiveCell(cell.row, 1);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if (this._grid.getOptions().multiSelect) {
|
|
||||||
if (e.ctrlKey || e.metaKey) {
|
|
||||||
if (cell.cell === 0) {
|
|
||||||
this._ranges.push(new Slick.Range(cell.row, 0, cell.row, this._grid.getColumns().length - 1));
|
|
||||||
this._grid.setActiveCell(cell.row, 1);
|
|
||||||
} else {
|
|
||||||
this._ranges.push(new Slick.Range(cell.row, cell.cell - 1, cell.row, cell.cell - 1));
|
|
||||||
this._grid.setActiveCell(cell.row, cell.cell);
|
|
||||||
}
|
|
||||||
} else if (this._ranges.length && e.shiftKey) {
|
|
||||||
let last = this._ranges.pop();
|
|
||||||
if (cell.cell === 0) {
|
|
||||||
let fromRow = Math.min(cell.row, last.fromRow);
|
|
||||||
let toRow = Math.max(cell.row, last.fromRow);
|
|
||||||
this._ranges = [new Slick.Range(fromRow, 0, toRow, this._grid.getColumns().length - 1)];
|
|
||||||
} else {
|
|
||||||
let fromRow = Math.min(cell.row, last.fromRow);
|
|
||||||
let fromCell = Math.min(cell.cell - 1, last.fromCell);
|
|
||||||
let toRow = Math.max(cell.row, last.toRow);
|
|
||||||
let toCell = Math.max(cell.cell - 1, last.toCell);
|
|
||||||
this._ranges = [new Slick.Range(fromRow, fromCell, toRow, toCell)];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
this.setSelectedRanges(this._ranges);
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
private handleDragInit(e: MouseEvent) {
|
|
||||||
e.stopImmediatePropagation();
|
|
||||||
}
|
|
||||||
|
|
||||||
private handleDragStart(e: MouseEvent) {
|
|
||||||
let cell = this._grid.getCellFromEvent(e);
|
|
||||||
e.stopImmediatePropagation();
|
|
||||||
this._dragging = true;
|
|
||||||
if (e.ctrlKey || e.metaKey) {
|
|
||||||
this._ranges.push(new Slick.Range(cell.row, cell.cell));
|
|
||||||
this._grid.setActiveCell(cell.row, cell.cell);
|
|
||||||
} else if (this._ranges.length && e.shiftKey) {
|
|
||||||
let last = this._ranges.pop();
|
|
||||||
let fromRow = Math.min(cell.row, last.fromRow);
|
|
||||||
let fromCell = Math.min(cell.cell - 1, last.fromCell);
|
|
||||||
let toRow = Math.max(cell.row, last.toRow);
|
|
||||||
let toCell = Math.max(cell.cell - 1, last.toCell);
|
|
||||||
this._ranges = [new Slick.Range(fromRow, fromCell, toRow, toCell)];
|
|
||||||
} else {
|
|
||||||
this._ranges = [new Slick.Range(cell.row, cell.cell)];
|
|
||||||
this._grid.setActiveCell(cell.row, cell.cell);
|
|
||||||
}
|
|
||||||
this.setSelectedRanges(this._ranges);
|
|
||||||
}
|
|
||||||
|
|
||||||
private handleDrag(e: MouseEvent) {
|
|
||||||
if (this._dragging) {
|
|
||||||
let cell = this._grid.getCellFromEvent(e);
|
|
||||||
let activeCell = this._grid.getActiveCell();
|
|
||||||
if (!cell || !this._grid.canCellBeActive(cell.row, cell.cell)) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
this._ranges.pop();
|
|
||||||
|
|
||||||
if (activeCell.cell === 0) {
|
|
||||||
let lastCell = this._grid.getColumns().length - 1;
|
|
||||||
let firstRow = Math.min(cell.row, activeCell.row);
|
|
||||||
let lastRow = Math.max(cell.row, activeCell.row);
|
|
||||||
this._ranges.push(new Slick.Range(firstRow, 0, lastRow, lastCell));
|
|
||||||
} else {
|
|
||||||
let firstRow = Math.min(cell.row, activeCell.row);
|
|
||||||
let lastRow = Math.max(cell.row, activeCell.row);
|
|
||||||
let firstColumn = Math.min(cell.cell - 1, activeCell.cell - 1);
|
|
||||||
let lastColumn = Math.max(cell.cell - 1, activeCell.cell - 1);
|
|
||||||
this._ranges.push(new Slick.Range(firstRow, firstColumn, lastRow, lastColumn));
|
|
||||||
}
|
|
||||||
this.setSelectedRanges(this._ranges);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
private handleDragEnd(e: MouseEvent) {
|
|
||||||
this._dragging = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -0,0 +1,70 @@
|
|||||||
|
/*---------------------------------------------------------------------------------------------
|
||||||
|
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||||
|
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||||
|
*--------------------------------------------------------------------------------------------*/
|
||||||
|
|
||||||
|
'use strict';
|
||||||
|
|
||||||
|
import { range } from 'vs/base/common/arrays';
|
||||||
|
|
||||||
|
export interface IRowNumberColumnOptions {
|
||||||
|
numberOfRows: number;
|
||||||
|
cssClass?: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
const sizePerDigit = 15;
|
||||||
|
|
||||||
|
export class RowNumberColumn<T> implements Slick.Plugin<T> {
|
||||||
|
private handler = new Slick.EventHandler();
|
||||||
|
private grid: Slick.Grid<T>;
|
||||||
|
|
||||||
|
|
||||||
|
constructor(private options: IRowNumberColumnOptions) {
|
||||||
|
}
|
||||||
|
|
||||||
|
public init(grid: Slick.Grid<T>) {
|
||||||
|
this.grid = grid;
|
||||||
|
this.handler
|
||||||
|
.subscribe(this.grid.onClick, (e, args) => this.handleClick(e, args))
|
||||||
|
.subscribe(this.grid.onHeaderClick, (e, args) => this.handleHeaderClick(e, args));
|
||||||
|
}
|
||||||
|
|
||||||
|
public destroy() {
|
||||||
|
this.handler.unsubscribeAll();
|
||||||
|
}
|
||||||
|
|
||||||
|
private handleClick(e: MouseEvent, args: Slick.OnClickEventArgs<T>): void {
|
||||||
|
if (this.grid.getColumns()[args.cell].id === 'rowNumber') {
|
||||||
|
this.grid.setActiveCell(args.row, 1);
|
||||||
|
this.grid.setSelectedRows([args.row]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private handleHeaderClick(e: MouseEvent, args: Slick.OnHeaderClickEventArgs<T>): void {
|
||||||
|
if (args.column.id === 'rowNumber') {
|
||||||
|
this.grid.setActiveCell(0, 1);
|
||||||
|
this.grid.setSelectedRows(range(this.grid.getDataLength()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public getColumnDefinition(): Slick.Column<T> {
|
||||||
|
return {
|
||||||
|
id: 'rowNumber',
|
||||||
|
name: '',
|
||||||
|
field: 'rowNumber',
|
||||||
|
width: this.options.numberOfRows.toString().length * sizePerDigit,
|
||||||
|
resizable: false,
|
||||||
|
cssClass: this.options.cssClass,
|
||||||
|
focusable: false,
|
||||||
|
selectable: false,
|
||||||
|
formatter: (r, c, v, cd, dc) => this.formatter(r, c, v, cd, dc)
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
private formatter(row, cell, value, columnDef: Slick.Column<T>, dataContext): string {
|
||||||
|
if (dataContext) {
|
||||||
|
return `<span>${row}</span>`;
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -11,8 +11,8 @@ import { IWorkbenchThemeService } from 'vs/workbench/services/themes/common/work
|
|||||||
import { IInsightsView, IInsightData } from 'sql/parts/dashboard/widgets/insights/interfaces';
|
import { IInsightsView, IInsightData } from 'sql/parts/dashboard/widgets/insights/interfaces';
|
||||||
import { Table } from 'sql/base/browser/ui/table/table';
|
import { Table } from 'sql/base/browser/ui/table/table';
|
||||||
import { TableDataView } from 'sql/base/browser/ui/table/tableDataView';
|
import { TableDataView } from 'sql/base/browser/ui/table/tableDataView';
|
||||||
import { DragCellSelectionModel } from 'sql/base/browser/ui/table/plugins/dragCellSelectionModel.plugin';
|
import { attachTableStyler } from 'sql/common/theme/styler';
|
||||||
import { attachTableStyler} from 'sql/common/theme/styler';
|
import { CellSelectionModel } from 'sql/base/browser/ui/table/plugins/cellSelectionModel.plugin';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
template: ''
|
template: ''
|
||||||
@@ -63,7 +63,7 @@ export default class TableInsight extends Disposable implements IInsightsView, O
|
|||||||
private createTable() {
|
private createTable() {
|
||||||
if (!this.table) {
|
if (!this.table) {
|
||||||
this.table = new Table(this._elementRef.nativeElement, this.dataView, this.columns, { showRowNumber: true });
|
this.table = new Table(this._elementRef.nativeElement, this.dataView, this.columns, { showRowNumber: true });
|
||||||
this.table.setSelectionModel(new DragCellSelectionModel());
|
this.table.setSelectionModel(new CellSelectionModel());
|
||||||
this._register(attachTableStyler(this.table, this.themeService));
|
this._register(attachTableStyler(this.table, this.themeService));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,7 +4,7 @@
|
|||||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||||
*--------------------------------------------------------------------------------------------*/
|
*--------------------------------------------------------------------------------------------*/
|
||||||
|
|
||||||
import { IColumnDefinition, IObservableCollection, IGridDataRow } from 'angular2-slickgrid';
|
import { ISlickColumn, IObservableCollection, IGridDataRow } from 'angular2-slickgrid';
|
||||||
|
|
||||||
export interface ISlickRange {
|
export interface ISlickRange {
|
||||||
fromCell: number;
|
fromCell: number;
|
||||||
@@ -42,7 +42,7 @@ export interface IGridIcon {
|
|||||||
|
|
||||||
export interface IGridDataSet {
|
export interface IGridDataSet {
|
||||||
dataRows: IObservableCollection<IGridDataRow>;
|
dataRows: IObservableCollection<IGridDataRow>;
|
||||||
columnDefinitions: IColumnDefinition[];
|
columnDefinitions: ISlickColumn<any>[];
|
||||||
resized: any; // EventEmitter<any>;
|
resized: any; // EventEmitter<any>;
|
||||||
totalRows: number;
|
totalRows: number;
|
||||||
batchId: number;
|
batchId: number;
|
||||||
|
|||||||
@@ -17,14 +17,13 @@
|
|||||||
showDataTypeIcon="false"
|
showDataTypeIcon="false"
|
||||||
showHeader="true"
|
showHeader="true"
|
||||||
[resized]="dataSet.resized"
|
[resized]="dataSet.resized"
|
||||||
[plugins]="slickgridPlugins"
|
[plugins]="plugins[i]"
|
||||||
(activeCellChanged)="onActiveCellChanged($event)"
|
(activeCellChanged)="onActiveCellChanged($event)"
|
||||||
(cellEditBegin)="onCellEditBegin($event)"
|
(cellEditBegin)="onCellEditBegin($event)"
|
||||||
(cellEditExit)="onCellEditEnd($event)"
|
(cellEditExit)="onCellEditEnd($event)"
|
||||||
(rowEditBegin)="onRowEditBegin($event)"
|
(rowEditBegin)="onRowEditBegin($event)"
|
||||||
(rowEditExit)="onRowEditEnd($event)"
|
(rowEditExit)="onRowEditEnd($event)"
|
||||||
(contextMenu)="openContextMenu($event, dataSet.batchId, dataSet.resultId, i)"
|
(contextMenu)="openContextMenu($event, dataSet.batchId, dataSet.resultId, i)"
|
||||||
[isColumnEditable]="onIsColumnEditable"
|
|
||||||
[isCellEditValid]="onIsCellEditValid"
|
[isCellEditValid]="onIsCellEditValid"
|
||||||
[overrideCellFn]="overrideCellFn"
|
[overrideCellFn]="overrideCellFn"
|
||||||
enableEditing="true"
|
enableEditing="true"
|
||||||
|
|||||||
@@ -24,6 +24,9 @@ import { error } from 'sql/base/common/log';
|
|||||||
import { clone, mixin } from 'sql/base/common/objects';
|
import { clone, mixin } from 'sql/base/common/objects';
|
||||||
import { IQueryEditorService } from 'sql/parts/query/common/queryEditorService';
|
import { IQueryEditorService } from 'sql/parts/query/common/queryEditorService';
|
||||||
import { IBootstrapParams } from 'sql/services/bootstrap/bootstrapService';
|
import { IBootstrapParams } from 'sql/services/bootstrap/bootstrapService';
|
||||||
|
import { RowNumberColumn } from 'sql/base/browser/ui/table/plugins/rowNumberColumn.plugin';
|
||||||
|
import { AutoColumnSize } from 'sql/base/browser/ui/table/plugins/autoSizeColumns.plugin';
|
||||||
|
import { AdditionalKeyBindings } from 'sql/base/browser/ui/table/plugins/additionalKeyBindings.plugin';
|
||||||
import { escape } from 'sql/base/common/strings';
|
import { escape } from 'sql/base/common/strings';
|
||||||
|
|
||||||
import { INotificationService } from 'vs/platform/notification/common/notification';
|
import { INotificationService } from 'vs/platform/notification/common/notification';
|
||||||
@@ -36,7 +39,6 @@ import { IConfigurationService } from 'vs/platform/configuration/common/configur
|
|||||||
import { IClipboardService } from 'vs/platform/clipboard/common/clipboardService';
|
import { IClipboardService } from 'vs/platform/clipboard/common/clipboardService';
|
||||||
import { KeyCode } from 'vs/base/common/keyCodes';
|
import { KeyCode } from 'vs/base/common/keyCodes';
|
||||||
import { StandardKeyboardEvent } from 'vs/base/browser/keyboardEvent';
|
import { StandardKeyboardEvent } from 'vs/base/browser/keyboardEvent';
|
||||||
|
|
||||||
export const EDITDATA_SELECTOR: string = 'editdata-component';
|
export const EDITDATA_SELECTOR: string = 'editdata-component';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
@@ -66,6 +68,7 @@ export class EditDataComponent extends GridParentComponent implements OnInit, On
|
|||||||
private newRowVisible: boolean;
|
private newRowVisible: boolean;
|
||||||
private removingNewRow: boolean;
|
private removingNewRow: boolean;
|
||||||
private rowIdMappings: { [gridRowId: number]: number } = {};
|
private rowIdMappings: { [gridRowId: number]: number } = {};
|
||||||
|
protected plugins = new Array<Array<Slick.Plugin<any>>>();
|
||||||
|
|
||||||
// Edit Data functions
|
// Edit Data functions
|
||||||
public onActiveCellChanged: (event: { row: number, column: number }) => void;
|
public onActiveCellChanged: (event: { row: number, column: number }) => void;
|
||||||
@@ -167,17 +170,6 @@ export class EditDataComponent extends GridParentComponent implements OnInit, On
|
|||||||
|
|
||||||
this.onRowEditEnd = (event: { row: number }): void => { };
|
this.onRowEditEnd = (event: { row: number }): void => { };
|
||||||
|
|
||||||
this.onIsColumnEditable = (column: number): boolean => {
|
|
||||||
let result = false;
|
|
||||||
// Check that our variables exist
|
|
||||||
if (column !== undefined && !!this.dataSet && !!this.dataSet.columnDefinitions[column]) {
|
|
||||||
result = this.dataSet.columnDefinitions[column].isEditable;
|
|
||||||
}
|
|
||||||
|
|
||||||
// If no column definition exists then the row is not editable
|
|
||||||
return result;
|
|
||||||
};
|
|
||||||
|
|
||||||
this.overrideCellFn = (rowNumber, columnId, value?, data?): string => {
|
this.overrideCellFn = (rowNumber, columnId, value?, data?): string => {
|
||||||
let returnVal = '';
|
let returnVal = '';
|
||||||
if (Services.DBCellValue.isDBCellValue(value)) {
|
if (Services.DBCellValue.isDBCellValue(value)) {
|
||||||
@@ -197,9 +189,9 @@ export class EditDataComponent extends GridParentComponent implements OnInit, On
|
|||||||
self.idMapping[rowIndex] = row.id;
|
self.idMapping[rowIndex] = row.id;
|
||||||
rowIndex++;
|
rowIndex++;
|
||||||
return {
|
return {
|
||||||
values: row.cells.map(c => {
|
values: [{}].concat(row.cells.map(c => {
|
||||||
return mixin({ ariaLabel: escape(c.displayValue) }, c);
|
return mixin({ ariaLabel: escape(c.displayValue) }, c);
|
||||||
}), row: row.id
|
})), row: row.id
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -351,6 +343,8 @@ export class EditDataComponent extends GridParentComponent implements OnInit, On
|
|||||||
let maxHeight = this.getMaxHeight(resultSet.rowCount);
|
let maxHeight = this.getMaxHeight(resultSet.rowCount);
|
||||||
let minHeight = this.getMinHeight(resultSet.rowCount);
|
let minHeight = this.getMinHeight(resultSet.rowCount);
|
||||||
|
|
||||||
|
let rowNumberColumn = new RowNumberColumn({ numberOfRows: resultSet.rowCount });
|
||||||
|
|
||||||
// Store the result set from the event
|
// Store the result set from the event
|
||||||
let dataSet: IGridDataSet = {
|
let dataSet: IGridDataSet = {
|
||||||
resized: undefined,
|
resized: undefined,
|
||||||
@@ -365,7 +359,7 @@ export class EditDataComponent extends GridParentComponent implements OnInit, On
|
|||||||
this.loadDataFunction,
|
this.loadDataFunction,
|
||||||
index => { return { values: [] }; }
|
index => { return { values: [] }; }
|
||||||
),
|
),
|
||||||
columnDefinitions: resultSet.columnInfo.map((c, i) => {
|
columnDefinitions: [rowNumberColumn.getColumnDefinition()].concat(resultSet.columnInfo.map((c, i) => {
|
||||||
let isLinked = c.isXml || c.isJson;
|
let isLinked = c.isXml || c.isJson;
|
||||||
let linkType = c.isXml ? 'xml' : 'json';
|
let linkType = c.isXml ? 'xml' : 'json';
|
||||||
|
|
||||||
@@ -374,13 +368,14 @@ export class EditDataComponent extends GridParentComponent implements OnInit, On
|
|||||||
name: c.columnName === 'Microsoft SQL Server 2005 XML Showplan'
|
name: c.columnName === 'Microsoft SQL Server 2005 XML Showplan'
|
||||||
? 'XML Showplan'
|
? 'XML Showplan'
|
||||||
: escape(c.columnName),
|
: escape(c.columnName),
|
||||||
type: self.stringToFieldType('string'),
|
field: i.toString(),
|
||||||
formatter: isLinked ? Services.hyperLinkFormatter : Services.textFormatter,
|
formatter: isLinked ? Services.hyperLinkFormatter : Services.textFormatter,
|
||||||
asyncPostRender: isLinked ? self.linkHandler(linkType) : undefined,
|
asyncPostRender: isLinked ? self.linkHandler(linkType) : undefined,
|
||||||
isEditable: c.isUpdatable
|
isEditable: c.isUpdatable
|
||||||
};
|
};
|
||||||
})
|
}))
|
||||||
};
|
};
|
||||||
|
self.plugins.push([rowNumberColumn, new AutoColumnSize(), new AdditionalKeyBindings()]);
|
||||||
self.dataSet = dataSet;
|
self.dataSet = dataSet;
|
||||||
|
|
||||||
// Create a dataSet to render without rows to reduce DOM size
|
// Create a dataSet to render without rows to reduce DOM size
|
||||||
|
|||||||
@@ -26,6 +26,7 @@ import * as GridContentEvents from 'sql/parts/grid/common/gridContentEvents';
|
|||||||
import { ResultsVisibleContext, ResultsGridFocussedContext, ResultsMessagesFocussedContext, QueryEditorVisibleContext } from 'sql/parts/query/common/queryContext';
|
import { ResultsVisibleContext, ResultsGridFocussedContext, ResultsMessagesFocussedContext, QueryEditorVisibleContext } from 'sql/parts/query/common/queryContext';
|
||||||
import { error } from 'sql/base/common/log';
|
import { error } from 'sql/base/common/log';
|
||||||
import { IQueryEditorService } from 'sql/parts/query/common/queryEditorService';
|
import { IQueryEditorService } from 'sql/parts/query/common/queryEditorService';
|
||||||
|
import { CellSelectionModel } from 'sql/base/browser/ui/table/plugins/cellSelectionModel.plugin';
|
||||||
|
|
||||||
import { IAction } from 'vs/base/common/actions';
|
import { IAction } from 'vs/base/common/actions';
|
||||||
import { ResolvedKeybinding } from 'vs/base/common/keyCodes';
|
import { ResolvedKeybinding } from 'vs/base/common/keyCodes';
|
||||||
@@ -33,8 +34,6 @@ import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding';
|
|||||||
import { IContextKeyService, IContextKey } from 'vs/platform/contextkey/common/contextkey';
|
import { IContextKeyService, IContextKey } from 'vs/platform/contextkey/common/contextkey';
|
||||||
import { IContextMenuService } from 'vs/platform/contextview/browser/contextView';
|
import { IContextMenuService } from 'vs/platform/contextview/browser/contextView';
|
||||||
import { IDisposable, dispose } from 'vs/base/common/lifecycle';
|
import { IDisposable, dispose } from 'vs/base/common/lifecycle';
|
||||||
import { AutoColumnSize } from 'sql/base/browser/ui/table/plugins/autoSizeColumns.plugin';
|
|
||||||
import { DragCellSelectionModel } from 'sql/base/browser/ui/table/plugins/dragCellSelectionModel.plugin';
|
|
||||||
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
|
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
|
||||||
import { IClipboardService } from 'vs/platform/clipboard/common/clipboardService';
|
import { IClipboardService } from 'vs/platform/clipboard/common/clipboardService';
|
||||||
import { StandardKeyboardEvent } from 'vs/base/browser/keyboardEvent';
|
import { StandardKeyboardEvent } from 'vs/base/browser/keyboardEvent';
|
||||||
@@ -42,14 +41,8 @@ import { StandardKeyboardEvent } from 'vs/base/browser/keyboardEvent';
|
|||||||
export abstract class GridParentComponent {
|
export abstract class GridParentComponent {
|
||||||
// CONSTANTS
|
// CONSTANTS
|
||||||
// tslint:disable:no-unused-variable
|
// tslint:disable:no-unused-variable
|
||||||
protected get selectionModel(): DragCellSelectionModel<any> {
|
|
||||||
return new DragCellSelectionModel<any>();
|
protected get selectionModel() { return new CellSelectionModel(); }
|
||||||
}
|
|
||||||
protected get slickgridPlugins(): Array<any> {
|
|
||||||
return [
|
|
||||||
new AutoColumnSize<any>({})
|
|
||||||
];
|
|
||||||
}
|
|
||||||
protected _rowHeight = 29;
|
protected _rowHeight = 29;
|
||||||
protected _defaultNumShowingRows = 8;
|
protected _defaultNumShowingRows = 8;
|
||||||
protected Constants = Constants;
|
protected Constants = Constants;
|
||||||
@@ -94,7 +87,6 @@ export abstract class GridParentComponent {
|
|||||||
public onRowEditBegin: (event: { row: number }) => void;
|
public onRowEditBegin: (event: { row: number }) => void;
|
||||||
public onRowEditEnd: (event: { row: number }) => void;
|
public onRowEditEnd: (event: { row: number }) => void;
|
||||||
public onIsCellEditValid: (row: number, column: number, newValue: any) => boolean;
|
public onIsCellEditValid: (row: number, column: number, newValue: any) => boolean;
|
||||||
public onIsColumnEditable: (column: number) => boolean;
|
|
||||||
public overrideCellFn: (rowNumber, columnId, value?, data?) => string;
|
public overrideCellFn: (rowNumber, columnId, value?, data?) => string;
|
||||||
public loadDataFunction: (offset: number, count: number) => Promise<IGridDataRow[]>;
|
public loadDataFunction: (offset: number, count: number) => Promise<IGridDataRow[]>;
|
||||||
|
|
||||||
@@ -423,7 +415,9 @@ export abstract class GridParentComponent {
|
|||||||
let self = this;
|
let self = this;
|
||||||
return (gridIndex: number) => {
|
return (gridIndex: number) => {
|
||||||
self.activeGrid = gridIndex;
|
self.activeGrid = gridIndex;
|
||||||
self.slickgrids.toArray()[this.activeGrid].selection = true;
|
let grid = self.slickgrids.toArray()[self.activeGrid];
|
||||||
|
grid.setActive();
|
||||||
|
grid.selection = true;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -433,22 +427,6 @@ export abstract class GridParentComponent {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Used to convert the string to a enum compatible with SlickGrid
|
|
||||||
*/
|
|
||||||
protected stringToFieldType(input: string): FieldType {
|
|
||||||
let fieldtype: FieldType;
|
|
||||||
switch (input) {
|
|
||||||
case 'string':
|
|
||||||
fieldtype = FieldType.String;
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
fieldtype = FieldType.String;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
return fieldtype;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Makes a resultset take up the full result height if this is not already true
|
* Makes a resultset take up the full result height if this is not already true
|
||||||
* Otherwise rerenders the result sets from default
|
* Otherwise rerenders the result sets from default
|
||||||
|
|||||||
@@ -20,12 +20,11 @@
|
|||||||
[dataRows]="dataSet.dataRows"
|
[dataRows]="dataSet.dataRows"
|
||||||
(contextMenu)="openContextMenu($event, dataSet.batchId, dataSet.resultId, i)"
|
(contextMenu)="openContextMenu($event, dataSet.batchId, dataSet.resultId, i)"
|
||||||
enableAsyncPostRender="true"
|
enableAsyncPostRender="true"
|
||||||
showDataTypeIcon="false"
|
|
||||||
showHeader="true"
|
showHeader="true"
|
||||||
[resized]="dataSet.resized"
|
[resized]="dataSet.resized"
|
||||||
(mousedown)="navigateToGrid(i)"
|
(mousedown)="navigateToGrid(i)"
|
||||||
[selectionModel]="selectionModel"
|
[selectionModel]="selectionModel"
|
||||||
[plugins]="slickgridPlugins"
|
[plugins]="plugins[i]"
|
||||||
class="boxCol content vertBox slickgrid"
|
class="boxCol content vertBox slickgrid"
|
||||||
[rowHeight]="rowHeight">
|
[rowHeight]="rowHeight">
|
||||||
</slick-grid>
|
</slick-grid>
|
||||||
|
|||||||
@@ -28,6 +28,9 @@ import { TabChild } from 'sql/base/browser/ui/panel/tab.component';
|
|||||||
import { clone, mixin } from 'sql/base/common/objects';
|
import { clone, mixin } from 'sql/base/common/objects';
|
||||||
import { IQueryEditorService } from 'sql/parts/query/common/queryEditorService';
|
import { IQueryEditorService } from 'sql/parts/query/common/queryEditorService';
|
||||||
import { escape } from 'sql/base/common/strings';
|
import { escape } from 'sql/base/common/strings';
|
||||||
|
import { RowNumberColumn } from 'sql/base/browser/ui/table/plugins/rowNumberColumn.plugin';
|
||||||
|
import { AutoColumnSize } from 'sql/base/browser/ui/table/plugins/autoSizeColumns.plugin';
|
||||||
|
import { AdditionalKeyBindings } from 'sql/base/browser/ui/table/plugins/additionalKeyBindings.plugin';
|
||||||
|
|
||||||
import { format } from 'vs/base/common/strings';
|
import { format } from 'vs/base/common/strings';
|
||||||
import * as DOM from 'vs/base/browser/dom';
|
import * as DOM from 'vs/base/browser/dom';
|
||||||
@@ -61,7 +64,9 @@ export class QueryComponent extends GridParentComponent implements OnInit, OnDes
|
|||||||
|
|
||||||
// create a function alias to use inside query.component
|
// create a function alias to use inside query.component
|
||||||
// tslint:disable-next-line:no-unused-variable
|
// tslint:disable-next-line:no-unused-variable
|
||||||
private stringsFormat: any = format;
|
protected stringsFormat: any = format;
|
||||||
|
|
||||||
|
protected plugins = new Array<Array<Slick.Plugin<any>>>();
|
||||||
|
|
||||||
// tslint:disable-next-line:no-unused-variable
|
// tslint:disable-next-line:no-unused-variable
|
||||||
private dataIcons: IGridIcon[] = [
|
private dataIcons: IGridIcon[] = [
|
||||||
@@ -302,9 +307,9 @@ export class QueryComponent extends GridParentComponent implements OnInit, OnDes
|
|||||||
for (let row = 0; row < rows.rows.length; row++) {
|
for (let row = 0; row < rows.rows.length; row++) {
|
||||||
// Push row values onto end of gridData for slickgrid
|
// Push row values onto end of gridData for slickgrid
|
||||||
gridData.push({
|
gridData.push({
|
||||||
values: rows.rows[row].map(c => {
|
values: [{}].concat(rows.rows[row].map(c => {
|
||||||
return mixin({ ariaLabel: escape(c.displayValue) }, c);
|
return mixin({ ariaLabel: escape(c.displayValue) }, c);
|
||||||
})
|
}))
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -331,6 +336,8 @@ export class QueryComponent extends GridParentComponent implements OnInit, OnDes
|
|||||||
minHeight = minHeightNumber.toString() + 'px';
|
minHeight = minHeightNumber.toString() + 'px';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let rowNumberColumn = new RowNumberColumn({ numberOfRows: resultSet.rowCount });
|
||||||
|
|
||||||
// Store the result set from the event
|
// Store the result set from the event
|
||||||
let dataSet: IGridDataSet = {
|
let dataSet: IGridDataSet = {
|
||||||
resized: undefined,
|
resized: undefined,
|
||||||
@@ -345,7 +352,7 @@ export class QueryComponent extends GridParentComponent implements OnInit, OnDes
|
|||||||
loadDataFunction,
|
loadDataFunction,
|
||||||
index => { return { values: [] }; }
|
index => { return { values: [] }; }
|
||||||
),
|
),
|
||||||
columnDefinitions: resultSet.columnInfo.map((c, i) => {
|
columnDefinitions: [rowNumberColumn.getColumnDefinition()].concat(resultSet.columnInfo.map((c, i) => {
|
||||||
let isLinked = c.isXml || c.isJson;
|
let isLinked = c.isXml || c.isJson;
|
||||||
let linkType = c.isXml ? 'xml' : 'json';
|
let linkType = c.isXml ? 'xml' : 'json';
|
||||||
|
|
||||||
@@ -354,12 +361,13 @@ export class QueryComponent extends GridParentComponent implements OnInit, OnDes
|
|||||||
name: c.columnName === 'Microsoft SQL Server 2005 XML Showplan'
|
name: c.columnName === 'Microsoft SQL Server 2005 XML Showplan'
|
||||||
? 'XML Showplan'
|
? 'XML Showplan'
|
||||||
: escape(c.columnName),
|
: escape(c.columnName),
|
||||||
type: self.stringToFieldType('string'),
|
field: i.toString(),
|
||||||
formatter: isLinked ? Services.hyperLinkFormatter : Services.textFormatter,
|
formatter: isLinked ? Services.hyperLinkFormatter : Services.textFormatter,
|
||||||
asyncPostRender: isLinked ? self.linkHandler(linkType) : undefined
|
asyncPostRender: isLinked ? self.linkHandler(linkType) : undefined
|
||||||
};
|
};
|
||||||
})
|
}))
|
||||||
};
|
};
|
||||||
|
self.plugins.push([rowNumberColumn, new AutoColumnSize(), new AdditionalKeyBindings()]);
|
||||||
self.dataSets.push(dataSet);
|
self.dataSets.push(dataSet);
|
||||||
|
|
||||||
// check if the resultset is for a query plan
|
// check if the resultset is for a query plan
|
||||||
|
|||||||
2
src/typings/globals/slickgrid/index.d.ts
vendored
2
src/typings/globals/slickgrid/index.d.ts
vendored
@@ -1149,7 +1149,7 @@ declare namespace Slick {
|
|||||||
* @param row A row index.
|
* @param row A row index.
|
||||||
* @param cell A column index.
|
* @param cell A column index.
|
||||||
**/
|
**/
|
||||||
public setActiveCell(row: number, cell: number): void;
|
public setActiveCell(row: number, cell: number, opt_editMode?: boolean, preClickModeOn?: boolean, suppressActiveCellChangedEvent?: boolean): void;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sets CSS classes to specific grid cells by calling removeCellCssStyles(key) followed by addCellCssStyles(key, hash). key is name for this set of styles so you can reference it later - to modify it or remove it, for example. hash is a per-row-index, per-column-name nested hash of CSS classes to apply.
|
* Sets CSS classes to specific grid cells by calling removeCellCssStyles(key) followed by addCellCssStyles(key, hash). key is name for this set of styles so you can reference it later - to modify it or remove it, for example. hash is a per-row-index, per-column-name nested hash of CSS classes to apply.
|
||||||
|
|||||||
@@ -81,6 +81,11 @@ export interface IColumnDefinition {
|
|||||||
formatter?: (row: number, cell: any, value: any, columnDef: any, dataContext: any) => string;
|
formatter?: (row: number, cell: any, value: any, columnDef: any, dataContext: any) => string;
|
||||||
isEditable?: boolean;
|
isEditable?: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface ISlickColumn<T> extends Slick.Column<T> {
|
||||||
|
isEditable?: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
export interface IGridColumnDefinition {
|
export interface IGridColumnDefinition {
|
||||||
id: string;
|
id: string;
|
||||||
type: number;
|
type: number;
|
||||||
|
|||||||
12
yarn.lock
12
yarn.lock
@@ -172,9 +172,9 @@ angular2-grid@2.0.6:
|
|||||||
version "2.0.6"
|
version "2.0.6"
|
||||||
resolved "https://registry.yarnpkg.com/angular2-grid/-/angular2-grid-2.0.6.tgz#01fe225dc13b2822370b6c61f9a6913b3a26f989"
|
resolved "https://registry.yarnpkg.com/angular2-grid/-/angular2-grid-2.0.6.tgz#01fe225dc13b2822370b6c61f9a6913b3a26f989"
|
||||||
|
|
||||||
"angular2-slickgrid@git://github.com/Microsoft/angular2-slickgrid.git#1.3.11":
|
"angular2-slickgrid@github:Microsoft/angular2-slickgrid#1.3.12":
|
||||||
version "1.3.10"
|
version "1.3.12"
|
||||||
resolved "git://github.com/Microsoft/angular2-slickgrid.git#35f00750ef2f544b17744cc167c0ff7997c114b4"
|
resolved "https://codeload.github.com/Microsoft/angular2-slickgrid/tar.gz/19aafe8888d2f2eb70aec858e4b86e3c1b7b3fc8"
|
||||||
|
|
||||||
ansi-colors@^1.0.1:
|
ansi-colors@^1.0.1:
|
||||||
version "1.1.0"
|
version "1.1.0"
|
||||||
@@ -5889,9 +5889,9 @@ slice-ansi@0.0.4:
|
|||||||
version "0.0.4"
|
version "0.0.4"
|
||||||
resolved "https://registry.yarnpkg.com/slice-ansi/-/slice-ansi-0.0.4.tgz#edbf8903f66f7ce2f8eafd6ceed65e264c831b35"
|
resolved "https://registry.yarnpkg.com/slice-ansi/-/slice-ansi-0.0.4.tgz#edbf8903f66f7ce2f8eafd6ceed65e264c831b35"
|
||||||
|
|
||||||
"slickgrid@github:anthonydresser/SlickGrid#2.3.23":
|
"slickgrid@github:anthonydresser/SlickGrid#2.3.24":
|
||||||
version "2.3.23"
|
version "2.3.24"
|
||||||
resolved "https://codeload.github.com/anthonydresser/SlickGrid/tar.gz/a88c0c25fd6cbe01be86b3018f523987a198a6b6"
|
resolved "https://codeload.github.com/anthonydresser/SlickGrid/tar.gz/52a87398330a4751088e3e59c37ef50f17179e09"
|
||||||
dependencies:
|
dependencies:
|
||||||
jquery ">=1.8.0"
|
jquery ">=1.8.0"
|
||||||
jquery-ui ">=1.8.0"
|
jquery-ui ">=1.8.0"
|
||||||
|
|||||||
Reference in New Issue
Block a user