// Adopted and converted to typescript from https://github.com/mleibman/SlickGrid/blob/gh-pages/plugins/slick.rowmovemanager.js // heavily modified import { RowSelectionModel } from 'sql/base/browser/ui/table/plugins/rowSelectionModel.plugin'; import { BaseClickableColumn, ClickableColumnOptions, IconColumnOptions } from 'sql/base/browser/ui/table/plugins/tableColumn'; import { mixin } from 'vs/base/common/objects'; const defaultOptions: IRowMoveManagerOptions = { cancelEditOnDrag: false }; export interface IRowMoveManagerOptions extends IconColumnOptions, ClickableColumnOptions, Slick.Column { cancelEditOnDrag?: boolean; } export interface RowMoveOnDragEventArgs { selectionProxy?: JQuery; guide?: JQuery; selectedRows?: number[]; insertBefore?: number; canMove?: boolean; } export interface RowMoveOnDragEventData { rows?: number[]; insertBefore: number; } // Wrapper interfaces for drag arguments to support selection export interface OnRowMoveDragInitEventArgs extends Slick.OnDragInitEventArgs, RowMoveOnDragEventArgs { } export interface OnRowMoveDragStartEventArgs extends Slick.OnDragStartEventArgs, RowMoveOnDragEventArgs { } export interface OnRowMoveDragEventArgs extends Slick.OnDragEventArgs, RowMoveOnDragEventArgs { } export interface OnRowMoveDragEndEventArgs extends Slick.OnDragEndEventArgs, RowMoveOnDragEventArgs { } export class RowMoveManager extends BaseClickableColumn { private _canvas: HTMLCanvasElement; private _dragging: boolean; public onBeforeMoveRows: Slick.Event = new Slick.Event(); public onMoveRows: Slick.Event = new Slick.Event(); constructor(private options: IRowMoveManagerOptions) { super(options); this.options = mixin(options, defaultOptions, false); } public get definition(): Slick.Column { return { id: this.options.id || this.options.title || this.options.field, width: this.options.width ?? 26, name: this.options.name, resizable: this.options.resizable, selectable: false, behavior: this.options.behavior, cssClass: this.options.iconCssClass, toolTip: this.options.title }; } public override init(grid: Slick.Grid) { this._grid = grid; this._grid.setSelectionModel(new RowSelectionModel()); this._canvas = this._grid.getCanvasNode(); this._handler .subscribe(this._grid.onDragInit, (e: DOMEvent, data: OnRowMoveDragInitEventArgs) => this.onDragInit(e as MouseEvent, data)) .subscribe(this._grid.onDragStart, (e: DOMEvent, data: OnRowMoveDragStartEventArgs) => this.onDragStart(e as MouseEvent, data)) .subscribe(this._grid.onDrag, (e: DOMEvent, data: OnRowMoveDragEventArgs) => this.onDrag(e as MouseEvent, data)) .subscribe(this._grid.onDragEnd, (e: DOMEvent, data: OnRowMoveDragEndEventArgs) => this.onDragEnd(e as MouseEvent, data)); } private onDragInit(e: MouseEvent, data: OnRowMoveDragInitEventArgs) { e.stopImmediatePropagation(); } private onDragStart(e: MouseEvent, data: OnRowMoveDragStartEventArgs) { const cell = this._grid.getCellFromEvent(e); const highlightStyle = {}; const columns = this._grid.getColumns(); highlightStyle[cell.row] = {}; columns.forEach((c) => { highlightStyle[cell.row][c.id] = 'isDragging'; }); this._grid.setCellCssStyles('isDragging', highlightStyle); if (this.options.cancelEditOnDrag && this._grid.getEditorLock().isActive()) { this._grid.getEditorLock().cancelCurrentEdit(); } if (this._grid.getEditorLock().isActive() || !/move|selectAndMove/.test(this._grid.getColumns()[cell.cell].behavior)) { return; } this._dragging = true; e.stopImmediatePropagation(); let selectedRows = this._grid.getSelectedRows(); if (selectedRows.length === 0 || jQuery.inArray(cell.row, selectedRows) === -1) { selectedRows = [cell.row]; this._grid.setSelectedRows(selectedRows); } const rowHeight = this._grid.getOptions().rowHeight; data.selectedRows = selectedRows; data.selectionProxy = jQuery('
') .css('position', 'absolute') .css('zIndex', '99999') .css('width', jQuery(this._canvas).innerWidth()) .css('height', rowHeight * selectedRows.length) .appendTo(this._canvas); data.guide = jQuery('
') .css('position', 'absolute') .css('zIndex', '99998') .css('width', jQuery(this._canvas).innerWidth()) .css('top', -1000) .appendTo(this._canvas); data.insertBefore = -1; } private onDrag(e: MouseEvent, data: OnRowMoveDragEventArgs) { if (!this._dragging) { return; } e.stopImmediatePropagation(); const top = e.pageY - jQuery(this._canvas).offset().top; data.selectionProxy.css('top', top - 5); const insertBefore = Math.max(0, Math.min(Math.round(top / this._grid.getOptions().rowHeight), this._grid.getDataLength())); if (insertBefore !== data.insertBefore) { const eventData: RowMoveOnDragEventData = { 'rows': data.selectedRows, 'insertBefore': insertBefore }; if (this.onBeforeMoveRows.notify(eventData) === false) { data.guide.css('top', -1000); data.canMove = false; } else { data.guide.css('top', insertBefore * this._grid.getOptions().rowHeight); data.canMove = true; } data.insertBefore = insertBefore; } } private onDragEnd(e: MouseEvent, data: OnRowMoveDragEndEventArgs) { if (!this._dragging) { return; } this._dragging = false; this._grid.removeCellCssStyles('isDragging'); e.stopImmediatePropagation(); data.guide.remove(); data.selectionProxy.remove(); if (data.canMove) { const eventData: RowMoveOnDragEventData = { 'rows': data.selectedRows, 'insertBefore': data.insertBefore }; this.onMoveRows.notify(eventData); } } }