Skip to content

Commit

Permalink
feat: add column reorderable option to optionally lock a column (#1357
Browse files Browse the repository at this point in the history
)

* feat: add column `reorderable` option to optionally lock a column
  • Loading branch information
ghiscoding authored Jan 20, 2024
1 parent a693965 commit 44f6c08
Show file tree
Hide file tree
Showing 17 changed files with 86 additions and 20 deletions.
12 changes: 12 additions & 0 deletions packages/common/src/core/__tests__/slickGrid.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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<any, Column>(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' }];
Expand Down Expand Up @@ -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);
Expand Down
22 changes: 16 additions & 6 deletions packages/common/src/core/slickGrid.ts
Original file line number Diff line number Diff line change
Expand Up @@ -206,6 +206,7 @@ export class SlickGrid<TData = any, C extends Column<TData> = Column<TData>, O e
suppressActiveCellChangeOnEdit: false,
enableCellNavigation: true,
enableColumnReorder: true,
unorderableColumnCssClass: 'unorderable',
asyncEditorLoading: false,
asyncEditorLoadDelay: 100,
forceFitColumns: false,
Expand Down Expand Up @@ -268,16 +269,17 @@ export class SlickGrid<TData = any, C extends Column<TData> = Column<TData>, 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<C>;

protected _columnResizeTimer?: NodeJS.Timeout;
Expand Down Expand Up @@ -1589,6 +1591,9 @@ export class SlickGrid<TData = any, C extends Column<TData> = Column<TData>, 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);

Expand Down Expand Up @@ -1790,6 +1795,11 @@ export class SlickGrid<TData = any, C extends Column<TData> = Column<TData>, 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;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -115,6 +115,7 @@ describe('SlickCheckboxSelectColumn Plugin', () => {
field: '_checkbox_selector',
hideSelectAllCheckbox: false,
name: '',
reorderable: false,
toolTip: 'Select/Deselect All',
width: 30,
hideInColumnTitleRow: false,
Expand All @@ -139,6 +140,7 @@ describe('SlickCheckboxSelectColumn Plugin', () => {
field: '_checkbox_selector',
hideSelectAllCheckbox: true,
name: '',
reorderable: false,
toolTip: 'Select/Deselect All',
width: 30,
hideInColumnTitleRow: true,
Expand Down Expand Up @@ -394,6 +396,7 @@ describe('SlickCheckboxSelectColumn Plugin', () => {
excludeFromColumnPicker: true,
excludeFromGridMenu: true,
excludeFromQuery: true,
reorderable: false,
excludeFromHeaderMenu: true,
hideSelectAllCheckbox: false,
resizable: false,
Expand Down Expand Up @@ -431,6 +434,7 @@ describe('SlickCheckboxSelectColumn Plugin', () => {
excludeFromGridMenu: true,
excludeFromHeaderMenu: true,
excludeFromQuery: true,
reorderable: false,
field: 'chk-id',
hideSelectAllCheckbox: false,
id: 'chk-id',
Expand Down Expand Up @@ -465,6 +469,7 @@ describe('SlickCheckboxSelectColumn Plugin', () => {
excludeFromGridMenu: true,
excludeFromHeaderMenu: true,
excludeFromQuery: true,
reorderable: false,
field: '_checkbox_selector',
formatter: expect.toBeFunction(),
hideSelectAllCheckbox: false,
Expand All @@ -490,6 +495,7 @@ describe('SlickCheckboxSelectColumn Plugin', () => {
excludeFromGridMenu: true,
excludeFromHeaderMenu: true,
excludeFromQuery: true,
reorderable: false,
field: '_checkbox_selector',
formatter: expect.toBeFunction(),
hideSelectAllCheckbox: true,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand All @@ -149,6 +150,7 @@ describe('SlickRowMoveManager Plugin', () => {
id: 'move-id',
name: '',
behavior: 'selectAndMove',
reorderable: false,
resizable: false,
selectable: false,
width: 40,
Expand All @@ -172,6 +174,7 @@ describe('SlickRowMoveManager Plugin', () => {
cssClass: 'some-class',
disableRowSelection: false,
hideRowMoveShadow: false,
reorderable: false,
rowMoveShadowMarginLeft: 2,
rowMoveShadowMarginTop: 5,
rowMoveShadowOpacity: 1,
Expand All @@ -196,6 +199,7 @@ describe('SlickRowMoveManager Plugin', () => {
formatter: expect.toBeFunction(),
id: 'move-id',
name: '',
reorderable: false,
resizable: false,
selectable: false,
width: 40,
Expand Down
2 changes: 2 additions & 0 deletions packages/common/src/extensions/slickCheckboxSelectColumn.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ export class SlickCheckboxSelectColumn<T = any> {
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
Expand Down Expand Up @@ -239,6 +240,7 @@ export class SlickCheckboxSelectColumn<T = any> {
excludeFromHeaderMenu: true,
hideSelectAllCheckbox: this._addonOptions.hideSelectAllCheckbox,
resizable: false,
reorderable: this._addonOptions.reorderable,
sortable: false,
width: this._addonOptions.width || 30,
formatter: this.checkboxSelectionFormatter.bind(this),
Expand Down
2 changes: 2 additions & 0 deletions packages/common/src/extensions/slickRowBasedEdit.ts
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ export class SlickRowBasedEdit {
allowMultipleRows: false,
columnId: '_slick_rowbasededit_action',
columnIndexPosition: -1,
reorderable: false,
} as RowBasedEditOptions;
protected _editedRows: Map<string, EditedRowDetails> = new Map();

Expand Down Expand Up @@ -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 ?? {}),
Expand Down
2 changes: 2 additions & 0 deletions packages/common/src/extensions/slickRowMoveManager.ts
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ export class SlickRowMoveManager {
cancelEditOnDrag: false,
disableRowSelection: false,
hideRowMoveShadow: true,
reorderable: false,
rowMoveShadowMarginTop: 0,
rowMoveShadowMarginLeft: 0,
rowMoveShadowOpacity: 0.9,
Expand Down Expand Up @@ -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,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand Down
6 changes: 6 additions & 0 deletions packages/common/src/interfaces/column.interface.ts
Original file line number Diff line number Diff line change
Expand Up @@ -290,6 +290,12 @@ export interface Column<T = any> {
*/
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;

Expand Down
3 changes: 3 additions & 0 deletions packages/common/src/interfaces/gridOption.interface.ts
Original file line number Diff line number Diff line change
Expand Up @@ -343,6 +343,9 @@ export interface GridOption<C extends Column = Column> {
*/
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?
Expand Down
23 changes: 13 additions & 10 deletions packages/common/src/interfaces/rowBasedEditOption.interface.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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.
*/
Expand Down Expand Up @@ -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

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -49,15 +49,18 @@ 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;

/** 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
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand Down
1 change: 1 addition & 0 deletions packages/common/src/styles/_variables.scss
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
3 changes: 3 additions & 0 deletions packages/common/src/styles/slick-bootstrap.scss
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,7 @@ describe('SlickRowDetailView plugin', () => {
keyPrefix: '::',
loadOnce: true,
collapseAllOnSort: true,
reorderable: false,
saveDetailViewOnScroll: true,
singleRowExpand: true,
useSimpleViewportCalc: true,
Expand Down Expand Up @@ -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' } });
Expand All @@ -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();
Expand Down
2 changes: 2 additions & 0 deletions packages/row-detail-view-plugin/src/slickRowDetailView.ts
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,7 @@ export class SlickRowDetailView implements ExternalResource, UniversalRowDetailV
keyPrefix: '_',
loadOnce: false,
maxRows: undefined,
reorderable: false,
saveDetailViewOnScroll: true,
singleRowExpand: false,
useSimpleViewportCalc: false,
Expand Down Expand Up @@ -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,
Expand Down

0 comments on commit 44f6c08

Please sign in to comment.