diff --git a/docs/grid-functionalities/grouping-aggregators.md b/docs/grid-functionalities/grouping-aggregators.md
index 60179aff6..2215180ef 100644
--- a/docs/grid-functionalities/grouping-aggregators.md
+++ b/docs/grid-functionalities/grouping-aggregators.md
@@ -2,6 +2,7 @@
- [Demo](#demo)
- [Description](#description)
- [Setup](#setup)
+- [Draggable Dropzone Location](#draggable-dropzone-location)
- [Aggregators](#aggregators)
- [SortComparers](https://github.com/ghiscoding/slickgrid-universal/blob/master/packages/common/src/sortComparers/sortComparers.index.ts)
- [GroupTotalsFormatter](#group-totals-formatter)
@@ -28,6 +29,43 @@ The important thing to understand while working with `SlickGrid` is that Groupin
2. You need to add a `groupTotalsFormatter` on the column definition you want it to be calculated
- this is very similar to a Formatter, except that they are designed to show aggregate results, e.g:: `Total: 142.50$`
+### Draggable Dropzone Location
+
+The Draggable Grouping can be located in either the Top-Header or the Pre-Header as described below.
+
+#### Pre-Heaader
+Draggable Grouping can be located in either the Pre-Header of the Top-Header, however when it is located in the Pre-Header then the Header Grouping will not be available (because both of them would conflict with each other). Note that prior to the version 5.1 of Slickgrid-Universal, the Pre-Header was the default and only available option.
+
+```ts
+this.gridOptions = {
+ createPreHeaderPanel: true,
+ showPreHeaderPanel: true,
+ preHeaderPanelHeight: 26,
+ draggableGrouping: {
+ // ... any draggable plugin option
+ },
+}
+```
+
+#### Top-Heaader
+##### requires v5.1 and higher
+This is the preferred section since the Top-Header is on top of all headers (including pre-header) and it will always be the full grid width. Using the Top-Header also frees up the Pre-Header section for the potential use of Header Grouping.
+
+When using Draggable Grouping and Header Grouping together, you need to enable both top-header and pre-header.
+```ts
+this.gridOptions = {
+ // we'll use top-header for the Draggable Grouping
+ createTopHeaderPanel: true,
+ showTopHeaderPanel: true,
+ topHeaderPanelHeight: 35,
+
+ // pre-header will include our Header Grouping (i.e. "Common Factor")
+ createPreHeaderPanel: true,
+ showPreHeaderPanel: true,
+ preHeaderPanelHeight: 26,
+}
+```
+
### Aggregators
The `Aggregators` is basically the accumulator, the logic that will do the sum (or any other aggregate we defined). We simply need to instantiate the `Aggregator` by passing the column definition `field` that will be used to accumulate. For example, if we have a column definition of Cost and we want to calculate it's sum, we can call the `Aggregator` as follow
```ts
diff --git a/examples/vite-demo-vanilla-bundle/src/examples/example03.ts b/examples/vite-demo-vanilla-bundle/src/examples/example03.ts
index 693b12312..7caf7a1df 100644
--- a/examples/vite-demo-vanilla-bundle/src/examples/example03.ts
+++ b/examples/vite-demo-vanilla-bundle/src/examples/example03.ts
@@ -77,7 +77,8 @@ export default class Example03 {
initializeGrid() {
this.columnDefinitions = [
{
- id: 'title', name: 'Title', field: 'title', sortable: true, type: FieldType.string,
+ id: 'title', name: 'Title', field: 'title', columnGroup: 'Common Factor',
+ sortable: true, type: FieldType.string,
editor: {
model: Editors.longText,
required: true,
@@ -95,7 +96,8 @@ export default class Example03 {
}
},
{
- id: 'duration', name: 'Duration', field: 'duration', sortable: true, filterable: true,
+ id: 'duration', name: 'Duration', field: 'duration', columnGroup: 'Common Factor',
+ sortable: true, filterable: true,
editor: {
model: Editors.float,
// required: true,
@@ -118,7 +120,45 @@ export default class Example03 {
}
},
{
- id: 'cost', name: 'Cost', field: 'cost',
+ id: 'start', name: 'Start', field: 'start', sortable: true, columnGroup: 'Period',
+ // formatter: Formatters.dateIso,
+ type: FieldType.date, outputType: FieldType.dateIso,
+ filterable: true, filter: { model: Filters.compoundDate },
+ formatter: Formatters.dateIso,
+ editor: { model: Editors.date },
+ grouping: {
+ getter: 'start',
+ formatter: (g) => `Start: ${g.value} (${g.count} items)`,
+ aggregators: [
+ new Aggregators.Sum('cost')
+ ],
+ aggregateCollapsed: false,
+ collapsed: false
+ }
+ },
+ {
+ id: 'finish', name: 'Finish', field: 'finish', columnGroup: 'Period',
+ sortable: true,
+ editor: {
+ model: Editors.date,
+ editorOptions: { range: { min: 'today' } } as VanillaCalendarOption
+ },
+ // formatter: Formatters.dateIso,
+ type: FieldType.date, outputType: FieldType.dateIso,
+ formatter: Formatters.dateIso,
+ filterable: true, filter: { model: Filters.dateRange },
+ grouping: {
+ getter: 'finish',
+ formatter: (g) => `Finish: ${g.value} (${g.count} items)`,
+ aggregators: [
+ new Aggregators.Sum('cost')
+ ],
+ aggregateCollapsed: false,
+ collapsed: false
+ }
+ },
+ {
+ id: 'cost', name: 'Cost', field: 'cost', columnGroup: 'Analysis',
width: 90,
sortable: true,
filterable: true,
@@ -138,7 +178,8 @@ export default class Example03 {
}
},
{
- id: 'percentComplete', name: '% Complete', field: 'percentComplete', type: FieldType.number,
+ id: 'percentComplete', name: '% Complete', field: 'percentComplete', columnGroup: 'Analysis',
+ type: FieldType.number,
editor: {
model: Editors.slider,
minValue: 0,
@@ -160,44 +201,7 @@ export default class Example03 {
params: { groupFormatterPrefix: 'Avg: ' },
},
{
- id: 'start', name: 'Start', field: 'start', sortable: true,
- // formatter: Formatters.dateIso,
- type: FieldType.date, outputType: FieldType.dateIso,
- filterable: true, filter: { model: Filters.compoundDate },
- formatter: Formatters.dateIso,
- editor: { model: Editors.date },
- grouping: {
- getter: 'start',
- formatter: (g) => `Start: ${g.value} (${g.count} items)`,
- aggregators: [
- new Aggregators.Sum('cost')
- ],
- aggregateCollapsed: false,
- collapsed: false
- }
- },
- {
- id: 'finish', name: 'Finish', field: 'finish', sortable: true,
- editor: {
- model: Editors.date,
- editorOptions: { range: { min: 'today' } } as VanillaCalendarOption
- },
- // formatter: Formatters.dateIso,
- type: FieldType.date, outputType: FieldType.dateIso,
- formatter: Formatters.dateIso,
- filterable: true, filter: { model: Filters.dateRange },
- grouping: {
- getter: 'finish',
- formatter: (g) => `Finish: ${g.value} (${g.count} items)`,
- aggregators: [
- new Aggregators.Sum('cost')
- ],
- aggregateCollapsed: false,
- collapsed: false
- }
- },
- {
- id: 'effortDriven', name: 'Effort-Driven', field: 'effortDriven',
+ id: 'effortDriven', name: 'Effort-Driven', field: 'effortDriven', columnGroup: 'Analysis',
width: 80, minWidth: 20, maxWidth: 100,
cssClass: 'cell-effort-driven',
sortable: true,
@@ -312,9 +316,18 @@ export default class Example03 {
selectActiveRow: false
},
showCustomFooter: true,
+
+ // pre-header will include our Header Grouping (i.e. "Common Factor")
+ // Draggable Grouping could be located in either the Pre-Header OR the new Top-Header
createPreHeaderPanel: true,
showPreHeaderPanel: true,
- preHeaderPanelHeight: 35,
+ preHeaderPanelHeight: 26,
+
+ // when Top-Header is created, it will be used by the Draggable Grouping (otherwise the Pre-Header will be used)
+ createTopHeaderPanel: true,
+ showTopHeaderPanel: true,
+ topHeaderPanelHeight: 35,
+
rowHeight: 33,
headerRowHeight: 35,
enableDraggableGrouping: true,
@@ -425,7 +438,7 @@ export default class Example03 {
groupByDuration() {
this.clearGrouping();
if (this.draggableGroupingPlugin?.setDroppedGroups) {
- this.showPreHeader();
+ this.showTopHeader();
this.draggableGroupingPlugin.setDroppedGroups('duration');
this.sgb?.slickGrid?.invalidate(); // invalidate all rows and re-render
}
@@ -445,14 +458,14 @@ export default class Example03 {
groupByDurationEffortDriven() {
this.clearGrouping();
if (this.draggableGroupingPlugin?.setDroppedGroups) {
- this.showPreHeader();
+ this.showTopHeader();
this.draggableGroupingPlugin.setDroppedGroups(['duration', 'effortDriven']);
this.sgb?.slickGrid?.invalidate(); // invalidate all rows and re-render
}
}
- showPreHeader() {
- this.sgb?.slickGrid?.setPreHeaderPanelVisibility(true);
+ showTopHeader() {
+ this.sgb?.slickGrid?.setTopHeaderPanelVisibility(true);
}
toggleDarkMode() {
@@ -469,7 +482,7 @@ export default class Example03 {
toggleDraggableGroupingRow() {
this.clearGroupsAndSelects();
- this.sgb?.slickGrid?.setPreHeaderPanelVisibility(!this.sgb?.slickGrid?.getOptions().showPreHeaderPanel);
+ this.sgb?.slickGrid?.setTopHeaderPanelVisibility(!this.sgb?.slickGrid?.getOptions().showTopHeaderPanel);
}
onGroupChanged(change: { caller?: string; groupColumns: Grouping[]; }) {
diff --git a/packages/common/src/core/__tests__/slickGrid.spec.ts b/packages/common/src/core/__tests__/slickGrid.spec.ts
index 7b59a9293..a10225b07 100644
--- a/packages/common/src/core/__tests__/slickGrid.spec.ts
+++ b/packages/common/src/core/__tests__/slickGrid.spec.ts
@@ -18,7 +18,6 @@ const pubSubServiceStub = {
} as BasePubSubService;
const DEFAULT_COLUMN_HEIGHT = 25;
-const DEFAULT_COLUMN_MIN_WIDTH = 30;
const DEFAULT_COLUMN_WIDTH = 80;
const DEFAULT_GRID_HEIGHT = 600;
const DEFAULT_GRID_WIDTH = 800;
@@ -454,6 +453,57 @@ describe('SlickGrid core file', () => {
});
});
+ describe('Top-Header Panel', () => {
+ it('should create a topheader panel when enabled', () => {
+ const paneHeight = 25;
+ const topHeaderPanelHeight = 30;
+ const columns = [{ id: 'firstName', field: 'firstName', name: 'First Name' }] as Column[];
+ const gridOptions = { ...defaultOptions, enableCellNavigation: true, topHeaderPanelHeight, showTopHeaderPanel: true, frozenColumn: 0, createTopHeaderPanel: true } as GridOption;
+ grid = new SlickGrid(container, [], columns, gridOptions);
+ grid.init();
+ const topheaderElm = container.querySelector('.slick-topheader-panel');
+ const topheaderElms = container.querySelectorAll('.slick-topheader-panel');
+
+ expect(grid).toBeTruthy();
+ expect(topheaderElm).toBeTruthy();
+ expect(topheaderElm?.querySelectorAll('div').length).toBe(3);
+ expect(topheaderElms[0].style.display).not.toBe('none');
+ expect(grid.getTopHeaderPanel()).toBeTruthy();
+ expect(grid.getTopHeaderPanel()).toEqual(grid.getTopHeaderPanel());
+
+ const paneHeaderLeftElms = container.querySelectorAll('.slick-pane-header');
+ jest.spyOn(paneHeaderLeftElms[0], 'getBoundingClientRect').mockReturnValue({ left: 25, top: 10, right: 0, bottom: 0, height: paneHeight } as DOMRect);
+ jest.spyOn(paneHeaderLeftElms[1], 'getBoundingClientRect').mockReturnValue({ left: 25, top: 10, right: 0, bottom: 0, height: paneHeight } as DOMRect);
+
+ // calling resize should add top offset of pane + topHeader
+ grid.resizeCanvas();
+
+ const paneTopLeftElm = container.querySelector('.slick-pane-top.slick-pane-left') as HTMLDivElement;
+
+ expect(paneTopLeftElm.style.top).toBe(`${paneHeight + topHeaderPanelHeight}px`);
+ });
+
+ it('should hide column headers div when "showTopHeaderPanel" is disabled', () => {
+ const columns = [{ id: 'firstName', field: 'firstName', name: 'First Name' }] as Column[];
+ const gridOptions = { ...defaultOptions, enableCellNavigation: true, topHeaderPanelHeight: 30, showTopHeaderPanel: false, createTopHeaderPanel: true } as GridOption;
+ grid = new SlickGrid(container, [], columns, gridOptions);
+ grid.init();
+ let topheaderElms = container.querySelectorAll('.slick-topheader-panel');
+
+ expect(grid).toBeTruthy();
+ expect(topheaderElms).toBeTruthy();
+ expect(topheaderElms[0].style.display).toBe('none');
+
+ grid.setTopHeaderPanelVisibility(true);
+ topheaderElms = container.querySelectorAll('.slick-topheader-panel');
+ expect(topheaderElms[0].style.display).not.toBe('none');
+
+ grid.setTopHeaderPanelVisibility(false);
+ topheaderElms = container.querySelectorAll('.slick-topheader-panel');
+ expect(topheaderElms[0].style.display).toBe('none');
+ });
+ });
+
describe('Headers', () => {
it('should show column headers div by default', () => {
const columns = [{ id: 'firstName', field: 'firstName', name: 'First Name' }] as Column[];
@@ -3304,6 +3354,39 @@ describe('SlickGrid core file', () => {
expect(viewportElm.scrollLeft).toBe(0);
});
+ it('should scroll all elements shown when triggered by mousewheel and topHeader is enabled', () => {
+ const dv = new SlickDataView();
+ dv.setItems(data);
+ grid = new SlickGrid(container, dv, columns, {
+ ...defaultOptions, enableMouseWheelScrollHandler: true,
+ createTopHeaderPanel: true,
+ });
+ grid.setOptions({ enableMouseWheelScrollHandler: false });
+ grid.setOptions({ enableMouseWheelScrollHandler: true });
+ grid.scrollCellIntoView(1, 2, true);
+
+ const mouseEvent = new Event('mousewheel');
+ const mousePreventSpy = jest.spyOn(mouseEvent, 'preventDefault');
+ const onViewportChangedSpy = jest.spyOn(grid.onViewportChanged, 'notify');
+ let viewportTopLeftElm = container.querySelector('.slick-viewport-top.slick-viewport-left') as HTMLDivElement;
+ Object.defineProperty(viewportTopLeftElm, 'scrollHeight', { writable: true, value: DEFAULT_GRID_HEIGHT });
+ Object.defineProperty(viewportTopLeftElm, 'scrollWidth', { writable: true, value: DEFAULT_GRID_WIDTH });
+ Object.defineProperty(viewportTopLeftElm, 'clientHeight', { writable: true, value: 125 });
+ Object.defineProperty(viewportTopLeftElm, 'clientWidth', { writable: true, value: 75 });
+
+ let viewportLeftElm = container.querySelector('.slick-viewport-top.slick-viewport-left') as HTMLDivElement;
+ let topHeaderElm = container.querySelector('.slick-topheader-panel') as HTMLDivElement;
+ Object.defineProperty(viewportLeftElm, 'scrollLeft', { writable: true, value: 88 });
+ viewportLeftElm.dispatchEvent(mouseEvent);
+
+ expect(topHeaderElm.scrollLeft).toBe(88);
+ expect(viewportLeftElm.scrollLeft).toBe(88);
+ expect(viewportLeftElm.scrollTop).toBe(25);
+ expect(viewportTopLeftElm.scrollTop).toBe(25);
+ expect(onViewportChangedSpy).toHaveBeenCalled();
+ expect(mousePreventSpy).toHaveBeenCalled();
+ });
+
it('should scroll all elements shown when triggered by mousewheel and preHeader/footer are enabled and without any Frozen rows/columns', () => {
const dv = new SlickDataView();
dv.setItems(data);
@@ -5216,7 +5299,6 @@ describe('SlickGrid core file', () => {
const columns = [{ id: 'name', field: 'name', name: 'Name' }, { id: 'age', field: 'age', name: 'Age' }] as Column[];
grid = new SlickGrid(container, items, columns, { ...defaultOptions, createPreHeaderPanel: true, preHeaderPanelHeight: 44, showPreHeaderPanel: true, enableCellNavigation: true });
const preheaderElm = container.querySelector('.slick-preheader-panel') as HTMLDivElement;
- const preheaderElms = container.querySelectorAll('.slick-preheader-panel');
Object.defineProperty(preheaderElm, 'scrollLeft', { writable: true, value: 25 });
preheaderElm.dispatchEvent(new CustomEvent('scroll'));
@@ -5230,6 +5312,23 @@ describe('SlickGrid core file', () => {
viewportTopLeft.dispatchEvent(selectStartEvent);
});
+ it('should update viewport top/left scrollLeft when scrolling in topHeader DOM element', () => {
+ const columns = [{ id: 'name', field: 'name', name: 'Name' }, { id: 'age', field: 'age', name: 'Age' }] as Column[];
+ grid = new SlickGrid(container, items, columns, { ...defaultOptions, createTopHeaderPanel: true, topHeaderPanelHeight: 44, showTopHeaderPanel: true, enableCellNavigation: true });
+ const topheaderElm = container.querySelector('.slick-topheader-panel') as HTMLDivElement;
+ Object.defineProperty(topheaderElm, 'scrollLeft', { writable: true, value: 25 });
+
+ topheaderElm.dispatchEvent(new CustomEvent('scroll'));
+
+ const viewportTopLeft = container.querySelector('.slick-viewport-top.slick-viewport-left') as HTMLDivElement;
+ expect(viewportTopLeft.scrollLeft).toBe(25);
+
+ // when enableTextSelectionOnCells isn't enabled and trigger IE related code
+ const selectStartEvent = new CustomEvent('selectstart');
+ Object.defineProperty(selectStartEvent, 'target', { writable: true, value: document.createElement('TextArea') });
+ viewportTopLeft.dispatchEvent(selectStartEvent);
+ });
+
it('should NOT trigger onHeaderRowMouseEnter notify when hovering a header when "slick-headerrow-column" class is not found', () => {
const columns = [{ id: 'name', field: 'name', name: 'Name' }, { id: 'age', field: 'age', name: 'Age' }] as Column[];
grid = new SlickGrid(container, items, columns, { ...defaultOptions, showHeaderRow: true, enableCellNavigation: true });
diff --git a/packages/common/src/core/slickGrid.ts b/packages/common/src/core/slickGrid.ts
index 08f387c3c..6f44d47ac 100644
--- a/packages/common/src/core/slickGrid.ts
+++ b/packages/common/src/core/slickGrid.ts
@@ -229,9 +229,13 @@ export class SlickGrid = Column, O e
showFooterRow: false,
footerRowHeight: 25,
createPreHeaderPanel: false,
+ createTopHeaderPanel: false,
showPreHeaderPanel: false,
+ showTopHeaderPanel: false,
preHeaderPanelHeight: 25,
preHeaderPanelWidth: 'auto', // mostly useful for Draggable Grouping dropzone to take full width
+ topHeaderPanelHeight: 25,
+ topHeaderPanelWidth: 'auto', // mostly useful for Draggable Grouping dropzone to take full width
showTopPanel: false,
topPanelHeight: 25,
formatterFactory: null,
@@ -327,6 +331,9 @@ export class SlickGrid = Column, O e
protected _preHeaderPanelR!: HTMLDivElement;
protected _preHeaderPanelScrollerR!: HTMLDivElement;
protected _preHeaderPanelSpacerR!: HTMLDivElement;
+ protected _topHeaderPanel!: HTMLDivElement;
+ protected _topHeaderPanelScroller!: HTMLDivElement;
+ protected _topHeaderPanelSpacer!: HTMLDivElement;
protected _topPanelScrollers!: HTMLDivElement[];
protected _topPanels!: HTMLDivElement[];
protected _viewport!: HTMLDivElement[];
@@ -650,6 +657,17 @@ export class SlickGrid = Column, O e
this._focusSink = createDomElement('div', { tabIndex: 0, style: { position: 'fixed', width: '0px', height: '0px', top: '0px', left: '0px', outline: '0px' } }, this._container);
+ if (this._options.createTopHeaderPanel) {
+ this._topHeaderPanelScroller = createDomElement('div', { className: 'slick-topheader-panel slick-state-default', style: { overflow: 'hidden', position: 'relative' } }, this._container);
+ this._topHeaderPanelScroller.appendChild(document.createElement('div'));
+ this._topHeaderPanel = createDomElement('div', null, this._topHeaderPanelScroller);
+ this._topHeaderPanelSpacer = createDomElement('div', { style: { display: 'block', height: '1px', position: 'absolute', top: '0px', left: '0px' } }, this._topHeaderPanelScroller);
+
+ if (!this._options.showTopHeaderPanel) {
+ Utils.hide(this._topHeaderPanelScroller);
+ }
+ }
+
// Containers used for scrolling frozen columns and rows
this._paneHeaderL = createDomElement('div', { className: 'slick-pane slick-pane-header slick-pane-left', tabIndex: 0 }, this._container);
this._paneHeaderR = createDomElement('div', { className: 'slick-pane slick-pane-header slick-pane-right', tabIndex: 0 }, this._container);
@@ -763,6 +781,11 @@ export class SlickGrid = Column, O e
// Default the active canvas to the top left
this._activeCanvasNode = this._canvasTopL;
+ // top-header
+ if (this._topHeaderPanelSpacer) {
+ Utils.width(this._topHeaderPanelSpacer, this.getCanvasWidth() + this.scrollbarDimensions.width);
+ }
+
// pre-header
if (this._preHeaderPanelSpacer) {
Utils.width(this._preHeaderPanelSpacer, this.getCanvasWidth() + this.scrollbarDimensions.width);
@@ -884,6 +907,10 @@ export class SlickGrid = Column, O e
});
}
+ if (this._options.createTopHeaderPanel) {
+ this._bindingEventService.bind(this._topHeaderPanelScroller, 'scroll', this.handleTopHeaderPanelScroll.bind(this) as EventListener);
+ }
+
if (this._options.createPreHeaderPanel) {
this._bindingEventService.bind(this._preHeaderPanelScroller, 'scroll', this.handlePreHeaderPanelScroll.bind(this) as EventListener);
}
@@ -1163,6 +1190,10 @@ export class SlickGrid = Column, O e
const oldCanvasWidthR = this.canvasWidthR;
this.canvasWidth = this.getCanvasWidth();
+ if (this._options.createTopHeaderPanel) {
+ Utils.width(this._topHeaderPanel, this._options.topHeaderPanelWidth ?? this.canvasWidth);
+ }
+
const widthChanged = this.canvasWidth !== oldCanvasWidth || this.canvasWidthL !== oldCanvasWidthL || this.canvasWidthR !== oldCanvasWidthR;
if (widthChanged || this.hasFrozenColumns() || this.hasFrozenRows) {
@@ -1433,6 +1464,11 @@ export class SlickGrid = Column, O e
return this._preHeaderPanelR;
}
+ /** Get the Top-Header Panel DOM node element */
+ getTopHeaderPanel() {
+ return this._topHeaderPanel;
+ }
+
/**
* Get Header Row Column DOM element by its column Id or index
* @param {Number|String} columnIdOrIdx - column Id or index
@@ -2353,6 +2389,7 @@ export class SlickGrid = Column, O e
`.${this.uid} .slick-header-column { left: 1000px; }`,
`.${this.uid} .slick-top-panel { height: ${this._options.topPanelHeight}px; }`,
`.${this.uid} .slick-preheader-panel { height: ${this._options.preHeaderPanelHeight}px; }`,
+ `.${this.uid} .slick-topheader-panel { height: ${this._options.topHeaderPanelHeight}px; }`,
`.${this.uid} .slick-headerrow-columns { height: ${this._options.headerRowHeight}px; }`,
`.${this.uid} .slick-footerrow-columns { height: ${this._options.footerRowHeight}px; }`,
`.${this.uid} .slick-cell { height: ${rowHeight}px; }`,
@@ -2529,6 +2566,10 @@ export class SlickGrid = Column, O e
this._bindingEventService.unbindByEventName(this._preHeaderPanelScroller, 'scroll');
}
+ if (this._topHeaderPanelScroller) {
+ this._bindingEventService.unbindByEventName(this._topHeaderPanelScroller, 'scroll');
+ }
+
this._bindingEventService.unbindByEventName(this._focusSink, 'keydown');
this._bindingEventService.unbindByEventName(this._focusSink2, 'keydown');
@@ -3130,7 +3171,7 @@ export class SlickGrid = Column, O e
return !Array.isArray(this.data);
}
- protected togglePanelVisibility(option: 'showTopPanel' | 'showHeaderRow' | 'showColumnHeader' | 'showFooterRow' | 'showPreHeaderPanel', container: HTMLElement | HTMLElement[], visible?: boolean) {
+ protected togglePanelVisibility(option: 'showTopPanel' | 'showHeaderRow' | 'showColumnHeader' | 'showFooterRow' | 'showPreHeaderPanel' | 'showTopHeaderPanel', container: HTMLElement | HTMLElement[], visible?: boolean) {
if (this._options[option] !== visible) {
this._options[option] = visible as boolean;
if (visible) {
@@ -3182,6 +3223,14 @@ export class SlickGrid = Column, O e
this.togglePanelVisibility('showPreHeaderPanel', [this._preHeaderPanelScroller, this._preHeaderPanelScrollerR], visible);
}
+ /**
+ * Set the Top-Header Visibility
+ * @param {Boolean} [visible] - optionally set if top-header panel is visible or not
+ */
+ setTopHeaderPanelVisibility(visible?: boolean) {
+ this.togglePanelVisibility('showTopHeaderPanel', this._topHeaderPanelScroller, visible);
+ }
+
/** Get Grid Canvas Node DOM Element */
getContainerNode() {
return this._container;
@@ -3683,6 +3732,7 @@ export class SlickGrid = Column, O e
} else {
const columnNamesH = (this._options.showColumnHeader) ? Utils.toFloat(Utils.height(this._headerScroller[0]) as number) + this.getVBoxDelta(this._headerScroller[0]) : 0;
const preHeaderH = (this._options.createPreHeaderPanel && this._options.showPreHeaderPanel) ? this._options.preHeaderPanelHeight! + this.getVBoxDelta(this._preHeaderPanelScroller) : 0;
+ const topHeaderH = (this._options.createTopHeaderPanel && this._options.showTopHeaderPanel) ? this._options.topHeaderPanelHeight! + this.getVBoxDelta(this._topHeaderPanelScroller) : 0;
const style = getComputedStyle(this._container);
this.viewportH = Utils.toFloat(style.height)
@@ -3692,7 +3742,8 @@ export class SlickGrid = Column, O e
- this.topPanelH
- this.headerRowH
- this.footerRowH
- - preHeaderH;
+ - preHeaderH
+ - topHeaderH;
}
this.numVisibleRows = Math.ceil(this.viewportH / this._options.rowHeight!);
@@ -3747,7 +3798,13 @@ export class SlickGrid = Column, O e
this._paneTopL.style.position = 'relative';
}
- Utils.setStyleSize(this._paneTopL, 'top', Utils.height(this._paneHeaderL) || (this._options.showHeaderRow ? this._options.headerRowHeight! : 0) + (this._options.showPreHeaderPanel ? this._options.preHeaderPanelHeight! : 0));
+ let topHeightOffset = Utils.height(this._paneHeaderL);
+ if (topHeightOffset) {
+ topHeightOffset += (this._options.showTopHeaderPanel ? this._options.topHeaderPanelHeight! : 0);
+ } else {
+ topHeightOffset = (this._options.showHeaderRow ? this._options.headerRowHeight! : 0) + (this._options.showPreHeaderPanel ? this._options.preHeaderPanelHeight! : 0);
+ }
+ Utils.setStyleSize(this._paneTopL, 'top', topHeightOffset || topHeightOffset);
Utils.height(this._paneTopL, this.paneTopH);
const paneBottomTop = this._paneTopL.offsetTop + this.paneTopH;
@@ -3757,7 +3814,11 @@ export class SlickGrid = Column, O e
}
if (this.hasFrozenColumns()) {
- Utils.setStyleSize(this._paneTopR, 'top', Utils.height(this._paneHeaderL) as number);
+ let topHeightOffset = Utils.height(this._paneHeaderL);
+ if (topHeightOffset) {
+ topHeightOffset += (this._options.showTopHeaderPanel ? this._options.topHeaderPanelHeight! : 0);
+ }
+ Utils.setStyleSize(this._paneTopR, 'top', topHeightOffset as number);
Utils.height(this._paneTopR, this.paneTopH);
Utils.height(this._viewportTopR, this.viewportTopH);
@@ -4330,6 +4391,10 @@ export class SlickGrid = Column, O e
this.handleElementScroll(this._preHeaderPanelScroller);
}
+ protected handleTopHeaderPanelScroll() {
+ this.handleElementScroll(this._topHeaderPanelScroller);
+ }
+
protected handleElementScroll(element: HTMLElement) {
const scrollLeft = element.scrollLeft;
if (scrollLeft !== this._viewportScrollContainerX.scrollLeft) {
@@ -4380,6 +4445,9 @@ export class SlickGrid = Column, O e
this._preHeaderPanelScroller.scrollLeft = this.scrollLeft;
}
}
+ if (this._options.createTopHeaderPanel) {
+ this._topHeaderPanelScroller.scrollLeft = this.scrollLeft;
+ }
if (this.hasFrozenColumns()) {
if (this.hasFrozenRows) {
diff --git a/packages/common/src/extensions/__tests__/slickDraggableGrouping.spec.ts b/packages/common/src/extensions/__tests__/slickDraggableGrouping.spec.ts
index e1b30c2ca..15a347e2a 100644
--- a/packages/common/src/extensions/__tests__/slickDraggableGrouping.spec.ts
+++ b/packages/common/src/extensions/__tests__/slickDraggableGrouping.spec.ts
@@ -79,6 +79,7 @@ const gridStub = {
getHeaderColumn: jest.fn(),
getOptions: jest.fn(),
getPreHeaderPanel: jest.fn(),
+ getTopHeaderPanel: jest.fn(),
getData: () => dataViewStub,
getEditorLock: () => getEditorLockMock,
getUID: () => GRID_UID,
diff --git a/packages/common/src/extensions/slickDraggableGrouping.ts b/packages/common/src/extensions/slickDraggableGrouping.ts
index 68753d155..a00408dd7 100644
--- a/packages/common/src/extensions/slickDraggableGrouping.ts
+++ b/packages/common/src/extensions/slickDraggableGrouping.ts
@@ -25,7 +25,7 @@ import { type SlickDataView, SlickEvent, SlickEventData, SlickEventHandler, type
* github.com/muthukumarse/Slickgrid
*
* NOTES:
- * This plugin provides the Draggable Grouping feature
+ * This plugin provides the Draggable Grouping feature which could be located in either the Top-Header or the Pre-Header
*
* A plugin to add drop-down menus to column headers.
* To specify a custom button in a column header, extend the column definition like so:
@@ -131,7 +131,7 @@ export class SlickDraggableGrouping {
if (grid) {
this._gridUid = grid.getUID();
this._gridColumns = grid.getColumns();
- this._dropzoneElm = grid.getPreHeaderPanel();
+ this._dropzoneElm = grid.getTopHeaderPanel() || grid.getPreHeaderPanel();
this._dropzoneElm.classList.add('slick-dropzone');
// add PubSub instance to all SlickEvent
@@ -216,7 +216,7 @@ export class SlickDraggableGrouping {
this._eventHandler.unsubscribeAll();
this.pubSubService.unsubscribeAll(this._subscriptions);
this._bindingEventService.unbindAll();
- emptyElement(this.gridContainer.querySelector(`.${this.gridUid} .slick-preheader-panel`));
+ emptyElement(this.gridContainer.querySelector(`.${this.gridUid} .slick-preheader-panel,.${this.gridUid} .slick-topheader-panel`));
}
clearDroppedGroups() {
@@ -277,7 +277,7 @@ export class SlickDraggableGrouping {
*/
setupColumnReorder(grid: SlickGrid, headers: any, _headerColumnWidthDiff: any, setColumns: (columns: Column[]) => void, setupColumnResize: () => void, _columns: Column[], getColumnIndex: (columnId: string) => number, _uid: string, trigger: (slickEvent: SlickEvent, data?: any) => void) {
this.destroySortableInstances();
- const dropzoneElm = grid.getPreHeaderPanel();
+ const dropzoneElm = grid.getTopHeaderPanel() || grid.getPreHeaderPanel();
const draggablePlaceholderElm = dropzoneElm.querySelector('.slick-draggable-dropzone-placeholder');
const groupTogglerElm = dropzoneElm.querySelector('.slick-group-toggle-all');
diff --git a/packages/common/src/interfaces/gridOption.interface.ts b/packages/common/src/interfaces/gridOption.interface.ts
index 18aa90ca5..ac428eab2 100644
--- a/packages/common/src/interfaces/gridOption.interface.ts
+++ b/packages/common/src/interfaces/gridOption.interface.ts
@@ -208,12 +208,15 @@ export interface GridOption {
/** Context menu options (mouse right+click) */
contextMenu?: ContextMenu;
- /** Defaults to false, which leads to create the footer row of the grid */
+ /** Defaults to false, which leads to creating the footer row of the grid */
createFooterRow?: boolean;
- /** Default to false, which leads to create an extra pre-header panel (on top of column header) for column grouping purposes */
+ /** Default to false, which leads to creating an extra pre-header panel (on top of column header) for column grouping purposes */
createPreHeaderPanel?: boolean;
+ /** Default to false, which leads to creating an extra top-header panel (on top of column header & pre-header) for column grouping purposes */
+ createTopHeaderPanel?: boolean;
+
/** Custom Footer Options */
customFooterOptions?: CustomFooterOption;
@@ -659,6 +662,12 @@ export interface GridOption {
/** Defaults to "auto", extra pre-header panel (on top of column header) width, it could be a number (pixels) or a string ("100%" or "auto") */
preHeaderPanelWidth?: number | string;
+ /** Extra top-header panel height (on top of column header & pre-header) */
+ topHeaderPanelHeight?: number;
+
+ /** Defaults to "auto", extra top-header panel (on top of column header & pre-header) width, it could be a number (pixels) or a string ("100%" or "auto") */
+ topHeaderPanelWidth?: number | string;
+
/** Do we want to preserve copied selection on paste? */
preserveCopiedSelectionOnPaste?: boolean;
@@ -756,6 +765,9 @@ export interface GridOption {
/** Do we want to show the extra pre-header panel (on top of column header) for column grouping purposes */
showPreHeaderPanel?: boolean;
+ /** Do we want to show the extra top-header panel (on top of column header & pre-header) for column grouping purposes */
+ showTopHeaderPanel?: boolean;
+
/** Do we want to show top panel row? */
showTopPanel?: boolean;
diff --git a/packages/common/src/services/groupingAndColspan.service.ts b/packages/common/src/services/groupingAndColspan.service.ts
index 37bcdf50d..0cd9c277b 100644
--- a/packages/common/src/services/groupingAndColspan.service.ts
+++ b/packages/common/src/services/groupingAndColspan.service.ts
@@ -100,18 +100,19 @@ export class GroupingAndColspanService {
/** Create or Render the Pre-Header Row Grouping Titles */
renderPreHeaderRowGroupingTitles() {
- if (this._gridOptions && this._gridOptions.frozenColumn !== undefined && this._gridOptions.frozenColumn >= 0) {
+ const colsCount = this._columnDefinitions.length;
+
+ if (this._gridOptions?.frozenColumn !== undefined && this._gridOptions.frozenColumn >= 0) {
+ const frozenCol = this._gridOptions.frozenColumn;
+
// Add column groups to left panel
- let preHeaderPanelElm = this._grid.getPreHeaderPanelLeft();
- this.renderHeaderGroups(preHeaderPanelElm, 0, this._gridOptions.frozenColumn + 1);
+ this.renderHeaderGroups(this._grid.getPreHeaderPanelLeft(), 0, frozenCol + 1);
// Add column groups to right panel
- preHeaderPanelElm = this._grid.getPreHeaderPanelRight();
- this.renderHeaderGroups(preHeaderPanelElm, this._gridOptions?.frozenColumn + 1, this._columnDefinitions.length);
+ this.renderHeaderGroups(this._grid.getPreHeaderPanelRight(), frozenCol + 1, colsCount);
} else {
// regular grid (not a frozen grid)
- const preHeaderPanelElm = this._grid.getPreHeaderPanel();
- this.renderHeaderGroups(preHeaderPanelElm, 0, this._columnDefinitions.length);
+ this.renderHeaderGroups(this._grid.getPreHeaderPanel(), 0, colsCount);
}
}
diff --git a/packages/common/src/styles/slick-grid.scss b/packages/common/src/styles/slick-grid.scss
index 13fc63c2e..35f5d5f9c 100644
--- a/packages/common/src/styles/slick-grid.scss
+++ b/packages/common/src/styles/slick-grid.scss
@@ -697,7 +697,8 @@
}
/** Header Grouping **/
- .slick-preheader-panel.slick-state-default {
+ .slick-preheader-panel.slick-state-default,
+ .slick-topheader-panel.slick-state-default {
border-bottom: var(--slick-preheader-border-bottom, $slick-preheader-border-bottom);
.slick-header-columns {
@@ -730,7 +731,8 @@
border-right: var(--slick-frozen-header-row-border-right, $slick-frozen-header-row-border-right);
}
.slick-pane-left {
- .slick-preheader-panel .slick-header-column.frozen:last-child {
+ .slick-preheader-panel .slick-header-column.frozen:last-child,
+ .slick-topheader-panel .slick-header-column.frozen:last-child {
border-right: var(--slick-frozen-preheader-row-border-right, $slick-frozen-preheader-row-border-right);
}
}
diff --git a/packages/common/src/styles/slick-plugins.scss b/packages/common/src/styles/slick-plugins.scss
index 37ecaf66e..57d7bf6f3 100644
--- a/packages/common/src/styles/slick-plugins.scss
+++ b/packages/common/src/styles/slick-plugins.scss
@@ -893,7 +893,8 @@ input.search-filter {
// Draggable Grouping Plugin
// ----------------------------------------------
-.slick-preheader-panel {
+.slick-preheader-panel,
+.slick-topheader-panel {
.slick-dropzone, .slick-dropzone-hover {
display: flex;
align-items: center;
diff --git a/packages/vanilla-bundle/src/components/__tests__/slick-vanilla-grid.spec.ts b/packages/vanilla-bundle/src/components/__tests__/slick-vanilla-grid.spec.ts
index 0b551a5b1..e520e17c0 100644
--- a/packages/vanilla-bundle/src/components/__tests__/slick-vanilla-grid.spec.ts
+++ b/packages/vanilla-bundle/src/components/__tests__/slick-vanilla-grid.spec.ts
@@ -1006,15 +1006,6 @@ describe('Slick-Vanilla-Grid-Bundle Component instantiated via Constructor', ()
expect(spy).toHaveBeenCalledWith(mockGrid, container);
});
- it('should not initialize groupingAndColspanService when "createPreHeaderPanel" grid option is enabled and "enableDraggableGrouping" is also enabled', () => {
- const spy = jest.spyOn(groupingAndColspanServiceStub, 'init');
-
- component.gridOptions = { createPreHeaderPanel: true, enableDraggableGrouping: true } as unknown as GridOption;
- component.initialization(divContainer, slickEventHandler);
-
- expect(spy).not.toHaveBeenCalled();
- });
-
it('should call "translateColumnHeaders" from ExtensionService when "enableTranslate" is set', () => {
const spy = jest.spyOn(extensionServiceStub, 'translateColumnHeaders');
diff --git a/packages/vanilla-bundle/src/components/slick-vanilla-grid-bundle.ts b/packages/vanilla-bundle/src/components/slick-vanilla-grid-bundle.ts
index 3cf8e80ee..7a3af613c 100644
--- a/packages/vanilla-bundle/src/components/slick-vanilla-grid-bundle.ts
+++ b/packages/vanilla-bundle/src/components/slick-vanilla-grid-bundle.ts
@@ -761,7 +761,7 @@ export class SlickVanillaGridBundle {
this._eventPubSubService.subscribe('onLanguageChange', (args: { language: string; }) => {
if (gridOptions.enableTranslate) {
this.extensionService.translateAllExtensions(args.language);
- if (gridOptions.createPreHeaderPanel && !gridOptions.enableDraggableGrouping) {
+ if ((gridOptions.createPreHeaderPanel && gridOptions.createTopHeaderPanel) || (gridOptions.createPreHeaderPanel && !gridOptions.enableDraggableGrouping)) {
this.groupingService.translateGroupingAndColSpan();
}
}
@@ -1378,7 +1378,7 @@ export class SlickVanillaGridBundle {
this._registeredResources.push(this.gridService, this.gridStateService);
// when using Grouping/DraggableGrouping/Colspan register its Service
- if (this.gridOptions.createPreHeaderPanel && !this.gridOptions.enableDraggableGrouping) {
+ if ((this.gridOptions.createPreHeaderPanel && this.gridOptions.createTopHeaderPanel) || (this.gridOptions.createPreHeaderPanel && !this.gridOptions.enableDraggableGrouping)) {
this._registeredResources.push(this.groupingService);
}
diff --git a/packages/vanilla-force-bundle/src/__tests__/vanilla-force-bundle.spec.ts b/packages/vanilla-force-bundle/src/__tests__/vanilla-force-bundle.spec.ts
index 5bca1f2d6..e815aa561 100644
--- a/packages/vanilla-force-bundle/src/__tests__/vanilla-force-bundle.spec.ts
+++ b/packages/vanilla-force-bundle/src/__tests__/vanilla-force-bundle.spec.ts
@@ -469,15 +469,6 @@ describe('Vanilla-Force-Grid-Bundle Component instantiated via Constructor', ()
expect(spy).toHaveBeenCalledWith(mockGrid, container);
});
- it('should not initialize groupingAndColspanService when "createPreHeaderPanel" grid option is enabled and "enableDraggableGrouping" is also enabled', () => {
- const spy = jest.spyOn(groupingAndColspanServiceStub, 'init');
-
- component.gridOptions = { createPreHeaderPanel: true, enableDraggableGrouping: true } as unknown as GridOption;
- component.initialization(divContainer, slickEventHandler);
-
- expect(spy).not.toHaveBeenCalled();
- });
-
it('should call "translateColumnHeaders" from ExtensionService when "enableTranslate" is set', () => {
const spy = jest.spyOn(extensionServiceStub, 'translateColumnHeaders');
diff --git a/packages/vanilla-force-bundle/src/vanilla-force-bundle.ts b/packages/vanilla-force-bundle/src/vanilla-force-bundle.ts
index 39b425773..7ff179e08 100644
--- a/packages/vanilla-force-bundle/src/vanilla-force-bundle.ts
+++ b/packages/vanilla-force-bundle/src/vanilla-force-bundle.ts
@@ -126,7 +126,7 @@ export class VanillaForceGridBundle extends SlickVanillaGridBundle {
this._registeredResources.push(this.gridService, this.gridStateService);
// when using Grouping/DraggableGrouping/Colspan register its Service
- if (this.gridOptions.createPreHeaderPanel && !this.gridOptions.enableDraggableGrouping) {
+ if ((this.gridOptions.createPreHeaderPanel && this.gridOptions.createTopHeaderPanel) || (this.gridOptions.createPreHeaderPanel && !this.gridOptions.enableDraggableGrouping)) {
this._registeredResources.push(this.groupingService);
}
diff --git a/test/cypress/e2e/example02.cy.ts b/test/cypress/e2e/example02.cy.ts
index 0009efa56..a0d3b29fa 100644
--- a/test/cypress/e2e/example02.cy.ts
+++ b/test/cypress/e2e/example02.cy.ts
@@ -201,7 +201,6 @@ describe('Example 02 - Grouping & Aggregators', () => {
cy.get('.item-count')
.should('contain', 5000);
-
cy.get('.search-filter.filter-title')
.clear()
.type('Ta*33');
diff --git a/test/cypress/e2e/example03.cy.ts b/test/cypress/e2e/example03.cy.ts
index 7a0cdddb1..8f3c7f87f 100644
--- a/test/cypress/e2e/example03.cy.ts
+++ b/test/cypress/e2e/example03.cy.ts
@@ -1,5 +1,6 @@
describe('Example 03 - Draggable Grouping', () => {
- const fullTitles = ['', 'Title', 'Duration', 'Cost', '% Complete', 'Start', 'Finish', 'Effort-Driven', 'Action'];
+ const preHeaders = ['', 'Common Factor', 'Period', 'Analysis', ''];
+ const fullTitles = ['', 'Title', 'Duration', 'Start', 'Finish', 'Cost', '% Complete', 'Effort-Driven', 'Action'];
const GRID_ROW_HEIGHT = 33;
it('should display Example title', () => {
@@ -8,13 +9,26 @@ describe('Example 03 - Draggable Grouping', () => {
cy.get('h3 span.subtitle').should('contain', '(with Salesforce Theme)');
});
- it('should have exact column titles on 1st grid', () => {
+ it('should have exact column (pre-header) grouping titles in grid', () => {
cy.get('.grid3')
- .find('.slick-header-columns')
+ .find('.slick-preheader-panel .slick-header-columns')
+ .children()
+ .each(($child, index) => expect($child.text()).to.eq(preHeaders[index]));
+ });
+
+ it('should have exact column titles in grid', () => {
+ cy.get('.grid3')
+ .find('.slick-header:not(.slick-preheader-panel) .slick-header-columns')
.children()
.each(($child, index) => expect($child.text()).to.eq(fullTitles[index]));
});
+ it('should have a draggable dropzone on top of the grid in the top-header section', () => {
+ cy.get('.grid3')
+ .find('.slick-topheader-panel .slick-dropzone:visible')
+ .contains('Drop a column header here to group by the column');
+ });
+
it('should open the Cell Menu on 2nd and 3rd row and change the Effort-Driven to "True" and expect the cell to be updated and have checkmark to be enabled', () => {
cy.get(`[style="top: ${GRID_ROW_HEIGHT * 1}px;"] > .slick-cell:nth(1)`).should('contain', 'Task 1');
cy.get(`[style="top: ${GRID_ROW_HEIGHT * 1}px;"] > .slick-cell:nth(8)`).find('.checkmark-icon').should('have.length', 0);
@@ -51,7 +65,7 @@ describe('Example 03 - Draggable Grouping', () => {
});
it('should collapse all rows and make sure Duration group is sorted in descending order', () => {
- cy.get('.slick-preheader-panel .slick-group-toggle-all').click();
+ cy.get('.slick-topheader-panel .slick-group-toggle-all').click();
cy.get(`[style="top: ${GRID_ROW_HEIGHT * 0}px;"] > .slick-cell:nth(0) .slick-group-toggle.collapsed`).should('have.length', 1);
cy.get(`[style="top: ${GRID_ROW_HEIGHT * 0}px;"] > .slick-cell:nth(0) .slick-group-title`).should('contain', 'Duration: 100');
cy.get(`[style="top: ${GRID_ROW_HEIGHT * 1}px;"] > .slick-cell:nth(0) .slick-group-title`).should('contain', 'Duration: 99');
@@ -64,7 +78,7 @@ describe('Example 03 - Draggable Grouping', () => {
});
it('should collapse all rows again and make sure Duration group is sorted in descending order', () => {
- cy.get('.slick-preheader-panel .slick-group-toggle-all').click();
+ cy.get('.slick-topheader-panel .slick-group-toggle-all').click();
cy.get(`[style="top: ${GRID_ROW_HEIGHT * 0}px;"] > .slick-cell:nth(0) .slick-group-toggle.collapsed`).should('have.length', 1);
cy.get(`[style="top: ${GRID_ROW_HEIGHT * 0}px;"] > .slick-cell:nth(0) .slick-group-title`).should('contain', 'Duration: 0');
cy.get(`[style="top: ${GRID_ROW_HEIGHT * 1}px;"] > .slick-cell:nth(0) .slick-group-title`).should('contain', 'Duration: 1');
@@ -125,8 +139,8 @@ describe('Example 03 - Draggable Grouping', () => {
cy.get(`[style="top: ${GRID_ROW_HEIGHT * 2}px;"] > .slick-cell:nth(2)`).should('contain', '0');
});
- it('should use the preheader Toggle All button and expect all groups to now be collapsed', () => {
- cy.get('.slick-preheader-panel .slick-group-toggle-all').click();
+ it('should use the topheader Toggle All button and expect all groups to now be collapsed', () => {
+ cy.get('.slick-topheader-panel .slick-group-toggle-all').click();
cy.get(`[style="top: ${GRID_ROW_HEIGHT * 0}px;"] > .slick-cell:nth(0) .slick-group-toggle.collapsed`).should('have.length', 1);
cy.get(`[style="top: ${GRID_ROW_HEIGHT * 0}px;"] > .slick-cell:nth(0) .slick-group-title`).should('contain', 'Effort-Driven: False');
@@ -179,8 +193,8 @@ describe('Example 03 - Draggable Grouping', () => {
.should('exist');
});
- it('should use the preheader Toggle All button and expect all groups to now be expanded', () => {
- cy.get('.slick-preheader-panel .slick-group-toggle-all').click();
+ it('should use the topheader Toggle All button and expect all groups to now be expanded', () => {
+ cy.get('.slick-topheader-panel .slick-group-toggle-all').click();
cy.get(`[style="top: ${GRID_ROW_HEIGHT * 0}px;"] > .slick-cell:nth(0) .slick-group-toggle.expanded`).should('have.length', 1);
cy.get(`[style="top: ${GRID_ROW_HEIGHT * 0}px;"] > .slick-cell:nth(0) .slick-group-title`).should('contain', 'Effort-Driven: False');
@@ -191,8 +205,8 @@ describe('Example 03 - Draggable Grouping', () => {
.should('have.css', 'marginLeft').and('eq', `15px`);
});
- it('should use the preheader Toggle All button again and expect all groups to now be collapsed', () => {
- cy.get('.slick-preheader-panel .slick-group-toggle-all').click();
+ it('should use the topheader Toggle All button again and expect all groups to now be collapsed', () => {
+ cy.get('.slick-topheader-panel .slick-group-toggle-all').click();
cy.get(`[style="top: ${GRID_ROW_HEIGHT * 0}px;"] > .slick-cell:nth(0) .slick-group-toggle.collapsed`).should('have.length', 1);
cy.get(`[style="top: ${GRID_ROW_HEIGHT * 0}px;"] > .slick-cell:nth(0) .slick-group-title`).should('contain', 'Effort-Driven: False');