diff --git a/src/global.d.ts b/src/global.d.ts index d0a61411..3669eacf 100644 --- a/src/global.d.ts +++ b/src/global.d.ts @@ -35,9 +35,11 @@ import type { SlickCellExternalCopyManager } from './plugins/slick.cellexternalc import type { SlickCellRangeDecorator } from './plugins/slick.cellrangedecorator'; import type { SlickCellRangeSelector } from './plugins/slick.cellrangeselector'; import type { SlickCellSelectionModel } from './plugins/slick.cellselectionmodel'; +import type { SlickCrossGridRowMoveManager } from './plugins/slick.crossgridrowmovemanager'; import type { SlickDraggableGrouping } from './plugins/slick.draggablegrouping'; import type { SlickRowSelectionModel } from './plugins/slick.rowselectionmodel'; import type { SlickResizer } from './plugins/slick.resizer'; +import type { SlickRowMoveManager } from './plugins/slick.rowmovemanager'; import type { SlickState } from './plugins/slick.state'; import type { SlickGroupItemMetadataProvider } from './slick.groupitemmetadataprovider'; import type { Draggable, MouseWheel, Resizable } from './slick.interactions'; @@ -66,6 +68,7 @@ declare global { GridMenu: typeof SlickGridMenu, Pager: typeof SlickGridPager }, + CrossGridRowMoveManager: SlickCrossGridRowMoveManager, Data: { Aggregators: typeof Aggregators, DataView: typeof SlickDataView, @@ -94,6 +97,7 @@ declare global { preClickClassName: typeof preClickClassName, Range: typeof SlickRange, Resizable: typeof Resizable, + RowMoveManager: typeof SlickRowMoveManager, RowSelectionMode: typeof RowSelectionMode, RowSelectionModel: typeof SlickRowSelectionModel, State: typeof SlickState, diff --git a/src/models/index.ts b/src/models/index.ts index bd83dc7d..58c9fa1a 100644 --- a/src/models/index.ts +++ b/src/models/index.ts @@ -60,6 +60,7 @@ export * from './pagingInfo.interface'; export * from './plugin.interface'; export * from './positionMethod.type'; export * from './resizerOption.interface'; +export * from './rowMoveManagerOption.interface'; export * from './rowSelectionModelOption.interface'; export * from './selectableOverrideCallback.interface'; export * from './singleColumnSort.interface'; diff --git a/src/models/rowMoveManagerOption.interface.ts b/src/models/rowMoveManagerOption.interface.ts new file mode 100644 index 00000000..76c3fd1d --- /dev/null +++ b/src/models/rowMoveManagerOption.interface.ts @@ -0,0 +1,67 @@ +import type { SlickCellRangeSelector } from '../plugins/slick.cellrangeselector'; +import type { UsabilityOverrideFn } from './usabilityOverrideFn.type'; +import type { SlickGrid } from '../slick.grid'; + +export interface RowMoveManagerOption { + /** + * Defaults to True, do we want to disable auto-scroll feature (which comes from CellRangeSelector). + * NOTE: this flag has no effect when a `cellRangeSelector` is provided, you could however turn `autoScroll: false` inside the `cellRangeSelector` + */ + autoScrollWhenDrag?: boolean; + + /** Defaults to false, option to cancel editing while dragging a row */ + cancelEditOnDrag?: boolean; + + /** + * Optional Cell Range Selector. + * NOTE: for an even simpler approach, we could use `enableCellRangeSelector` which the lib will take care of creating the instance by itself. + */ + cellRangeSelector?: SlickCellRangeSelector; + + /** A CSS class to be added to the menu item container. */ + cssClass?: string; + + /** Column definition id(defaults to "_move") */ + columnId?: string; + + /** + * Defaults to 0, the column index position in the grid by default it will show as the first column (index 0). + * Also note that the index position might vary if you use other extensions, after each extension is created, + * it will add an offset to take into consideration (1.CheckboxSelector, 2.RowDetail, 3.RowMove) + */ + columnIndexPosition?: number; + + /** Defaults to False, do we want to disable the row selection? */ + disableRowSelection?: boolean; + + /** Defaults to False, should we select when dragging? */ + dragToSelect?: boolean; + + /** Defaults to True, do we want to hide the row move shadow of what we're dragging? */ + hideRowMoveShadow?: boolean; + + /** Defaults to 0, optional left margin of the row move shadown element when enabled */ + rowMoveShadowMarginLeft?: number | string; + + /** Defaults to 0, optional top margin of the row move shadown element when enabled */ + rowMoveShadowMarginTop?: number | string; + + /** Defaults to 0.9, opacity of row move shadow element (requires shadow to be shown via option: `hideRowMoveShadow: false`) */ + rowMoveShadowOpacity?: number | string; + + /** Defaults to 0.75, scale size of row move shadow element (requires shadow to be shown via option: `hideRowMoveShadow: false`) */ + rowMoveShadowScale?: number | string; + + /** Defaults to False, do we want a single row move? Setting this to false means that 1 or more rows can be selected to move together. */ + singleRowMove?: boolean; + + /** Width of the column in pixels (must be a number) */ + width?: number; + + /** Override the logic for showing (or not) the move icon (use case example: only every 2nd row is moveable) */ + usabilityOverride?: UsabilityOverrideFn; +} + +export interface CrossGridRowMoveManagerOption extends RowMoveManagerOption { + toGrid: SlickGrid; +} \ No newline at end of file diff --git a/src/plugins/slick.crossgridrowmovemanager.js b/src/plugins/slick.crossgridrowmovemanager.js deleted file mode 100644 index 9ef3d791..00000000 --- a/src/plugins/slick.crossgridrowmovemanager.js +++ /dev/null @@ -1,295 +0,0 @@ -import { Event as SlickEvent_, EventHandler as EventHandler_, Utils as Utils_ } from '../slick.core'; - -// for (iife) load Slick methods from global Slick object, or use imports for (esm) -const SlickEvent = IIFE_ONLY ? Slick.Event : SlickEvent_; -const EventHandler = IIFE_ONLY ? Slick.EventHandler : EventHandler_; -const Utils = IIFE_ONLY ? Slick.Utils : Utils_; - -/** - * Row Move Manager options: - * cssClass: A CSS class to be added to the menu item container. - * columnId: Column definition id (defaults to "_move") - * cancelEditOnDrag: Do we want to cancel any Editing while dragging a row (defaults to false) - * disableRowSelection: Do we want to disable the row selection? (defaults to false) - * hideRowMoveShadow: Do we want to hide the row move shadow clone? (defaults to true) - * rowMoveShadowMarginTop: When row move shadow is shown, optional margin-top (defaults to 0) - * rowMoveShadowMarginLeft: When row move shadow is shown, optional margin-left (defaults to 0) - * rowMoveShadowOpacity: When row move shadow is shown, what is its opacity? (defaults to 0.95) - * rowMoveShadowScale: When row move shadow is shown, what is its size scale? (default to 0.75) - * singleRowMove: Do we want a single row move? Setting this to false means that it's a multple row move (defaults to false) - * width: Width of the column - * usabilityOverride: Callback method that user can override the default behavior of the row being moveable or not - * - */ - -export function CrossGridRowMoveManager(options) { - var _grid; - var _canvas; - var _toGrid; - var _toCanvas; - var _dragging; - var _self = this; - var _usabilityOverride = null; - var _handler = new EventHandler(); - var _defaults = { - columnId: "_move", - cssClass: null, - cancelEditOnDrag: false, - disableRowSelection: false, - hideRowMoveShadow: true, - rowMoveShadowMarginTop: 0, - rowMoveShadowMarginLeft: 0, - rowMoveShadowOpacity: 0.95, - rowMoveShadowScale: 0.75, - singleRowMove: false, - width: 40, - }; - - // user could override the expandable icon logic from within the options or after instantiating the plugin - if (options && typeof options.usabilityOverride === 'function') { - usabilityOverride(options.usabilityOverride); - } - - function init(grid) { - options = Utils.extend(true, {}, _defaults, options); - _grid = grid; - _canvas = _grid.getCanvasNode(); - - _toGrid = options.toGrid; - _toCanvas = _toGrid.getCanvasNode(); - _handler - .subscribe(_grid.onDragInit, handleDragInit) - .subscribe(_grid.onDragStart, handleDragStart) - .subscribe(_grid.onDrag, handleDrag) - .subscribe(_grid.onDragEnd, handleDragEnd); - } - - function destroy() { - _handler.unsubscribeAll(); - } - - function setOptions(newOptions) { - options = Utils.extend({}, options, newOptions); - } - - function handleDragInit(e) { - // prevent the grid from cancelling drag'n'drop by default - e.stopImmediatePropagation(); - } - - function handleDragStart(e, dd) { - var cell = _grid.getCellFromEvent(e); - var currentRow = cell && cell.row; - var dataContext = _grid.getDataItem(currentRow); - - if (!checkUsabilityOverride(currentRow, dataContext, _grid)) { - return; - } - - if (options.cancelEditOnDrag && _grid.getEditorLock().isActive()) { - _grid.getEditorLock().cancelCurrentEdit(); - } - - if (_grid.getEditorLock().isActive() || !isHandlerColumn(cell.cell)) { - return false; - } - - _dragging = true; - e.stopImmediatePropagation(); - - // optionally create a shadow element of the row so that we can see all the time which row exactly we're dragging - if (!options.hideRowMoveShadow) { - const cellNodeElm = _grid.getCellNode(cell.row, cell.cell); - const slickRowElm = cellNodeElm && cellNodeElm.closest('.slick-row'); - if (slickRowElm) { - dd.clonedSlickRow = slickRowElm.cloneNode(true); - dd.clonedSlickRow.classList.add('slick-reorder-shadow-row'); - dd.clonedSlickRow.style.display = 'none'; - dd.clonedSlickRow.style.marginLeft = Number(options.rowMoveShadowMarginLeft || 0) + 'px'; - dd.clonedSlickRow.style.marginTop = Number(options.rowMoveShadowMarginTop || 0) + 'px'; - dd.clonedSlickRow.style.opacity = `${options.rowMoveShadowOpacity || 0.95}`; - dd.clonedSlickRow.style.transform = `scale(${options.rowMoveShadowScale || 0.75})`; - _canvas.appendChild(dd.clonedSlickRow); - } - } - - var selectedRows = options.singleRowMove ? [cell.row] : _grid.getSelectedRows(); - - if (selectedRows.length === 0 || !selectedRows.some(selectedRow => selectedRow === cell.row)) { - selectedRows = [cell.row]; - if (!options.disableRowSelection) { - _grid.setSelectedRows(selectedRows); - } - } - - selectedRows.sort(function(a,b) { return a-b; }); - - var rowHeight = _grid.getOptions().rowHeight; - - dd.fromGrid = _grid; - dd.toGrid = _toGrid; - dd.selectedRows = selectedRows; - - dd.selectionProxy = document.createElement('div'); - dd.selectionProxy.className = 'slick-reorder-proxy'; - dd.selectionProxy.style.display = 'none'; - dd.selectionProxy.style.position = 'absolute'; - dd.selectionProxy.style.zIndex = '99999'; - dd.selectionProxy.style.width = `${_toCanvas.clientWidth}px`; - dd.selectionProxy.style.height = `${rowHeight * selectedRows.length}px`; - _toCanvas.appendChild(dd.selectionProxy); - - dd.guide = document.createElement('div'); - dd.guide.className = 'slick-reorder-guide'; - dd.guide.style.position = 'absolute'; - dd.guide.style.zIndex = '99999'; - dd.guide.style.width = `${_toCanvas.clientWidth}px`; - dd.guide.style.top = `-1000px`; - _toCanvas.appendChild(dd.guide); - - dd.insertBefore = -1; - } - - function handleDrag(evt, dd) { - if (!_dragging) { - return; - } - - evt.stopImmediatePropagation(); - const e = evt.getNativeEvent(); - - var targetEvent = e.touches ? e.touches[0] : e; - const top = targetEvent.pageY - (Utils.offset(_toCanvas).top || 0); - dd.selectionProxy.style.top = `${top - 5}px`; - dd.selectionProxy.style.display = 'block'; - - // if the row move shadow is enabled, we'll also make it follow the mouse cursor - if (dd.clonedSlickRow) { - dd.clonedSlickRow.style.top = `${top - 6}px`; - dd.clonedSlickRow.style.display = 'block'; - } - - var insertBefore = Math.max(0, Math.min(Math.round(top / _toGrid.getOptions().rowHeight), _toGrid.getDataLength())); - if (insertBefore !== dd.insertBefore) { - var eventData = { - "fromGrid": _grid, - "toGrid": _toGrid, - "rows": dd.selectedRows, - "insertBefore": insertBefore - }; - - if (_self.onBeforeMoveRows.notify(eventData).getReturnValue() === false) { - dd.canMove = false; - } else { - dd.canMove = true; - } - - // if there's a UsabilityOverride defined, we also need to verify that the condition is valid - if (_usabilityOverride && dd.canMove) { - var insertBeforeDataContext = _toGrid.getDataItem(insertBefore); - dd.canMove = checkUsabilityOverride(insertBefore, insertBeforeDataContext, _toGrid); - } - - // if the new target is possible we'll display the dark blue bar (representin the acceptability) at the target position - // else it won't show up (it will be off the screen) - if (!dd.canMove) { - dd.guide.style.top = '-1000px'; - } else { - dd.guide.style.top = `${insertBefore * (_toGrid.getOptions().rowHeight || 0)}px`; - } - - dd.insertBefore = insertBefore; - } - } - - function handleDragEnd(e, dd) { - if (!_dragging) { - return; - } - _dragging = false; - e.stopImmediatePropagation(); - - dd.guide.remove(); - dd.selectionProxy.remove(); - if (dd.clonedSlickRow) { - dd.clonedSlickRow.remove(); - dd.clonedSlickRow = null; - } - - if (dd.canMove) { - var eventData = { - "fromGrid": _grid, - "toGrid": _toGrid, - "rows": dd.selectedRows, - "insertBefore": dd.insertBefore - }; - // TODO: _grid.remapCellCssClasses ? - _self.onMoveRows.notify(eventData); - } - } - - function getColumnDefinition() { - return { - id: options.columnId || "_move", - name: "", - field: "move", - width: options.width || 40, - behavior: "selectAndMove", - selectable: false, - resizable: false, - cssClass: options.cssClass, - formatter: moveIconFormatter - }; - } - - function moveIconFormatter(row, cell, value, columnDef, dataContext, grid) { - if (!checkUsabilityOverride(row, dataContext, grid)) { - return null; - } else { - return { addClasses: "cell-reorder dnd", text: "" }; - } - } - - function checkUsabilityOverride(row, dataContext, grid) { - if (typeof _usabilityOverride === 'function') { - return _usabilityOverride(row, dataContext, grid); - } - return true; - } - - /** - * Method that user can pass to override the default behavior or making every row moveable. - * In order word, user can choose which rows to be an available as moveable (or not) by providing his own logic show/hide icon and usability. - * @param overrideFn: override function callback - */ - function usabilityOverride(overrideFn) { - _usabilityOverride = overrideFn; - } - - function isHandlerColumn(columnIndex) { - return /move|selectAndMove/.test(_grid.getColumns()[columnIndex].behavior); - } - - Utils.extend(this, { - "onBeforeMoveRows": new SlickEvent(), - "onMoveRows": new SlickEvent(), - - "init": init, - "destroy": destroy, - "getColumnDefinition": getColumnDefinition, - "setOptions": setOptions, - "usabilityOverride": usabilityOverride, - "isHandlerColumn": isHandlerColumn, - "pluginName": "CrossGridRowMoveManager" - }); - } - -// extend Slick namespace on window object when building as iife -if (IIFE_ONLY && window.Slick) { - Utils.extend(true, window, { - Slick: { - CrossGridRowMoveManager - } - }); -} - diff --git a/src/plugins/slick.crossgridrowmovemanager.ts b/src/plugins/slick.crossgridrowmovemanager.ts new file mode 100644 index 00000000..d63d6e36 --- /dev/null +++ b/src/plugins/slick.crossgridrowmovemanager.ts @@ -0,0 +1,296 @@ +import { SlickEvent as SlickEvent_, SlickEventData as SlickEventData_, SlickEventHandler as SlickEventHandler_, Utils as Utils_ } from '../slick.core'; +import type { Column, DOMEvent, DragRowMove, FormatterResultObject, CrossGridRowMoveManagerOption, UsabilityOverrideFn } from '../models/index'; +import type { SlickGrid } from '../slick.grid'; + +// for (iife) load Slick methods from global Slick object, or use imports for (esm) +const SlickEvent = IIFE_ONLY ? Slick.Event : SlickEvent_; +const SlickEventHandler = IIFE_ONLY ? Slick.EventHandler : SlickEventHandler_; +const Utils = IIFE_ONLY ? Slick.Utils : Utils_; + +/** + * Row Move Manager options: + * cssClass: A CSS class to be added to the menu item container. + * columnId: Column definition id (defaults to "_move") + * cancelEditOnDrag: Do we want to cancel any Editing while dragging a row (defaults to false) + * disableRowSelection: Do we want to disable the row selection? (defaults to false) + * hideRowMoveShadow: Do we want to hide the row move shadow clone? (defaults to true) + * rowMoveShadowMarginTop: When row move shadow is shown, optional margin-top (defaults to 0) + * rowMoveShadowMarginLeft: When row move shadow is shown, optional margin-left (defaults to 0) + * rowMoveShadowOpacity: When row move shadow is shown, what is its opacity? (defaults to 0.95) + * rowMoveShadowScale: When row move shadow is shown, what is its size scale? (default to 0.75) + * singleRowMove: Do we want a single row move? Setting this to false means that it's a multple row move (defaults to false) + * width: Width of the column + * usabilityOverride: Callback method that user can override the default behavior of the row being moveable or not + * + */ +export class SlickCrossGridRowMoveManager { + // -- + // public API + pluginName = 'CrossGridRowMoveManager' as const; + onBeforeMoveRows = new SlickEvent<{ rows: number[]; insertBefore: number; fromGrid: SlickGrid; toGrid: SlickGrid; }>(); + onMoveRows = new SlickEvent<{ rows: number[]; insertBefore: number; fromGrid: SlickGrid; toGrid: SlickGrid; }>(); + + // -- + // protected props + protected _grid!: SlickGrid; + protected _canvas!: HTMLElement; + protected _dragging = false; + protected _toGrid!: SlickGrid; + protected _toCanvas!: HTMLElement; + protected _usabilityOverride?: UsabilityOverrideFn; + protected _eventHandler: SlickEventHandler_; + protected _options: CrossGridRowMoveManagerOption; + protected _defaults: CrossGridRowMoveManagerOption = { + columnId: '_move', + cssClass: undefined, + cancelEditOnDrag: false, + disableRowSelection: false, + hideRowMoveShadow: true, + rowMoveShadowMarginTop: 0, + rowMoveShadowMarginLeft: 0, + rowMoveShadowOpacity: 0.95, + rowMoveShadowScale: 0.75, + singleRowMove: false, + toGrid: undefined as any, + width: 40, + }; + + constructor(options: Partial) { + this._options = Utils.extend(true, {}, this._defaults, options); + this._eventHandler = new SlickEventHandler(); + } + + init(grid: SlickGrid) { + this._grid = grid; + this._canvas = this._grid.getCanvasNode(); + this._toGrid = this._options.toGrid; + this._toCanvas = this._toGrid.getCanvasNode(); + + // user could override the expandable icon logic from within the options or after instantiating the plugin + if (typeof this._options?.usabilityOverride === 'function') { + this.usabilityOverride(this._options.usabilityOverride); + } + + this._eventHandler + .subscribe(this._grid.onDragInit, this.handleDragInit.bind(this)) + .subscribe(this._grid.onDragStart, this.handleDragStart.bind(this)) + .subscribe(this._grid.onDrag, this.handleDrag.bind(this)) + .subscribe(this._grid.onDragEnd, this.handleDragEnd.bind(this)); + } + + destroy() { + this._eventHandler.unsubscribeAll(); + } + + setOptions(newOptions: CrossGridRowMoveManagerOption) { + this._options = Utils.extend({}, this._options, newOptions); + } + + protected handleDragInit(e: SlickEventData_) { + // prevent the grid from cancelling drag'n'drop by default + e.stopImmediatePropagation(); + } + + protected handleDragStart(e: DOMEvent, dd: DragRowMove & { fromGrid: SlickGrid; toGrid: SlickGrid; }): boolean | void { + const cell = this._grid.getCellFromEvent(e) || { cell: -1, row: -1 }; + const currentRow = cell?.row ?? 0; + const dataContext = this._grid.getDataItem(currentRow); + + if (!this.checkUsabilityOverride(currentRow, dataContext, this._grid)) { + return; + } + + if (this._options.cancelEditOnDrag && this._grid.getEditorLock().isActive()) { + this._grid.getEditorLock().cancelCurrentEdit(); + } + + if (this._grid.getEditorLock().isActive() || !this.isHandlerColumn(cell.cell)) { + return false; + } + + this._dragging = true; + e.stopImmediatePropagation(); + + // optionally create a shadow element of the row so that we can see all the time which row exactly we're dragging + if (!this._options.hideRowMoveShadow) { + const cellNodeElm = this._grid.getCellNode(cell.row, cell.cell); + const slickRowElm = cellNodeElm?.closest('.slick-row'); + if (slickRowElm) { + dd.clonedSlickRow = slickRowElm.cloneNode(true) as HTMLDivElement; + dd.clonedSlickRow.classList.add('slick-reorder-shadow-row'); + dd.clonedSlickRow.style.display = 'none'; + dd.clonedSlickRow.style.marginLeft = Number(this._options.rowMoveShadowMarginLeft || 0) + 'px'; + dd.clonedSlickRow.style.marginTop = Number(this._options.rowMoveShadowMarginTop || 0) + 'px'; + dd.clonedSlickRow.style.opacity = `${this._options.rowMoveShadowOpacity || 0.95}`; + dd.clonedSlickRow.style.transform = `scale(${this._options.rowMoveShadowScale || 0.75})`; + this._canvas.appendChild(dd.clonedSlickRow); + } + } + + let selectedRows = this._options.singleRowMove ? [cell.row] : this._grid.getSelectedRows(); + if (selectedRows.length === 0 || !selectedRows.some(selectedRow => selectedRow === cell.row)) { + selectedRows = [cell.row]; + if (!this._options.disableRowSelection) { + this._grid.setSelectedRows(selectedRows); + } + } + + selectedRows.sort((a, b) => a - b); + + const rowHeight = this._grid.getOptions().rowHeight; + + dd.fromGrid = this._grid; + dd.toGrid = this._toGrid; + dd.selectedRows = selectedRows; + + dd.selectionProxy = document.createElement('div'); + dd.selectionProxy.className = 'slick-reorder-proxy'; + dd.selectionProxy.style.display = 'none'; + dd.selectionProxy.style.position = 'absolute'; + dd.selectionProxy.style.zIndex = '99999'; + dd.selectionProxy.style.width = `${this._toCanvas.clientWidth}px`; + dd.selectionProxy.style.height = `${rowHeight * selectedRows.length}px`; + this._toCanvas.appendChild(dd.selectionProxy); + + dd.guide = document.createElement('div'); + dd.guide.className = 'slick-reorder-guide'; + dd.guide.style.position = 'absolute'; + dd.guide.style.zIndex = '99999'; + dd.guide.style.width = `${this._toCanvas.clientWidth}px`; + dd.guide.style.top = `-1000px`; + this._toCanvas.appendChild(dd.guide); + + dd.insertBefore = -1; + } + + protected handleDrag(evt: SlickEventData_, dd: DragRowMove): boolean | void { + if (!this._dragging) { + return; + } + + evt.stopImmediatePropagation(); + const e = evt.getNativeEvent(); + + const targetEvent = e.touches ? e.touches[0] : e; + const top = targetEvent.pageY - (Utils.offset(this._toCanvas)?.top ?? 0); + dd.selectionProxy.style.top = `${top - 5}px`; + dd.selectionProxy.style.display = 'block'; + + // if the row move shadow is enabled, we'll also make it follow the mouse cursor + if (dd.clonedSlickRow) { + dd.clonedSlickRow.style.top = `${top - 6}px`; + dd.clonedSlickRow.style.display = 'block'; + } + + const insertBefore = Math.max(0, Math.min(Math.round(top / this._toGrid.getOptions().rowHeight), this._toGrid.getDataLength())); + if (insertBefore !== dd.insertBefore) { + const eventData = { + fromGrid: this._grid, + toGrid: this._toGrid, + rows: dd.selectedRows, + insertBefore: insertBefore + }; + + if (this.onBeforeMoveRows.notify(eventData).getReturnValue() === false) { + dd.canMove = false; + } else { + dd.canMove = true; + } + + // if there's a UsabilityOverride defined, we also need to verify that the condition is valid + if (this._usabilityOverride && dd.canMove) { + const insertBeforeDataContext = this._toGrid.getDataItem(insertBefore); + dd.canMove = this.checkUsabilityOverride(insertBefore, insertBeforeDataContext, this._toGrid); + } + + // if the new target is possible we'll display the dark blue bar (representin the acceptability) at the target position + // else it won't show up (it will be off the screen) + if (!dd.canMove) { + dd.guide.style.top = '-1000px'; + } else { + dd.guide.style.top = `${insertBefore * (this._toGrid.getOptions().rowHeight || 0)}px`; + } + + dd.insertBefore = insertBefore; + } + } + + protected handleDragEnd(e: SlickEventData_, dd: DragRowMove) { + if (!this._dragging) { + return; + } + this._dragging = false; + e.stopImmediatePropagation(); + + dd.guide?.remove(); + dd.selectionProxy?.remove(); + dd.clonedSlickRow?.remove(); + + if (dd.canMove) { + const eventData = { + fromGrid: this._grid, + toGrid: this._toGrid, + rows: dd.selectedRows, + insertBefore: dd.insertBefore + }; + // TODO: this._grid.remapCellCssClasses ? + this.onMoveRows.notify(eventData); + } + } + + getColumnDefinition(): Column { + const columnId = String(this._options?.columnId ?? this._defaults.columnId); + + return { + id: columnId, + name: '', + field: 'move', + behavior: 'selectAndMove', + excludeFromColumnPicker: true, + excludeFromGridMenu: true, + excludeFromHeaderMenu: true, + selectable: false, + resizable: false, + width: this._options.width || 40, + formatter: this.moveIconFormatter.bind(this) + }; + } + + protected moveIconFormatter(row: number, _cell: number, _val: any, _column: Column, dataContext: any, grid: SlickGrid): FormatterResultObject | string { + if (!this.checkUsabilityOverride(row, dataContext, grid)) { + return ''; + } else { + return { addClasses: `cell-reorder dnd ${this._options.cssClass || ''}`, text: '' }; + } + } + + protected checkUsabilityOverride(row: number, dataContext: any, grid: SlickGrid) { + if (typeof this._usabilityOverride === 'function') { + return this._usabilityOverride(row, dataContext, grid); + } + return true; + } + + /** + * Method that user can pass to override the default behavior or making every row moveable. + * In order word, user can choose which rows to be an available as moveable (or not) by providing his own logic show/hide icon and usability. + * @param overrideFn: override function callback + */ + usabilityOverride(overrideFn: UsabilityOverrideFn) { + this._usabilityOverride = overrideFn; + } + + isHandlerColumn(columnIndex: number | string) { + return /move|selectAndMove/.test(this._grid.getColumns()[columnIndex].behavior); + } +} + +// extend Slick namespace on window object when building as iife +if (IIFE_ONLY && window.Slick) { + Utils.extend(true, window, { + Slick: { + CrossGridRowMoveManager: SlickCrossGridRowMoveManager + } + }); +} + diff --git a/src/plugins/slick.rowmovemanager.js b/src/plugins/slick.rowmovemanager.js deleted file mode 100644 index 733f133f..00000000 --- a/src/plugins/slick.rowmovemanager.js +++ /dev/null @@ -1,284 +0,0 @@ -import { Event as SlickEvent_, EventHandler as EventHandler_, Utils as Utils_ } from '../slick.core'; - -// for (iife) load Slick methods from global Slick object, or use imports for (esm) -const SlickEvent = IIFE_ONLY ? Slick.Event : SlickEvent_; -const EventHandler = IIFE_ONLY ? Slick.EventHandler : EventHandler_; -const Utils = IIFE_ONLY ? Slick.Utils : Utils_; - -/** - * Row Move Manager options: - * cssClass: A CSS class to be added to the menu item container. - * columnId: Column definition id (defaults to "_move") - * cancelEditOnDrag: Do we want to cancel any Editing while dragging a row (defaults to false) - * disableRowSelection: Do we want to disable the row selection? (defaults to false) - * hideRowMoveShadow: Do we want to hide the row move shadow clone? (defaults to true) - * rowMoveShadowMarginTop: When row move shadow is shown, optional margin-top (defaults to 0) - * rowMoveShadowMarginLeft: When row move shadow is shown, optional margin-left (defaults to 0) - * rowMoveShadowOpacity: When row move shadow is shown, what is its opacity? (defaults to 0.95) - * rowMoveShadowScale: When row move shadow is shown, what is its size scale? (default to 0.75) - * singleRowMove: Do we want a single row move? Setting this to false means that it's a multple row move (defaults to false) - * width: Width of the column - * usabilityOverride: Callback method that user can override the default behavior of the row being moveable or not - * - */ - -export function RowMoveManager(options) { - var _grid; - var _canvas; - var _dragging; - var _self = this; - var _usabilityOverride = null; - var _handler = new EventHandler(); - var _defaults = { - columnId: "_move", - cssClass: null, - cancelEditOnDrag: false, - disableRowSelection: false, - hideRowMoveShadow: true, - rowMoveShadowMarginTop: 0, - rowMoveShadowMarginLeft: 0, - rowMoveShadowOpacity: 0.95, - rowMoveShadowScale: 0.75, - singleRowMove: false, - width: 40, - }; - - // user could override the expandable icon logic from within the options or after instantiating the plugin - if (options && typeof options.usabilityOverride === 'function') { - usabilityOverride(options.usabilityOverride); - } - - function init(grid) { - options = Utils.extend(true, {}, _defaults, 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 setOptions(newOptions) { - options = Utils.extend({}, options, newOptions); - } - - function handleDragInit(e) { - // prevent the grid from cancelling drag'n'drop by default - e.stopImmediatePropagation(); - } - - function handleDragStart(e, dd) { - var cell = _grid.getCellFromEvent(e); - var currentRow = cell && cell.row; - var dataContext = _grid.getDataItem(currentRow); - - if (!checkUsabilityOverride(currentRow, dataContext, _grid)) { - return; - } - - if (options.cancelEditOnDrag && _grid.getEditorLock().isActive()) { - _grid.getEditorLock().cancelCurrentEdit(); - } - - if (_grid.getEditorLock().isActive() || !isHandlerColumn(cell.cell)) { - return false; - } - - _dragging = true; - e.stopImmediatePropagation(); - - // optionally create a shadow element of the row so that we can see all the time which row exactly we're dragging - if (!options.hideRowMoveShadow) { - const cellNodeElm = _grid.getCellNode(cell.row, cell.cell); - const slickRowElm = cellNodeElm && cellNodeElm.closest('.slick-row'); - if (slickRowElm) { - dd.clonedSlickRow = slickRowElm.cloneNode(true); - dd.clonedSlickRow.classList.add('slick-reorder-shadow-row'); - dd.clonedSlickRow.style.display = 'none'; - dd.clonedSlickRow.style.marginLeft = Number(options.rowMoveShadowMarginLeft || 0) + 'px'; - dd.clonedSlickRow.style.marginTop = Number(options.rowMoveShadowMarginTop || 0) + 'px'; - dd.clonedSlickRow.style.opacity = `${options.rowMoveShadowOpacity || 0.95}`; - dd.clonedSlickRow.style.transform = `scale(${options.rowMoveShadowScale || 0.75})`; - _canvas.appendChild(dd.clonedSlickRow); - } - } - - var selectedRows = options.singleRowMove ? [cell.row] : _grid.getSelectedRows(); - - if (selectedRows.length === 0 || !selectedRows.some(selectedRow => selectedRow === cell.row)) { - selectedRows = [cell.row]; - if (!options.disableRowSelection) { - _grid.setSelectedRows(selectedRows); - } - } - - var rowHeight = _grid.getOptions().rowHeight; - - dd.selectedRows = selectedRows; - - dd.selectionProxy = document.createElement('div'); - dd.selectionProxy.className = 'slick-reorder-proxy'; - dd.selectionProxy.style.display = 'none'; - dd.selectionProxy.style.position = 'absolute'; - dd.selectionProxy.style.zIndex = '99999'; - dd.selectionProxy.style.width = `${_canvas.clientWidth}px`; - dd.selectionProxy.style.height = `${rowHeight * selectedRows.length}px`; - _canvas.appendChild(dd.selectionProxy); - - dd.guide = document.createElement('div'); - dd.guide.className = 'slick-reorder-guide'; - dd.guide.style.position = 'absolute'; - dd.guide.style.zIndex = '99999'; - dd.guide.style.width = `${_canvas.clientWidth}px`; - dd.guide.style.top = `-1000px`; - _canvas.appendChild(dd.guide); - - dd.insertBefore = -1; - } - - function handleDrag(evt, dd) { - if (!_dragging) { - return; - } - - evt.stopImmediatePropagation(); - const e = evt.getNativeEvent(); - - var targetEvent = e.touches ? e.touches[0] : e; - const top = targetEvent.pageY - (Utils.offset(_canvas).top || 0); - dd.selectionProxy.style.top = `${top - 5}px`; - dd.selectionProxy.style.display = 'block'; - - // if the row move shadow is enabled, we'll also make it follow the mouse cursor - if (dd.clonedSlickRow) { - dd.clonedSlickRow.style.top = `${top - 6}px`; - dd.clonedSlickRow.style.display = 'block'; - } - - var insertBefore = Math.max(0, Math.min(Math.round(top / _grid.getOptions().rowHeight), _grid.getDataLength())); - if (insertBefore !== dd.insertBefore) { - var eventData = { - "grid": _grid, - "rows": dd.selectedRows, - "insertBefore": insertBefore - }; - - if (_self.onBeforeMoveRows.notify(eventData).getReturnValue() === false) { - dd.canMove = false; - } else { - dd.canMove = true; - } - - // if there's a UsabilityOverride defined, we also need to verify that the condition is valid - if (_usabilityOverride && dd.canMove) { - var insertBeforeDataContext = _grid.getDataItem(insertBefore); - dd.canMove = checkUsabilityOverride(insertBefore, insertBeforeDataContext, _grid); - } - - // if the new target is possible we'll display the dark blue bar (representin the acceptability) at the target position - // else it won't show up (it will be off the screen) - if (!dd.canMove) { - dd.guide.style.top = '-1000px'; - } else { - dd.guide.style.top = `${insertBefore * (_grid.getOptions().rowHeight || 0)}px`; - } - - dd.insertBefore = insertBefore; - } - } - - function handleDragEnd(e, dd) { - if (!_dragging) { - return; - } - _dragging = false; - e.stopImmediatePropagation(); - - dd.guide.remove(); - dd.selectionProxy.remove(); - if (dd.clonedSlickRow) { - dd.clonedSlickRow.remove(); - dd.clonedSlickRow = null; - } - - if (dd.canMove) { - var eventData = { - "grid": _grid, - "rows": dd.selectedRows, - "insertBefore": dd.insertBefore - }; - // TODO: _grid.remapCellCssClasses ? - _self.onMoveRows.notify(eventData); - } - } - - function getColumnDefinition() { - return { - id: options.columnId || "_move", - name: "", - field: "move", - width: options.width || 40, - behavior: "selectAndMove", - selectable: false, - resizable: false, - // cssClass: options.cssClass, - formatter: moveIconFormatter - }; - } - - function moveIconFormatter(row, cell, value, columnDef, dataContext, grid) { - if (!checkUsabilityOverride(row, dataContext, grid)) { - return null; - } else { - return { addClasses: "cell-reorder dnd " + options.cssClass || '', text: "" }; - } - } - - function checkUsabilityOverride(row, dataContext, grid) { - if (typeof _usabilityOverride === 'function') { - return _usabilityOverride(row, dataContext, grid); - } - return true; - } - - /** - * Method that user can pass to override the default behavior or making every row moveable. - * In order word, user can choose which rows to be an available as moveable (or not) by providing his own logic show/hide icon and usability. - * @param overrideFn: override function callback - */ - function usabilityOverride(overrideFn) { - _usabilityOverride = overrideFn; - } - - function isHandlerColumn(columnIndex) { - return /move|selectAndMove/.test(_grid.getColumns()[columnIndex].behavior); - } - - Utils.extend(this, { - "onBeforeMoveRows": new SlickEvent(), - "onMoveRows": new SlickEvent(), - - "init": init, - "destroy": destroy, - "getColumnDefinition": getColumnDefinition, - "setOptions": setOptions, - "usabilityOverride": usabilityOverride, - "isHandlerColumn": isHandlerColumn, - "pluginName": "RowMoveManager" - }); -} - -// extend Slick namespace on window object when building as iife -if (IIFE_ONLY && window.Slick) { - Utils.extend(true, window, { - Slick: { - RowMoveManager - } - }); -} - diff --git a/src/plugins/slick.rowmovemanager.ts b/src/plugins/slick.rowmovemanager.ts new file mode 100644 index 00000000..79cb5a2a --- /dev/null +++ b/src/plugins/slick.rowmovemanager.ts @@ -0,0 +1,286 @@ +import { SlickEvent as SlickEvent_, SlickEventData as SlickEventData_, SlickEventHandler as SlickEventHandler_, Utils as Utils_ } from '../slick.core'; +import type { Column, DOMEvent, DragRowMove, FormatterResultObject, RowMoveManagerOption, UsabilityOverrideFn } from '../models/index'; +import type { SlickGrid } from '../slick.grid'; + +// for (iife) load Slick methods from global Slick object, or use imports for (esm) +const SlickEvent = IIFE_ONLY ? Slick.Event : SlickEvent_; +const SlickEventHandler = IIFE_ONLY ? Slick.EventHandler : SlickEventHandler_; +const Utils = IIFE_ONLY ? Slick.Utils : Utils_; + +/** + * Row Move Manager options: + * cssClass: A CSS class to be added to the menu item container. + * columnId: Column definition id (defaults to "_move") + * cancelEditOnDrag: Do we want to cancel any Editing while dragging a row (defaults to false) + * disableRowSelection: Do we want to disable the row selection? (defaults to false) + * hideRowMoveShadow: Do we want to hide the row move shadow clone? (defaults to true) + * rowMoveShadowMarginTop: When row move shadow is shown, optional margin-top (defaults to 0) + * rowMoveShadowMarginLeft: When row move shadow is shown, optional margin-left (defaults to 0) + * rowMoveShadowOpacity: When row move shadow is shown, what is its opacity? (defaults to 0.95) + * rowMoveShadowScale: When row move shadow is shown, what is its size scale? (default to 0.75) + * singleRowMove: Do we want a single row move? Setting this to false means that it's a multple row move (defaults to false) + * width: Width of the column + * usabilityOverride: Callback method that user can override the default behavior of the row being moveable or not + * + */ + +export class SlickRowMoveManager { + // -- + // public API + pluginName = 'RowMoveManager' as const; + onBeforeMoveRows = new SlickEvent<{ grid: SlickGrid; rows: number[]; insertBefore: number; }>(); + onMoveRows = new SlickEvent<{ grid: SlickGrid; rows: number[]; insertBefore: number; }>(); + + // -- + // protected props + protected _grid!: SlickGrid; + protected _canvas!: HTMLElement; + protected _dragging = false; + protected _eventHandler: SlickEventHandler_; + protected _usabilityOverride?: UsabilityOverrideFn; + protected _options: RowMoveManagerOption; + protected _defaults: RowMoveManagerOption = { + columnId: '_move', + cssClass: undefined, + cancelEditOnDrag: false, + disableRowSelection: false, + hideRowMoveShadow: true, + rowMoveShadowMarginTop: 0, + rowMoveShadowMarginLeft: 0, + rowMoveShadowOpacity: 0.95, + rowMoveShadowScale: 0.75, + singleRowMove: false, + width: 40, + }; + + constructor(options: Partial) { + this._options = Utils.extend(true, {}, this._defaults, options); + this._eventHandler = new SlickEventHandler(); + } + + + init(grid: SlickGrid) { + this._grid = grid; + this._canvas = this._grid.getCanvasNode(); + + // user could override the expandable icon logic from within the options or after instantiating the plugin + if (typeof this._options?.usabilityOverride === 'function') { + this.usabilityOverride(this._options.usabilityOverride); + } + + this._eventHandler + .subscribe(this._grid.onDragInit, this.handleDragInit.bind(this)) + .subscribe(this._grid.onDragStart, this.handleDragStart.bind(this)) + .subscribe(this._grid.onDrag, this.handleDrag.bind(this)) + .subscribe(this._grid.onDragEnd, this.handleDragEnd.bind(this)); + } + + destroy() { + this._eventHandler.unsubscribeAll(); + } + + setOptions(newOptions: Partial) { + this._options = Utils.extend({}, this._options, newOptions); + } + + protected handleDragInit(e: SlickEventData_) { + // prevent the grid from cancelling drag'n'drop by default + e.stopImmediatePropagation(); + } + + protected handleDragStart(e: DOMEvent, dd: DragRowMove): boolean | void { + const cell = this._grid.getCellFromEvent(e) || { cell: -1, row: -1 }; + const currentRow = cell?.row; + const dataContext = this._grid.getDataItem(currentRow); + + if (!this.checkUsabilityOverride(currentRow, dataContext, this._grid)) { + return; + } + + if (this._options.cancelEditOnDrag && this._grid.getEditorLock().isActive()) { + this._grid.getEditorLock().cancelCurrentEdit(); + } + + if (this._grid.getEditorLock().isActive() || !this.isHandlerColumn(cell.cell)) { + return false; + } + + this._dragging = true; + e.stopImmediatePropagation(); + + // optionally create a shadow element of the row so that we can see all the time which row exactly we're dragging + if (!this._options.hideRowMoveShadow) { + const slickRowElm = this._grid.getCellNode(cell.row, cell.cell)?.closest('.slick-row'); + if (slickRowElm) { + dd.clonedSlickRow = slickRowElm.cloneNode(true) as HTMLDivElement; + dd.clonedSlickRow.classList.add('slick-reorder-shadow-row'); + dd.clonedSlickRow.style.display = 'none'; + dd.clonedSlickRow.style.marginLeft = Number(this._options.rowMoveShadowMarginLeft || 0) + 'px'; + dd.clonedSlickRow.style.marginTop = Number(this._options.rowMoveShadowMarginTop || 0) + 'px'; + dd.clonedSlickRow.style.opacity = `${this._options.rowMoveShadowOpacity || 0.95}`; + dd.clonedSlickRow.style.transform = `scale(${this._options.rowMoveShadowScale || 0.75})`; + this._canvas.appendChild(dd.clonedSlickRow); + } + } + + let selectedRows = this._options.singleRowMove ? [cell.row] : this._grid.getSelectedRows(); + if (selectedRows.length === 0 || !selectedRows.some(selectedRow => selectedRow === cell.row)) { + selectedRows = [cell.row]; + if (!this._options.disableRowSelection) { + this._grid.setSelectedRows(selectedRows); + } + } + + const rowHeight = this._grid.getOptions().rowHeight; + + dd.selectedRows = selectedRows; + + dd.selectionProxy = document.createElement('div'); + dd.selectionProxy.className = 'slick-reorder-proxy'; + dd.selectionProxy.style.display = 'none'; + dd.selectionProxy.style.position = 'absolute'; + dd.selectionProxy.style.zIndex = '99999'; + dd.selectionProxy.style.width = `${this._canvas.clientWidth}px`; + dd.selectionProxy.style.height = `${rowHeight * selectedRows.length}px`; + this._canvas.appendChild(dd.selectionProxy); + + dd.guide = document.createElement('div'); + dd.guide.className = 'slick-reorder-guide'; + dd.guide.style.position = 'absolute'; + dd.guide.style.zIndex = '99999'; + dd.guide.style.width = `${this._canvas.clientWidth}px`; + dd.guide.style.top = `-1000px`; + this._canvas.appendChild(dd.guide); + + dd.insertBefore = -1; + } + + protected handleDrag(evt: SlickEventData_, dd: DragRowMove): boolean | void { + if (!this._dragging) { + return; + } + + evt.stopImmediatePropagation(); + const e = evt.getNativeEvent(); + + const targetEvent = e.touches ? e.touches[0] : e; + const top = targetEvent.pageY - (Utils.offset(this._canvas)?.top ?? 0); + dd.selectionProxy.style.top = `${top - 5}px`; + dd.selectionProxy.style.display = 'block'; + + // if the row move shadow is enabled, we'll also make it follow the mouse cursor + if (dd.clonedSlickRow) { + dd.clonedSlickRow.style.top = `${top - 6}px`; + dd.clonedSlickRow.style.display = 'block'; + } + + const insertBefore = Math.max(0, Math.min(Math.round(top / this._grid.getOptions().rowHeight), this._grid.getDataLength())); + if (insertBefore !== dd.insertBefore) { + const eventData = { + grid: this._grid, + rows: dd.selectedRows, + insertBefore + }; + + if (this.onBeforeMoveRows.notify(eventData).getReturnValue() === false) { + dd.canMove = false; + } else { + dd.canMove = true; + } + + // if there's a UsabilityOverride defined, we also need to verify that the condition is valid + if (this._usabilityOverride && dd.canMove) { + const insertBeforeDataContext = this._grid.getDataItem(insertBefore); + dd.canMove = this.checkUsabilityOverride(insertBefore, insertBeforeDataContext, this._grid); + } + + // if the new target is possible we'll display the dark blue bar (representin the acceptability) at the target position + // else it won't show up (it will be off the screen) + if (!dd.canMove) { + dd.guide.style.top = '-1000px'; + } else { + dd.guide.style.top = `${insertBefore * (this._grid.getOptions().rowHeight || 0)}px`; + } + + dd.insertBefore = insertBefore; + } + } + + protected handleDragEnd(e: SlickEventData_, dd: DragRowMove) { + if (!this._dragging) { + return; + } + this._dragging = false; + e.stopImmediatePropagation(); + + dd.guide?.remove(); + dd.selectionProxy?.remove(); + dd.clonedSlickRow?.remove(); + + if (dd.canMove) { + const eventData = { + grid: this._grid, + rows: dd.selectedRows, + insertBefore: dd.insertBefore + }; + // TODO: this._grid.remapCellCssClasses ? + this.onMoveRows.notify(eventData); + } + } + + getColumnDefinition(): Column { + const columnId = String(this._options?.columnId ?? this._defaults.columnId); + + return { + id: columnId, + name: '', + field: 'move', + behavior: 'selectAndMove', + excludeFromColumnPicker: true, + excludeFromGridMenu: true, + excludeFromHeaderMenu: true, + resizable: false, + selectable: false, + width: this._options.width || 40, + formatter: this.moveIconFormatter.bind(this) + }; + } + + protected moveIconFormatter(row: number, _cell: number, _val: any, _column: Column, dataContext: any, grid: SlickGrid): FormatterResultObject | string { + if (!this.checkUsabilityOverride(row, dataContext, grid)) { + return ''; + } else { + return { addClasses: `cell-reorder dnd ${this._options.cssClass || ''}`, text: '' }; + } + } + + protected checkUsabilityOverride(row: number, dataContext: any, grid: SlickGrid) { + if (typeof this._usabilityOverride === 'function') { + return this._usabilityOverride(row, dataContext, grid); + } + return true; + } + + /** + * Method that user can pass to override the default behavior or making every row moveable. + * In order word, user can choose which rows to be an available as moveable (or not) by providing his own logic show/hide icon and usability. + * @param overrideFn: override function callback + */ + usabilityOverride(overrideFn: UsabilityOverrideFn) { + this._usabilityOverride = overrideFn; + } + + isHandlerColumn(columnIndex: number | string) { + return /move|selectAndMove/.test(this._grid.getColumns()[columnIndex].behavior); + } +} + +// extend Slick namespace on window object when building as iife +if (IIFE_ONLY && window.Slick) { + Utils.extend(true, window, { + Slick: { + RowMoveManager: SlickRowMoveManager + } + }); +} + diff --git a/src/plugins/slick.state.ts b/src/plugins/slick.state.ts index 04b34f0d..84928790 100644 --- a/src/plugins/slick.state.ts +++ b/src/plugins/slick.state.ts @@ -1,6 +1,6 @@ import { SlickEvent as SlickEvent_, Utils as Utils_ } from '../slick.core'; import type { Column, ColumnSort, Plugin } from '../models/index'; -import type { SlickGrid } from 'src/slick.grid'; +import type { SlickGrid } from '../slick.grid'; // for (iife) load Slick methods from global Slick object, or use imports for (esm) const SlickEvent = IIFE_ONLY ? Slick.Event : SlickEvent_; diff --git a/src/slick.core.ts b/src/slick.core.ts index 58efc274..3ad846f9 100644 --- a/src/slick.core.ts +++ b/src/slick.core.ts @@ -889,7 +889,7 @@ const SlickCore = { NonDataRow: SlickNonDataItem, Group: SlickGroup, GroupTotals: SlickGroupTotals, - // EditorLock: EditorLock, + EditorLock: SlickEditorLock, RegexSanitizer: regexSanitizer, // BindingEventService: BindingEventService, Utils: { @@ -1006,7 +1006,7 @@ const SlickCore = { } export const { - Utils, Event, EventData, EventHandler, Group, GroupTotals, NonDataRow, Range, + Utils, EditorLock, Event, EventData, EventHandler, Group, GroupTotals, NonDataRow, Range, RegexSanitizer, GlobalEditorLock, keyCode, preClickClassName, GridAutosizeColsMode, ColAutosizeMode, RowSelectionMode, ValueFilterMode, WidthEvalMode } = SlickCore;