From 401fc8161a119ca721931c856f2ebdc13cf169a1 Mon Sep 17 00:00:00 2001 From: Anthony Dresser Date: Thu, 6 Sep 2018 14:43:52 -0700 Subject: [PATCH] fix dragging (#2438) --- .../ui/table/plugins/cellRangeSelector.ts | 130 ++++++++++++++++++ .../plugins/cellSelectionModel.plugin.ts | 11 +- src/typings/globals/slickgrid/index.d.ts | 5 + 3 files changed, 138 insertions(+), 8 deletions(-) create mode 100644 src/sql/base/browser/ui/table/plugins/cellRangeSelector.ts diff --git a/src/sql/base/browser/ui/table/plugins/cellRangeSelector.ts b/src/sql/base/browser/ui/table/plugins/cellRangeSelector.ts new file mode 100644 index 0000000000..8102d4c3fe --- /dev/null +++ b/src/sql/base/browser/ui/table/plugins/cellRangeSelector.ts @@ -0,0 +1,130 @@ +import { mixin } from 'vs/base/common/objects'; + +require.__$__nodeRequire('slickgrid/plugins/slick.cellrangedecorator'); + +const defaultOptions: ICellRangeSelectorOptions = { + selectionCss: { + 'border': '2px dashed blue' + } +}; + +export interface ICellRangeSelectorOptions { + selectionCss?: { [key: string]: string }; + cellDecorator?: ICellRangeDecorator; +} + +export interface ICellRangeSelector extends Slick.Plugin { + onCellRangeSelected: Slick.Event<{ range: Slick.Range }>; + onBeforeCellRangeSelected: Slick.Event; +} + +export interface ICellRangeDecorator { + show(range: Slick.Range); + hide(); +} + +export class CellRangeSelector implements ICellRangeSelector { + private grid: Slick.Grid; + private dragging: boolean; + private handler = new Slick.EventHandler(); + private decorator: ICellRangeDecorator; + private canvas: HTMLCanvasElement; + private currentlySelectedRange: { start: Slick.Cell, end: Slick.Cell }; + + public onBeforeCellRangeSelected = new Slick.Event(); + public onCellRangeSelected = new Slick.Event<{ range: Slick.Range }>(); + + constructor(private options: ICellRangeSelectorOptions) { + this.options = mixin(this.options, defaultOptions, false); + } + + public init(grid: Slick.Grid) { + this.decorator = this.options.cellDecorator || new (Slick).CellRangeDecorator(grid, this.options); + this.grid = grid; + this.canvas = this.grid.getCanvasNode(); + this.handler + .subscribe(this.grid.onDragInit, e => this.handleDragInit(e)) + .subscribe(this.grid.onDragStart, (e, dd) => this.handleDragStart(e, dd)) + .subscribe(this.grid.onDrag, (e, dd) => this.handleDrag(e, dd)) + .subscribe(this.grid.onDragEnd, (e, dd) => this.handleDragEnd(e, dd)); + } + + public destroy() { + this.handler.unsubscribeAll(); + } + + public getCellDecorator() { + return this.decorator; + } + + public getCurrentRange() { + return this.currentlySelectedRange; + } + + private handleDragInit(e: DOMEvent) { + // prevent the grid from cancelling drag'n'drop by default + e.stopImmediatePropagation(); + } + + private handleDragStart(e: MouseEvent, dd: Slick.OnDragStartEventArgs) { + let cell = this.grid.getCellFromEvent(e); + if (this.onBeforeCellRangeSelected.notify(cell) !== false) { + if (this.grid.canCellBeSelected(cell.row, cell.cell)) { + this.dragging = true; + e.stopImmediatePropagation(); + } + } + if (!this.dragging) { + return; + } + + this.grid.focus(); + + let start = this.grid.getCellFromPoint( + dd.startX - $(this.canvas).offset().left, + dd.startY - $(this.canvas).offset().top); + + dd.range = { start: start, end: undefined }; + this.currentlySelectedRange = dd.range; + return this.decorator.show(new Slick.Range(start.row, start.cell)); + } + + private handleDrag(e: MouseEvent, dd: Slick.OnDragEventArgs) { + if (!this.dragging) { + return; + } + + e.stopImmediatePropagation(); + + let end = this.grid.getCellFromPoint( + e.pageX - $(this.canvas).offset().left, + e.pageY - $(this.canvas).offset().top); + + if (!this.grid.canCellBeSelected(end.row, end.cell)) { + return; + } + + dd.range.end = end; + this.currentlySelectedRange = dd.range; + this.decorator.show(new Slick.Range(dd.range.start.row, dd.range.start.cell, end.row, end.cell)); + } + + private handleDragEnd(e: MouseEvent, dd: Slick.OnDragEndEventArgs) { + if (!this.dragging) { + return; + } + + this.dragging = false; + e.stopImmediatePropagation(); + + this.decorator.hide(); + this.onCellRangeSelected.notify({ + range: new Slick.Range( + dd.range.start.row, + dd.range.start.cell, + dd.range.end.row, + dd.range.end.cell + ) + }); + } +} diff --git a/src/sql/base/browser/ui/table/plugins/cellSelectionModel.plugin.ts b/src/sql/base/browser/ui/table/plugins/cellSelectionModel.plugin.ts index 3108af4bbf..fcc914fd21 100644 --- a/src/sql/base/browser/ui/table/plugins/cellSelectionModel.plugin.ts +++ b/src/sql/base/browser/ui/table/plugins/cellSelectionModel.plugin.ts @@ -3,15 +3,10 @@ import { mixin } from 'vs/base/common/objects'; import { isUndefinedOrNull } from 'vs/base/common/types'; -import { IThemeService } from 'vs/platform/theme/common/themeService'; + +import { CellRangeSelector, ICellRangeSelector } from 'sql/base/browser/ui/table/plugins/cellRangeSelector'; require.__$__nodeRequire('slickgrid/plugins/slick.cellrangedecorator'); -require.__$__nodeRequire('slickgrid/plugins/slick.cellrangeselector'); - -export interface ICellRangeSelector extends Slick.Plugin { - onCellRangeSelected: Slick.Event<{ range: Slick.Range }>; - onBeforeCellRangeSelected: Slick.Event; -} export interface ICellSelectionModelOptions { cellRangeSelector?: any; @@ -36,7 +31,7 @@ export class CellSelectionModel implements Slick.SelectionModelSlick).CellRangeSelector({ selectionCss: { 'border': '2px dashed grey' } }); + this.selector = new CellRangeSelector({ selectionCss: { 'border': '2px dashed grey' } }); } } diff --git a/src/typings/globals/slickgrid/index.d.ts b/src/typings/globals/slickgrid/index.d.ts index 5a9f073a71..57db849b3c 100644 --- a/src/typings/globals/slickgrid/index.d.ts +++ b/src/typings/globals/slickgrid/index.d.ts @@ -1252,16 +1252,21 @@ declare namespace Slick { export interface OnDragEndEventArgs extends GridEventArgs { // todo: need to understand $canvas drag event parameter's 'dd' object // the documentation is not enlightening + range: { start: Slick.Cell, end: Slick.Cell }; } export interface OnDragEventArgs extends GridEventArgs { // todo: need to understand $canvas drag event parameter's 'dd' object // the documentation is not enlightening + range: { start: Slick.Cell, end: Slick.Cell }; } export interface OnDragStartEventArgs extends GridEventArgs { // todo: need to understand $canvas drag event parameter's 'dd' object // the documentation is not enlightening + startX: number; + startY: number; + range: { start: Slick.Cell, end: Slick.Cell }; } export interface OnDragInitEventArgs extends GridEventArgs {