diff --git a/packages/common/src/core/__tests__/slickGrid.spec.ts b/packages/common/src/core/__tests__/slickGrid.spec.ts index 1505856ca..87f3fae0f 100644 --- a/packages/common/src/core/__tests__/slickGrid.spec.ts +++ b/packages/common/src/core/__tests__/slickGrid.spec.ts @@ -215,6 +215,16 @@ describe('SlickGrid core file', () => { expect(renderSpy).toHaveBeenCalled(); }); + it('should be able to disable column reorderable', () => { + const columns = [{ id: 'firstName', field: 'firstName', name: 'First Name', reorderable: false }] as Column[]; + const data = [{ id: 0, firstName: 'John' }, { id: 1, firstName: 'Jane' }]; + + grid = new SlickGrid(container, data, columns, defaultOptions); + const headerElms = container.querySelectorAll('.slick-header-column'); + + expect(headerElms[0].classList.contains('unorderable')).toBeTruthy(); + }); + it('should be able to edit when editable grid option is enabled and invalidate some rows', () => { const columns = [{ id: 'firstName', field: 'firstName', name: 'First Name', editor: InputEditor }] as Column[]; const data = [{ id: 0, firstName: 'John' }, { id: 1, firstName: 'Jane' }]; @@ -1920,12 +1930,14 @@ describe('SlickGrid core file', () => { const dragEvent = new CustomEvent('DragEvent'); jest.spyOn(viewportTopLeft, 'getBoundingClientRect').mockReturnValue({ left: 25, top: 10, right: 0, bottom: 0 } as DOMRect); Object.defineProperty(dragEvent, 'originalEvent', { writable: true, value: { pageX: 20 } }); + Object.defineProperty(dragEvent, 'related', { writable: true, value: headerColumnElms[0] }); Object.defineProperty(dragEvent, 'item', { writable: true, value: headerColumnElms[0] }); Object.defineProperty(headerColumnElms[0], 'clientLeft', { writable: true, value: 25 }); Object.defineProperty(viewportTopLeft, 'clientLeft', { writable: true, value: 25 }); expect(sortInstance).toBeTruthy(); sortInstance.options.onStart(dragEvent); + sortInstance.options.onMove(dragEvent); expect(viewportTopLeft.scrollLeft).toBe(0); jest.advanceTimersByTime(100); diff --git a/packages/common/src/core/slickGrid.ts b/packages/common/src/core/slickGrid.ts index d8ffd082d..7acf545de 100644 --- a/packages/common/src/core/slickGrid.ts +++ b/packages/common/src/core/slickGrid.ts @@ -206,6 +206,7 @@ export class SlickGrid = Column, O e suppressActiveCellChangeOnEdit: false, enableCellNavigation: true, enableColumnReorder: true, + unorderableColumnCssClass: 'unorderable', asyncEditorLoading: false, asyncEditorLoadDelay: 100, forceFitColumns: false, @@ -268,16 +269,17 @@ export class SlickGrid = Column, O e protected _columnDefaults = { name: '', - resizable: true, - sortable: false, - minWidth: 30, - maxWidth: undefined, - rerenderOnResize: false, headerCssClass: null, defaultSortAsc: true, focusable: true, + hidden: false, + minWidth: 30, + maxWidth: undefined, + rerenderOnResize: false, + reorderable: true, + resizable: true, + sortable: false, selectable: true, - hidden: false } as Partial; protected _columnResizeTimer?: NodeJS.Timeout; @@ -1589,6 +1591,9 @@ export class SlickGrid = Column, O e if (m.toolTip) { header.title = m.toolTip; } + if (!m.reorderable) { + header.classList.add(this._options.unorderableColumnCssClass!); + } const colNameElm = createDomElement('span', { className: 'slick-column-name' }, header); this.applyHtmlCode(colNameElm, m.name as string); @@ -1790,6 +1795,11 @@ export class SlickGrid = Column, O e dragoverBubble: false, revertClone: true, scroll: !this.hasFrozenColumns(), // enable auto-scroll + // lock unorderable columns by using a combo of filter + onMove + filter: `.${this._options.unorderableColumnCssClass}`, + onMove: (event) => { + return !event.related.classList.contains(this._options.unorderableColumnCssClass as string); + }, onStart: (e: SortableEvent) => { canDragScroll = !this.hasFrozenColumns() || getOffset(e.item)!.left > getOffset(this._viewportScrollContainerX)!.left; diff --git a/packages/common/src/extensions/__tests__/slickCheckboxSelectColumn.spec.ts b/packages/common/src/extensions/__tests__/slickCheckboxSelectColumn.spec.ts index 42cc5a884..96f86e0c4 100644 --- a/packages/common/src/extensions/__tests__/slickCheckboxSelectColumn.spec.ts +++ b/packages/common/src/extensions/__tests__/slickCheckboxSelectColumn.spec.ts @@ -115,6 +115,7 @@ describe('SlickCheckboxSelectColumn Plugin', () => { field: '_checkbox_selector', hideSelectAllCheckbox: false, name: '', + reorderable: false, toolTip: 'Select/Deselect All', width: 30, hideInColumnTitleRow: false, @@ -139,6 +140,7 @@ describe('SlickCheckboxSelectColumn Plugin', () => { field: '_checkbox_selector', hideSelectAllCheckbox: true, name: '', + reorderable: false, toolTip: 'Select/Deselect All', width: 30, hideInColumnTitleRow: true, @@ -394,6 +396,7 @@ describe('SlickCheckboxSelectColumn Plugin', () => { excludeFromColumnPicker: true, excludeFromGridMenu: true, excludeFromQuery: true, + reorderable: false, excludeFromHeaderMenu: true, hideSelectAllCheckbox: false, resizable: false, @@ -431,6 +434,7 @@ describe('SlickCheckboxSelectColumn Plugin', () => { excludeFromGridMenu: true, excludeFromHeaderMenu: true, excludeFromQuery: true, + reorderable: false, field: 'chk-id', hideSelectAllCheckbox: false, id: 'chk-id', @@ -465,6 +469,7 @@ describe('SlickCheckboxSelectColumn Plugin', () => { excludeFromGridMenu: true, excludeFromHeaderMenu: true, excludeFromQuery: true, + reorderable: false, field: '_checkbox_selector', formatter: expect.toBeFunction(), hideSelectAllCheckbox: false, @@ -490,6 +495,7 @@ describe('SlickCheckboxSelectColumn Plugin', () => { excludeFromGridMenu: true, excludeFromHeaderMenu: true, excludeFromQuery: true, + reorderable: false, field: '_checkbox_selector', formatter: expect.toBeFunction(), hideSelectAllCheckbox: true, diff --git a/packages/common/src/extensions/__tests__/slickRowMoveManager.spec.ts b/packages/common/src/extensions/__tests__/slickRowMoveManager.spec.ts index a85fb3a95..4062f0ae1 100644 --- a/packages/common/src/extensions/__tests__/slickRowMoveManager.spec.ts +++ b/packages/common/src/extensions/__tests__/slickRowMoveManager.spec.ts @@ -127,6 +127,7 @@ describe('SlickRowMoveManager Plugin', () => { cssClass: 'slick-row-move-column', disableRowSelection: false, hideRowMoveShadow: true, + reorderable: false, rowMoveShadowMarginLeft: 0, rowMoveShadowMarginTop: 0, rowMoveShadowOpacity: 0.9, @@ -149,6 +150,7 @@ describe('SlickRowMoveManager Plugin', () => { id: 'move-id', name: '', behavior: 'selectAndMove', + reorderable: false, resizable: false, selectable: false, width: 40, @@ -172,6 +174,7 @@ describe('SlickRowMoveManager Plugin', () => { cssClass: 'some-class', disableRowSelection: false, hideRowMoveShadow: false, + reorderable: false, rowMoveShadowMarginLeft: 2, rowMoveShadowMarginTop: 5, rowMoveShadowOpacity: 1, @@ -196,6 +199,7 @@ describe('SlickRowMoveManager Plugin', () => { formatter: expect.toBeFunction(), id: 'move-id', name: '', + reorderable: false, resizable: false, selectable: false, width: 40, diff --git a/packages/common/src/extensions/slickCheckboxSelectColumn.ts b/packages/common/src/extensions/slickCheckboxSelectColumn.ts index 9dabe9e99..af921593f 100644 --- a/packages/common/src/extensions/slickCheckboxSelectColumn.ts +++ b/packages/common/src/extensions/slickCheckboxSelectColumn.ts @@ -17,6 +17,7 @@ export class SlickCheckboxSelectColumn { name: '', toolTip: 'Select/Deselect All', width: 30, + reorderable: false, applySelectOnAllPages: true, // when that is enabled the "Select All" will be applied to all pages (when using Pagination) hideInColumnTitleRow: false, hideInFilterHeaderRow: true @@ -239,6 +240,7 @@ export class SlickCheckboxSelectColumn { excludeFromHeaderMenu: true, hideSelectAllCheckbox: this._addonOptions.hideSelectAllCheckbox, resizable: false, + reorderable: this._addonOptions.reorderable, sortable: false, width: this._addonOptions.width || 30, formatter: this.checkboxSelectionFormatter.bind(this), diff --git a/packages/common/src/extensions/slickRowBasedEdit.ts b/packages/common/src/extensions/slickRowBasedEdit.ts index 16ae530c8..9d71ced2a 100644 --- a/packages/common/src/extensions/slickRowBasedEdit.ts +++ b/packages/common/src/extensions/slickRowBasedEdit.ts @@ -47,6 +47,7 @@ export class SlickRowBasedEdit { allowMultipleRows: false, columnId: '_slick_rowbasededit_action', columnIndexPosition: -1, + reorderable: false, } as RowBasedEditOptions; protected _editedRows: Map = new Map(); @@ -185,6 +186,7 @@ export class SlickRowBasedEdit { width: 75, maxWidth: 75, excludeFromExport: true, + reorderable: this._addonOptions?.reorderable, formatter: this.actionColumnFormatter.bind(this), onCellClick: this.onCellClickHandler.bind(this), ...(this._addonOptions?.actionColumnConfig ?? {}), diff --git a/packages/common/src/extensions/slickRowMoveManager.ts b/packages/common/src/extensions/slickRowMoveManager.ts index 2913fe559..7f8cb9744 100644 --- a/packages/common/src/extensions/slickRowMoveManager.ts +++ b/packages/common/src/extensions/slickRowMoveManager.ts @@ -41,6 +41,7 @@ export class SlickRowMoveManager { cancelEditOnDrag: false, disableRowSelection: false, hideRowMoveShadow: true, + reorderable: false, rowMoveShadowMarginTop: 0, rowMoveShadowMarginLeft: 0, rowMoveShadowOpacity: 0.9, @@ -136,6 +137,7 @@ export class SlickRowMoveManager { excludeFromQuery: true, excludeFromHeaderMenu: true, field: columnId, + reorderable: this._addonOptions.reorderable, resizable: false, selectable: false, width: this._addonOptions.width || 40, diff --git a/packages/common/src/interfaces/checkboxSelectorOption.interface.ts b/packages/common/src/interfaces/checkboxSelectorOption.interface.ts index 687d78c81..ccae41f35 100644 --- a/packages/common/src/interfaces/checkboxSelectorOption.interface.ts +++ b/packages/common/src/interfaces/checkboxSelectorOption.interface.ts @@ -40,6 +40,9 @@ export interface CheckboxSelectorOption { */ name?: string; + /** Defaults to false, makes the column reorderable to another position in the grid. */ + reorderable?: boolean; + /** Defaults to "Select/Deselect All", provide a tooltip that will be shown over the "Select All" checkbox */ toolTip?: string; diff --git a/packages/common/src/interfaces/column.interface.ts b/packages/common/src/interfaces/column.interface.ts index 2dbf1af1a..bd6751ddf 100644 --- a/packages/common/src/interfaces/column.interface.ts +++ b/packages/common/src/interfaces/column.interface.ts @@ -290,6 +290,12 @@ export interface Column { */ queryFieldSorter?: string; + /** + * Defaults to true, makes the column reorderable to another position in the grid. + * NOTE: Works best when used as first or last columns of the grid (e.g.: row selection checkbox as first column). + */ + reorderable?: boolean; + /** Is the column resizable, can we make it wider/thinner? A resize cursor icon will show on the right side of the column when enabled. */ resizable?: boolean; diff --git a/packages/common/src/interfaces/gridOption.interface.ts b/packages/common/src/interfaces/gridOption.interface.ts index d4aa3f2a4..664e7655e 100644 --- a/packages/common/src/interfaces/gridOption.interface.ts +++ b/packages/common/src/interfaces/gridOption.interface.ts @@ -343,6 +343,9 @@ export interface GridOption { */ enableColumnReorder?: boolean | ColumnReorderFunction; + /** Defaults to "unorderable", a CSS class name that will be added to the column classes when the column cannot be reordered. */ + unorderableColumnCssClass?: string; + /** * Defaults to true, when doing a double-click in the column resize section (top right of a column when the mouse resize icon shows up), * do we want to automatically resize the column by its cell content? diff --git a/packages/common/src/interfaces/rowBasedEditOption.interface.ts b/packages/common/src/interfaces/rowBasedEditOption.interface.ts index 57d7248aa..04f1df147 100644 --- a/packages/common/src/interfaces/rowBasedEditOption.interface.ts +++ b/packages/common/src/interfaces/rowBasedEditOption.interface.ts @@ -9,16 +9,6 @@ export interface RowBasedEditOptions { /** whether multiple rows can be toggled into edit mode at the same itme (default: false) */ allowMultipleRows?: boolean; - /** Defaults to "_slick_rowbasededit_action", Row Detail column Id */ - columnId?: string; - - /** - * Defaults to -1, the column index position in the grid by default it will show as the last column. - * 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; - /** * additional column configurations for the action column. You can override the defaults by passing your own Column definition. */ @@ -61,6 +51,19 @@ export interface RowBasedEditOptions { updateButtonPrompt?: string; }; + /** Defaults to "_slick_rowbasededit_action", Row Detail column Id */ + columnId?: string; + + /** + * Defaults to -1, the column index position in the grid by default it will show as the last column. + * 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, makes the column reorderable to another position in the grid. */ + reorderable?: boolean; + // -- // Available Callbacks diff --git a/packages/common/src/interfaces/rowDetailViewOption.interface.ts b/packages/common/src/interfaces/rowDetailViewOption.interface.ts index c2fac58a4..27f5cb59e 100644 --- a/packages/common/src/interfaces/rowDetailViewOption.interface.ts +++ b/packages/common/src/interfaces/rowDetailViewOption.interface.ts @@ -49,8 +49,8 @@ export interface RowDetailViewOption { */ parent?: any; - /** Defaults to false, when True will open the row detail on a row click (from any column) */ - useRowClick?: boolean; + /** Defaults to false, makes the column reorderable to another position in the grid. */ + reorderable?: boolean; /** Defaults to true, which will save the row detail view in a cache when it detects that it will become out of the viewport buffer */ saveDetailViewOnScroll?: boolean; @@ -58,6 +58,9 @@ export interface RowDetailViewOption { /** Defaults to false, which will limit expanded row to only 1 at a time (it will close all other rows before opening new one). */ singleRowExpand?: boolean; + /** Defaults to false, when True will open the row detail on a row click (from any column) */ + useRowClick?: boolean; + /** * Defaults to false, which will use a simpler way of calculating when rows become out (or back) of viewport range. * It is recommended to enable this flag since it seems to work correctly with Slickgrid-Universal while the inverse is misbehaving diff --git a/packages/common/src/interfaces/rowMoveManagerOption.interface.ts b/packages/common/src/interfaces/rowMoveManagerOption.interface.ts index f7692ac8f..b2a1dbe88 100644 --- a/packages/common/src/interfaces/rowMoveManagerOption.interface.ts +++ b/packages/common/src/interfaces/rowMoveManagerOption.interface.ts @@ -39,6 +39,9 @@ export interface RowMoveManagerOption { /** Defaults to True, do we want to hide the row move shadow of what we're dragging? */ hideRowMoveShadow?: boolean; + /** Defaults to false, makes the column reorderable to another position in the grid. */ + reorderable?: boolean; + /** Defaults to 0, optional left margin of the row move shadown element when enabled */ rowMoveShadowMarginLeft?: number | string; diff --git a/packages/common/src/styles/_variables.scss b/packages/common/src/styles/_variables.scss index d14675046..77ae1663c 100644 --- a/packages/common/src/styles/_variables.scss +++ b/packages/common/src/styles/_variables.scss @@ -35,6 +35,7 @@ $slick-container-border-left: 0 none !default; $slick-grid-border-color: fade(black, 3%) !default; $slick-grid-border-style: solid !default; $slick-grid-header-background: rgba(255, 255, 255, .6) !default; +$slick-grid-header-unorderable-bg-color: darken($slick-grid-header-background, 4%) !default; $slick-grid-cell-color: rgb(255, 255, 255) !default; $slick-gray-dark: #333 !default; $slick-link-color: #08c !default; diff --git a/packages/common/src/styles/slick-bootstrap.scss b/packages/common/src/styles/slick-bootstrap.scss index e74c5840a..5baf10c1a 100644 --- a/packages/common/src/styles/slick-bootstrap.scss +++ b/packages/common/src/styles/slick-bootstrap.scss @@ -376,6 +376,9 @@ top: var(--slick-header-resizable-hover-top, $slick-header-resizable-hover-top); opacity: var(--slick-header-resizable-hover-opacity, $slick-header-resizable-hover-opacity); } + &.unorderable { + background-color: var(--slick-grid-header-unorderable-bg-color, $slick-grid-header-unorderable-bg-color); + } } } diff --git a/packages/row-detail-view-plugin/src/slickRowDetailView.spec.ts b/packages/row-detail-view-plugin/src/slickRowDetailView.spec.ts index b67c3f613..20787bf27 100644 --- a/packages/row-detail-view-plugin/src/slickRowDetailView.spec.ts +++ b/packages/row-detail-view-plugin/src/slickRowDetailView.spec.ts @@ -90,6 +90,7 @@ describe('SlickRowDetailView plugin', () => { keyPrefix: '::', loadOnce: true, collapseAllOnSort: true, + reorderable: false, saveDetailViewOnScroll: true, singleRowExpand: true, useSimpleViewportCalc: true, @@ -203,7 +204,7 @@ describe('SlickRowDetailView plugin', () => { id: '_detail_', field: '_detail_', name: '', alwaysRenderColumn: true, cssClass: 'some-class', excludeFromExport: true, excludeFromColumnPicker: true, excludeFromGridMenu: true, excludeFromQuery: true, excludeFromHeaderMenu: true, formatter: expect.anything(), - resizable: false, sortable: false, toolTip: 'title', width: 30, + reorderable: false, resizable: false, sortable: false, toolTip: 'title', width: 30, }; const output = plugin.create(mockColumns, { rowDetailView: { process: processMock, expandableOverride: overrideMock, panelRows: 4, columnId: '_detail_', cssClass: 'some-class', toolTip: 'title' } }); @@ -223,7 +224,7 @@ describe('SlickRowDetailView plugin', () => { id: '_detail_', field: '_detail_', name: '', alwaysRenderColumn: true, cssClass: 'some-class', excludeFromExport: true, excludeFromColumnPicker: true, excludeFromGridMenu: true, excludeFromQuery: true, excludeFromHeaderMenu: true, formatter: expect.anything(), - resizable: false, sortable: false, toolTip: 'title', width: 30, + reorderable: false, resizable: false, sortable: false, toolTip: 'title', width: 30, }); expect(plugin.getExpandableOverride()).toBeFalsy(); expect(output instanceof SlickRowDetailView).toBeTruthy(); diff --git a/packages/row-detail-view-plugin/src/slickRowDetailView.ts b/packages/row-detail-view-plugin/src/slickRowDetailView.ts index 83b16ef30..4900753c0 100644 --- a/packages/row-detail-view-plugin/src/slickRowDetailView.ts +++ b/packages/row-detail-view-plugin/src/slickRowDetailView.ts @@ -76,6 +76,7 @@ export class SlickRowDetailView implements ExternalResource, UniversalRowDetailV keyPrefix: '_', loadOnce: false, maxRows: undefined, + reorderable: false, saveDetailViewOnScroll: true, singleRowExpand: false, useSimpleViewportCalc: false, @@ -388,6 +389,7 @@ export class SlickRowDetailView implements ExternalResource, UniversalRowDetailV excludeFromQuery: true, excludeFromHeaderMenu: true, formatter: this.detailSelectionFormatter.bind(this), + reorderable: this._addonOptions.reorderable, resizable: false, sortable: false, toolTip: this._addonOptions.toolTip,