Skip to content

Commit

Permalink
feat(pinning): add "Frozen Columns" to header menu (#363)
Browse files Browse the repository at this point in the history
* feat(pinning): add "Frozen Columns" to header menu
- this feature will basically allow the user to freeze all columns until the current position of the column header he opened. For example if user is opening column 4 header menu and click on "Frozen Columns", it will freeze all 4 columns on the left.
  • Loading branch information
ghiscoding committed Jun 30, 2020
1 parent 881f234 commit e518eef
Show file tree
Hide file tree
Showing 27 changed files with 519 additions and 37 deletions.
2 changes: 2 additions & 0 deletions assets/i18n/en/aurelia-slickgrid.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
"CLEAR_ALL_FILTERS": "Clear all Filters",
"CLEAR_ALL_GROUPING": "Clear all Grouping",
"CLEAR_ALL_SORTING": "Clear all Sorting",
"CLEAR_FROZEN_COLUMNS": "Clear Frozen Columns",
"COLLAPSE_ALL_GROUPS": "Collapse all Groups",
"COLUMNS": "Columns",
"COMMANDS": "Commands",
Expand All @@ -18,6 +19,7 @@
"EXPORT_TO_TEXT_FORMAT": "Export in Text format",
"FROM_TO_OF_TOTAL_ITEMS": "{{from}}-{{to}} of {{totalItems}} items",
"FORCE_FIT_COLUMNS": "Force fit columns",
"FREEZE_COLUMNS": "Freeze Columns",
"INVALID_FLOAT": "The number must be valid and have a maximum of {{maxDecimal}} decimals.",
"GROUP_BY": "Group by",
"HIDE_COLUMN": "Hide Column",
Expand Down
2 changes: 2 additions & 0 deletions assets/i18n/fr/aurelia-slickgrid.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
"CLEAR_ALL_FILTERS": "Supprimer tous les filtres",
"CLEAR_ALL_GROUPING": "Supprimer tous les groupes",
"CLEAR_ALL_SORTING": "Supprimer tous les tris",
"CLEAR_FROZEN_COLUMNS": "Libérer les colonnes gelées",
"COLLAPSE_ALL_GROUPS": "Réduire tous les groupes",
"COLUMNS": "Colonnes",
"COMMANDS": "Commandes",
Expand All @@ -18,6 +19,7 @@
"EXPORT_TO_TEXT_FORMAT": "Exporter en format texte",
"FROM_TO_OF_TOTAL_ITEMS": "{{from}}-{{to}} de {{totalItems}} éléments",
"FORCE_FIT_COLUMNS": "Ajustement forcé des colonnes",
"FREEZE_COLUMNS": "Geler les colonnes",
"GROUP_BY": "Grouper par",
"HIDE_COLUMN": "Cacher la colonne",
"IN_COLLECTION_SEPERATED_BY_COMMA": "Recherche incluant certain éléments d'une collection, doit être séparé par une virgule (a,b)",
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,7 @@
"jquery-ui-dist": "^1.12.1",
"lodash.isequal": "^4.5.0",
"moment-mini": "^2.24.0",
"slickgrid": "^2.4.24",
"slickgrid": "^2.4.25",
"text-encoding-utf-8": "^1.0.2"
},
"devDependencies": {
Expand Down
2 changes: 2 additions & 0 deletions src/assets/i18n/en/aurelia-slickgrid.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
"CLEAR_ALL_FILTERS": "Clear all Filters",
"CLEAR_ALL_GROUPING": "Clear all Grouping",
"CLEAR_ALL_SORTING": "Clear all Sorting",
"CLEAR_FROZEN_COLUMNS": "Clear Frozen Columns",
"COLLAPSE_ALL_GROUPS": "Collapse all Groups",
"COLUMNS": "Columns",
"COMMANDS": "Commands",
Expand All @@ -18,6 +19,7 @@
"EXPORT_TO_TEXT_FORMAT": "Export in Text format",
"FROM_TO_OF_TOTAL_ITEMS": "{{from}}-{{to}} of {{totalItems}} items",
"FORCE_FIT_COLUMNS": "Force fit columns",
"FREEZE_COLUMNS": "Freeze Columns",
"INVALID_FLOAT": "The number must be valid and have a maximum of {{maxDecimal}} decimals.",
"GROUP_BY": "Group by",
"HIDE_COLUMN": "Hide Column",
Expand Down
2 changes: 2 additions & 0 deletions src/assets/i18n/fr/aurelia-slickgrid.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
"CLEAR_ALL_FILTERS": "Supprimer tous les filtres",
"CLEAR_ALL_GROUPING": "Supprimer tous les groupes",
"CLEAR_ALL_SORTING": "Supprimer tous les tris",
"CLEAR_FROZEN_COLUMNS": "Libérer les colonnes gelées",
"COLLAPSE_ALL_GROUPS": "Réduire tous les groupes",
"COLUMNS": "Colonnes",
"COMMANDS": "Commandes",
Expand All @@ -18,6 +19,7 @@
"EXPORT_TO_TEXT_FORMAT": "Exporter en format texte",
"FROM_TO_OF_TOTAL_ITEMS": "{{from}}-{{to}} de {{totalItems}} éléments",
"FORCE_FIT_COLUMNS": "Ajustement forcé des colonnes",
"FREEZE_COLUMNS": "Geler les colonnes",
"GROUP_BY": "Grouper par",
"HIDE_COLUMN": "Cacher la colonne",
"IN_COLLECTION_SEPERATED_BY_COMMA": "Recherche incluant certain éléments d'une collection, doit être séparé par une virgule (a,b)",
Expand Down
2 changes: 2 additions & 0 deletions src/aurelia-slickgrid/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ export class Constants {
TEXT_CLEAR_ALL_FILTERS: 'Clear all Filters',
TEXT_CLEAR_ALL_GROUPING: 'Clear all Grouping',
TEXT_CLEAR_ALL_SORTING: 'Clear all Sorting',
TEXT_CLEAR_FROZEN_COLUMNS: 'Clear Frozen Columns',
TEXT_COLLAPSE_ALL_GROUPS: 'Collapse all Groups',
TEXT_CONTAINS: 'Contains',
TEXT_COLUMNS: 'Columns',
Expand All @@ -20,6 +21,7 @@ export class Constants {
TEXT_EXPORT_TO_TEXT_FORMAT: 'Export in Text format (Tab delimited)',
TEXT_EXPORT_TO_EXCEL: 'Export to Excel',
TEXT_FORCE_FIT_COLUMNS: 'Force fit columns',
TEXT_FREEZE_COLUMNS: 'Freeze Columns',
TEXT_GROUP_BY: 'Group By',
TEXT_HIDE_COLUMN: 'Hide Column',
TEXT_ITEMS: 'items',
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { FrameworkConfiguration } from 'aurelia-framework';
import { configure, SlickgridConfig } from '../../index';
import * as entry from '../../index';

jest.mock('flatpickr', () => { });

Expand All @@ -18,6 +19,12 @@ describe('Testing library entry point and aurelia configure routine', () => {
expect(typeof configure).toBe('function');
});

it('should export a few functions', () => {
expect(entry.AureliaSlickgridCustomElement).toBeTruthy();
expect(entry.SlickPaginationCustomElement).toBeTruthy();
expect(entry.SlickgridConfig).toBeTruthy();
});

it('should accept a setup callback passing back the instance', (done) => {
const callback = (instance: SlickgridConfig) => {
expect(typeof instance).toBe('object');
Expand Down
2 changes: 1 addition & 1 deletion src/aurelia-slickgrid/editors/dualInputEditor.ts
Original file line number Diff line number Diff line change
Expand Up @@ -138,7 +138,7 @@ export class DualInputEditor implements Editor {
const columnId = this.columnDef && this.columnDef.id;
const elements = document.querySelectorAll(`.dual-editor-text.editor-${columnId}`);
if (elements.length > 0) {
elements.forEach((elm) => elm.removeEventListener('focusout', () => { }));
elements.forEach((elm) => elm.removeEventListener('focusout', this.handleFocusOut.bind(this)));
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ const gridStub = {
getUID: () => gridUid,
registerPlugin: jest.fn(),
setColumns: jest.fn(),
setOptions: jest.fn(),
setHeaderRowVisibility: jest.fn(),
setTopPanelVisibility: jest.fn(),
setPreHeaderPanelVisibility: jest.fn(),
Expand Down Expand Up @@ -77,6 +78,7 @@ const template =
describe('gridMenuExtension', () => {
const columnsMock: Column[] = [{ id: 'field1', field: 'field1', width: 100, nameKey: 'TITLE' }, { id: 'field2', field: 'field2', width: 75 }];
let extensionUtility: ExtensionUtility;
let ea: EventAggregator;
let i18n: I18N;
let extension: GridMenuExtension;
let sharedService: SharedService;
Expand All @@ -97,6 +99,7 @@ describe('gridMenuExtension', () => {
gridMenu: {
customItems: [],
hideClearAllFiltersCommand: false,
hideClearFrozenColumnsCommand: true,
hideForceFitButton: false,
hideSyncResizeButton: true,
onExtensionRegistered: jest.fn(),
Expand All @@ -121,6 +124,7 @@ describe('gridMenuExtension', () => {
document.body.appendChild(div);

sharedService = new SharedService();
ea = new EventAggregator();
i18n = new I18N(new EventAggregator(), new BindingSignaler());
extensionUtility = new ExtensionUtility(i18n, sharedService);
extension = new GridMenuExtension(excelExportServiceStub, exportServiceStub, extensionUtility, filterServiceStub, i18n, sharedService, sortServiceStub);
Expand All @@ -136,6 +140,7 @@ describe('gridMenuExtension', () => {
TITLE: 'Titre',
CLEAR_ALL_FILTERS: 'Supprimer tous les filtres',
CLEAR_ALL_SORTING: 'Supprimer tous les tris',
CLEAR_FROZEN_COLUMNS: 'Libérer les colonnes gelées',
EXPORT_TO_CSV: 'Exporter en format CSV',
EXPORT_TO_EXCEL: 'Exporter vers Excel',
EXPORT_TO_TAB_DELIMITED: 'Exporter en format texte (délimité par tabulation)',
Expand Down Expand Up @@ -366,6 +371,16 @@ describe('gridMenuExtension', () => {
expect(SharedService.prototype.gridOptions.gridMenu.customItems).toEqual([]);
});

it('should expect menu related to "Clear Frozen Columns"', () => {
const copyGridOptionsMock = { ...gridOptionsMock, gridMenu: { hideClearFrozenColumnsCommand: false, } } as unknown as GridOption;
jest.spyOn(SharedService.prototype, 'gridOptions', 'get').mockReturnValue(copyGridOptionsMock);
extension.register();
extension.register(); // calling 2x register to make sure it doesn't duplicate commands
expect(SharedService.prototype.gridOptions.gridMenu.customItems).toEqual([
{ iconCssClass: 'fa fa-times', title: 'Libérer les colonnes gelées', disabled: false, command: 'clear-frozen-columns', positionOrder: 49 },
]);
});

it('should expect all menu related to Filter when "enableFilering" is set', () => {
const copyGridOptionsMock = { ...gridOptionsMock, enableFiltering: true, showHeaderRow: true, } as unknown as GridOption;
jest.spyOn(SharedService.prototype, 'gridOptions', 'get').mockReturnValue(copyGridOptionsMock);
Expand All @@ -379,7 +394,7 @@ describe('gridMenuExtension', () => {
});

it('should have only 1 menu "clear-filter" when all other menus are defined as hidden & when "enableFilering" is set', () => {
const copyGridOptionsMock = { ...gridOptionsMock, enableFiltering: true, showHeaderRow: true, gridMenu: { hideToggleFilterCommand: true, hideRefreshDatasetCommand: true } } as unknown as GridOption;
const copyGridOptionsMock = { ...gridOptionsMock, enableFiltering: true, showHeaderRow: true, gridMenu: { hideClearFrozenColumnsCommand: true, hideToggleFilterCommand: true, hideRefreshDatasetCommand: true } } as unknown as GridOption;
jest.spyOn(SharedService.prototype, 'gridOptions', 'get').mockReturnValue(copyGridOptionsMock);
extension.register();
extension.register(); // calling 2x register to make sure it doesn't duplicate commands
Expand All @@ -389,7 +404,7 @@ describe('gridMenuExtension', () => {
});

it('should have only 1 menu "toggle-filter" when all other menus are defined as hidden & when "enableFilering" is set', () => {
const copyGridOptionsMock = { ...gridOptionsMock, enableFiltering: true, showHeaderRow: true, gridMenu: { hideClearAllFiltersCommand: true, hideRefreshDatasetCommand: true } } as unknown as GridOption;
const copyGridOptionsMock = { ...gridOptionsMock, enableFiltering: true, showHeaderRow: true, gridMenu: { hideClearFrozenColumnsCommand: true, hideClearAllFiltersCommand: true, hideRefreshDatasetCommand: true } } as unknown as GridOption;
jest.spyOn(SharedService.prototype, 'gridOptions', 'get').mockReturnValue(copyGridOptionsMock);
extension.register();
extension.register(); // calling 2x register to make sure it doesn't duplicate commands
Expand All @@ -399,7 +414,7 @@ describe('gridMenuExtension', () => {
});

it('should have only 1 menu "refresh-dataset" when all other menus are defined as hidden & when "enableFilering" is set', () => {
const copyGridOptionsMock = { ...gridOptionsMock, enableFiltering: true, showHeaderRow: true, gridMenu: { hideClearAllFiltersCommand: true, hideToggleFilterCommand: true } } as unknown as GridOption;
const copyGridOptionsMock = { ...gridOptionsMock, enableFiltering: true, showHeaderRow: true, gridMenu: { hideClearFrozenColumnsCommand: true, hideClearAllFiltersCommand: true, hideToggleFilterCommand: true } } as unknown as GridOption;
jest.spyOn(SharedService.prototype, 'gridOptions', 'get').mockReturnValue(copyGridOptionsMock);
extension.register();
extension.register(); // calling 2x register to make sure it doesn't duplicate commands
Expand All @@ -419,7 +434,7 @@ describe('gridMenuExtension', () => {
});

it('should not have the "toggle-preheader" menu command when "showPreHeaderPanel" and "hideTogglePreHeaderCommand" are set', () => {
const copyGridOptionsMock = { ...gridOptionsMock, showPreHeaderPanel: true, gridMenu: { hideTogglePreHeaderCommand: true } } as unknown as GridOption;
const copyGridOptionsMock = { ...gridOptionsMock, showPreHeaderPanel: true, gridMenu: { hideClearFrozenColumnsCommand: true, hideTogglePreHeaderCommand: true } } as unknown as GridOption;
jest.spyOn(SharedService.prototype, 'gridOptions', 'get').mockReturnValue(copyGridOptionsMock);
extension.register();
expect(SharedService.prototype.gridOptions.gridMenu.customItems).toEqual([]);
Expand All @@ -436,14 +451,14 @@ describe('gridMenuExtension', () => {
});

it('should not have the "clear-sorting" menu command when "enableSorting" and "hideClearAllSortingCommand" are set', () => {
const copyGridOptionsMock = { ...gridOptionsMock, enableSorting: true, gridMenu: { hideClearAllSortingCommand: true } } as unknown as GridOption;
const copyGridOptionsMock = { ...gridOptionsMock, enableSorting: true, gridMenu: { hideClearFrozenColumnsCommand: true, hideClearAllSortingCommand: true } } as unknown as GridOption;
jest.spyOn(SharedService.prototype, 'gridOptions', 'get').mockReturnValue(copyGridOptionsMock);
extension.register();
expect(SharedService.prototype.gridOptions.gridMenu.customItems).toEqual([]);
});

it('should have the "export-csv" menu command when "enableExport" is set', () => {
const copyGridOptionsMock = { ...gridOptionsMock, enableExport: true, gridMenu: { hideExportExcelCommand: true, hideExportTextDelimitedCommand: true } } as unknown as GridOption;
const copyGridOptionsMock = { ...gridOptionsMock, enableExport: true, gridMenu: { hideClearFrozenColumnsCommand: true, hideExportExcelCommand: true, hideExportTextDelimitedCommand: true } } as unknown as GridOption;
jest.spyOn(SharedService.prototype, 'gridOptions', 'get').mockReturnValue(copyGridOptionsMock);
extension.register();
extension.register(); // calling 2x register to make sure it doesn't duplicate commands
Expand All @@ -453,14 +468,14 @@ describe('gridMenuExtension', () => {
});

it('should not have the "export-csv" menu command when "enableExport" and "hideExportCsvCommand" are set', () => {
const copyGridOptionsMock = { ...gridOptionsMock, enableExport: true, gridMenu: { hideExportExcelCommand: true, hideExportCsvCommand: true, hideExportTextDelimitedCommand: true } } as unknown as GridOption;
const copyGridOptionsMock = { ...gridOptionsMock, enableExport: true, gridMenu: { hideClearFrozenColumnsCommand: true, hideExportExcelCommand: true, hideExportCsvCommand: true, hideExportTextDelimitedCommand: true } } as unknown as GridOption;
jest.spyOn(SharedService.prototype, 'gridOptions', 'get').mockReturnValue(copyGridOptionsMock);
extension.register();
expect(SharedService.prototype.gridOptions.gridMenu.customItems).toEqual([]);
});

it('should have the "export-excel" menu command when "enableExport" is set', () => {
const copyGridOptionsMock = { ...gridOptionsMock, enableExcelExport: true, enableExport: false, gridMenu: { hideExportCsvCommand: true, hideExportExcelCommand: false } } as unknown as GridOption;
const copyGridOptionsMock = { ...gridOptionsMock, enableExcelExport: true, enableExport: false, gridMenu: { hideClearFrozenColumnsCommand: true, hideExportCsvCommand: true, hideExportExcelCommand: false } } as unknown as GridOption;
jest.spyOn(SharedService.prototype, 'gridOptions', 'get').mockReturnValue(copyGridOptionsMock);
extension.register();
extension.register(); // calling 2x register to make sure it doesn't duplicate commands
Expand All @@ -470,7 +485,7 @@ describe('gridMenuExtension', () => {
});

it('should have the "export-text-delimited" menu command when "enableExport" is set', () => {
const copyGridOptionsMock = { ...gridOptionsMock, enableExport: true, gridMenu: { hideExportCsvCommand: true, hideExportExcelCommand: true } } as unknown as GridOption;
const copyGridOptionsMock = { ...gridOptionsMock, enableExport: true, gridMenu: { hideClearFrozenColumnsCommand: true, hideExportCsvCommand: true, hideExportExcelCommand: true } } as unknown as GridOption;
jest.spyOn(SharedService.prototype, 'gridOptions', 'get').mockReturnValue(copyGridOptionsMock);
extension.register();
extension.register(); // calling 2x register to make sure it doesn't duplicate commands
Expand All @@ -480,7 +495,7 @@ describe('gridMenuExtension', () => {
});

it('should not have the "export-text-delimited" menu command when "enableExport" and "hideExportCsvCommand" are set', () => {
const copyGridOptionsMock = { ...gridOptionsMock, enableExport: true, gridMenu: { hideExportExcelCommand: true, hideExportCsvCommand: true, hideExportTextDelimitedCommand: true } } as unknown as GridOption;
const copyGridOptionsMock = { ...gridOptionsMock, enableExport: true, gridMenu: { hideClearFrozenColumnsCommand: true, hideExportExcelCommand: true, hideExportCsvCommand: true, hideExportTextDelimitedCommand: true } } as unknown as GridOption;
jest.spyOn(SharedService.prototype, 'gridOptions', 'get').mockReturnValue(copyGridOptionsMock);
extension.register();
expect(SharedService.prototype.gridOptions.gridMenu.customItems).toEqual([]);
Expand All @@ -502,6 +517,7 @@ describe('gridMenuExtension', () => {
enableExport: true,
gridMenu: {
customItems: customItemsMock,
hideClearFrozenColumnsCommand: true,
hideExportCsvCommand: false,
hideExportExcelCommand: false,
hideExportTextDelimitedCommand: true,
Expand Down Expand Up @@ -587,6 +603,21 @@ describe('gridMenuExtension', () => {
mockGridMenuAddon.onCommand = new Slick.Event();
});

it('should call "clearFrozenColumns" when the command triggered is "clear-frozen-columns"', () => {
const setOptionsSpy = jest.spyOn(gridStub, 'setOptions');
const setColumnsSpy = jest.spyOn(gridStub, 'setColumns');
const onCommandSpy = jest.spyOn(SharedService.prototype.gridOptions.gridMenu, 'onCommand');
jest.spyOn(SharedService.prototype, 'allColumns', 'get').mockReturnValue(columnsMock);
jest.spyOn(SharedService.prototype, 'visibleColumns', 'get').mockReturnValue(columnsMock.slice(0, 1));

const instance = extension.register();
instance.onCommand.notify({ grid: gridStub, command: 'clear-frozen-columns' }, new Slick.EventData(), gridStub);

expect(onCommandSpy).toHaveBeenCalled();
expect(setColumnsSpy).toHaveBeenCalled();
expect(setOptionsSpy).toHaveBeenCalledWith({ frozenColumn: -1 });
});

it('should call "clearFilters" and dataview refresh when the command triggered is "clear-filter"', () => {
const filterSpy = jest.spyOn(filterServiceStub, 'clearFilters');
const refreshSpy = jest.spyOn(SharedService.prototype.dataView, 'refresh');
Expand Down
Loading

0 comments on commit e518eef

Please sign in to comment.