Skip to content

Commit

Permalink
fix: deprecate GridMenu customItems in favor of commandItems
Browse files Browse the repository at this point in the history
- to align with other Menu plugins (ContextMenu, CellMenu), it's better if we rename `customItems` to `commandItems`, we'll only deprecate it for now so both names would work but the `customItems` will now show a console warning
  • Loading branch information
ghiscoding-SE committed Oct 23, 2023
1 parent 9aebf45 commit 86ced36
Show file tree
Hide file tree
Showing 7 changed files with 84 additions and 57 deletions.
10 changes: 5 additions & 5 deletions cypress/e2e/example-grid-menu.cy.ts
Original file line number Diff line number Diff line change
Expand Up @@ -35,10 +35,10 @@ describe('Example - Grid Menu', () => {
});
});

it('should have the Grid Menu already opened and expect a title for "Custom Menus" and for "Columns"', () => {
it('should have the Grid Menu already opened and expect a title for "Custom Commands" and for "Columns"', () => {
cy.get('.slick-gridmenu-custom')
.find('.title')
.contains('Custom Menus');
.contains('Custom Commands');

cy.get('.slick-gridmenu')
.find('.title')
Expand Down Expand Up @@ -262,7 +262,7 @@ describe('Example - Grid Menu', () => {

it('should expect "Clear Sorting" command to become hidden from Grid Menu when disabling feature', () => {
cy.get('#toggle-sorting')
.click();
.click();

cy.get('#myGrid')
.find('button.slick-gridmenu-button')
Expand All @@ -276,7 +276,7 @@ describe('Example - Grid Menu', () => {

it('should expect "Clear Sorting" command to become visible agaom in Grid Menu when toggling feature again', () => {
cy.get('#toggle-sorting')
.click();
.click();

cy.get('#myGrid')
.find('button.slick-gridmenu-button')
Expand Down Expand Up @@ -336,7 +336,7 @@ describe('Example - Grid Menu', () => {

cy.get('.slick-submenu').should('have.length', 1);
cy.get('.slick-gridmenu.slick-menu-level-1 .slick-gridmenu-command-list')
.find('.slick-gridmenu-item')
.find('.slick-gridmenu-item')
.contains('Excel')
.click();

Expand Down
14 changes: 7 additions & 7 deletions examples/example-grid-menu.html
Original file line number Diff line number Diff line change
Expand Up @@ -186,15 +186,15 @@ <h2>View Source:</h2>
// we could disable the menu entirely by returning false
return true;
},
customTitle: "Custom Menus",
commandTitle: "Custom Commands",
columnTitle: "Columns",
hideForceFitButton: false,
hideSyncResizeButton: false,
iconCssClass: "sgi sgi-menu sgi-17px", // you can provide iconImage OR iconCssClass
leaveOpen: false, // do we want to leave the Grid Menu open after a command execution? (false by default)
// menuWidth: 18, // width that will be use to resize the column header container (18 by default)
resizeOnShowHeaderRow: true,
customItems: [
commandItems: [
{
iconCssClass: "sgi sgi-close red bold",
title: "Clear Filters",
Expand Down Expand Up @@ -256,11 +256,11 @@ <h2>View Source:</h2>
{
// we can also have multiple nested sub-menus
command: 'export', title: 'Export',
customItems: [
commandItems: [
{ command: "export-txt", title: "Text" },
{
command: 'sub-menu', title: 'Excel', cssClass: "green", subMenuTitle: "available formats", subMenuTitleCssClass: "italic orange",
customItems: [
commandItems: [
{ command: "export-csv", title: "Excel (csv)" },
{ command: "export-xls", title: "Excel (xls)" },
]
Expand All @@ -269,12 +269,12 @@ <h2>View Source:</h2>
},
{
command: 'feedback', title: 'Feedback',
customItems: [
commandItems: [
{ command: "request-update", title: "Request update from shipping team", iconCssClass: "sgi sgi-tag-outline", tooltip: "this will automatically send an alert to the shipping team to contact the user for an update" },
"divider",
{
command: 'sub-menu', title: 'Contact Us', iconCssClass: "sgi sgi-user", subMenuTitle: "contact us...", subMenuTitleCssClass: "italic",
customItems: [
commandItems: [
{ command: "contact-email", title: "Email us", iconCssClass: "sgi sgi-pencil-outline" },
{ command: "contact-chat", title: "Chat with us", iconCssClass: "sgi sgi-message-outline" },
{ command: "contact-meeting", title: "Book an appointment", iconCssClass: "sgi sgi-coffee-outline" },
Expand Down Expand Up @@ -337,7 +337,7 @@ <h2>View Source:</h2>

function toggleSorting(e) {
isSortingDisabled = !isSortingDisabled;
options.gridMenu.customItems.forEach(function(menuItem) {
options.gridMenu.commandItems.forEach(function(menuItem) {
if (menuItem && typeof menuItem !== 'string') {
const menuCommand = menuItem.command;
if (menuCommand === 'clear-sorting') {
Expand Down
96 changes: 58 additions & 38 deletions src/controls/slick.gridmenu.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,14 @@
import type { Column, DOMMouseOrTouchEvent, GridMenuCommandItemCallbackArgs, GridMenuEventWithElementCallbackArgs, GridMenuItem, GridMenuOption, GridOption, onGridMenuColumnsChangedCallbackArgs } from '../models/index';
import type {
Column,
DOMMouseOrTouchEvent,
GridMenuCommandItemCallbackArgs,
GridMenuEventWithElementCallbackArgs,
GridMenuItem,
GridMenuOption,
GridOption,
MenuCommandItem,
onGridMenuColumnsChangedCallbackArgs
} from '../models/index';
import { BindingEventService as BindingEventService_, Event as SlickEvent_, Utils as Utils_ } from '../slick.core';
import type { SlickGrid } from '../slick.grid';

Expand All @@ -22,7 +32,7 @@ const Utils = IIFE_ONLY ? Slick.Utils : Utils_;
* let options = {
* enableCellNavigation: true,
* gridMenu: {
* customTitle: "Custom Menus", // default to empty string
* commandTitle: "Command List", // default to empty string
* columnTitle: "Columns", // default to empty string
* iconImage: "some-image.png", // this is the Grid Menu icon (hamburger icon)
* iconCssClass: "fa fa-bars", // you can provide iconImage OR iconCssClass
Expand All @@ -42,12 +52,12 @@ const Utils = IIFE_ONLY ? Slick.Utils : Utils_;
* forceFitTitle: "Force fit columns", // default to "Force fit columns"
* syncResizeTitle: "Synchronous resize", // default to "Synchronous resize"
*
* customItems: [
* commandItems: [
* {
* // custom menu item options
* // command menu item options
* },
* {
* // custom menu item options
* // command menu item options
* }
* ]
* }
Expand All @@ -68,7 +78,7 @@ const Utils = IIFE_ONLY ? Slick.Utils : Utils_;
* marginBottom: Margin to use at the bottom of the grid menu, only in effect when height is undefined (defaults to 15)
* subItemChevronClass: CSS class that can be added on the right side of a sub-item parent (typically a chevron-right icon)
*
* Available custom menu item options:
* Available command menu item options:
* action: Optionally define a callback function that gets executed when item is chosen (and/or use the onCommand event)
* title: Menu item text.
* divider: Whether the current item is a divider, not an actual command.
Expand Down Expand Up @@ -136,8 +146,8 @@ export class SlickGridMenu {
protected _isMenuOpen = false;
protected _columnCheckboxes: HTMLInputElement[] = [];
protected _columnTitleElm!: HTMLElement;
protected _customTitleElm!: HTMLElement;
protected _customMenuElm!: HTMLDivElement;
protected _commandTitleElm!: HTMLElement;
protected _commandListElm!: HTMLDivElement;
protected _headerElm: HTMLDivElement | null = null;
protected _listElm!: HTMLElement;
protected _buttonElm!: HTMLElement;
Expand Down Expand Up @@ -182,6 +192,10 @@ export class SlickGridMenu {
this._gridOptions = grid.getOptions();
this.createGridMenu();

if (this._gridMenuOptions?.customItems || this._gridMenuOptions?.customTitle) {
console.warn('[SlickGrid] Grid Menu "customItems" and "customTitle" were deprecated to align with other Menu plugins, please use "commandItems" and "commandTitle" instead.');
}

// subscribe to the grid, when it's destroyed, we should also destroy the Grid Menu
grid.onBeforeDestroy.subscribe(this.destroy.bind(this));
}
Expand Down Expand Up @@ -240,7 +254,7 @@ export class SlickGridMenu {
}

/** Create the menu or sub-menu(s) but without the column picker which is a separate single process */
createMenu(level = 0, item?: GridMenuItem | 'divider') {
createMenu(level = 0, item?: GridMenuItem | MenuCommandItem | 'divider') {
// create a new cell menu
const maxHeight = isNaN(this._gridMenuOptions?.maxHeight as number) ? this._gridMenuOptions?.maxHeight : `${this._gridMenuOptions?.maxHeight ?? 0}px`;
const width = isNaN(this._gridMenuOptions?.width as number) ? this._gridMenuOptions?.width : `${this._gridMenuOptions?.maxWidth ?? 0}px`;
Expand Down Expand Up @@ -305,20 +319,26 @@ export class SlickGridMenu {
}

// -- Command List section
this._customMenuElm = document.createElement('div');
this._customMenuElm.className = `slick-gridmenu-custom slick-gridmenu-command-list slick-menu-level-${level}`;
this._customMenuElm.role = 'menu';
menuElm.appendChild(this._customMenuElm);
this._commandListElm = document.createElement('div');
this._commandListElm.className = `slick-gridmenu-custom slick-gridmenu-command-list slick-menu-level-${level}`;
this._commandListElm.role = 'menu';
menuElm.appendChild(this._commandListElm);

const commandItems =
(item as GridMenuItem)?.commandItems
?? (item as GridMenuItem)?.customItems
?? this._gridMenuOptions?.commandItems
?? this._gridMenuOptions?.customItems
?? [];

const commandItems = (item as GridMenuItem)?.customItems ?? this._gridMenuOptions?.customItems ?? [];
if (commandItems.length > 0) {

// when creating sub-menu add its sub-menu title when exists
if (item && level > 0) {
this.addSubMenuTitleWhenExists(item, this._customMenuElm); // add sub-menu title when exists
this.addSubMenuTitleWhenExists(item, this._commandListElm); // add sub-menu title when exists
}
}
this.populateCustomMenus(commandItems, this._customMenuElm, { grid: this.grid, level });
this.populateCommandsMenu(commandItems, this._commandListElm, { grid: this.grid, level });

// increment level for possible next sub-menus if exists
level++;
Expand Down Expand Up @@ -363,19 +383,19 @@ export class SlickGridMenu {
}

/** Construct the custom command menu items. */
protected populateCustomMenus(customItems: Array<GridMenuItem | 'divider'>, customMenuElm: HTMLElement, args: { grid: SlickGrid, level: number }) {
protected populateCommandsMenu(commandItems: Array<GridMenuItem | MenuCommandItem | 'divider'>, commandListElm: HTMLElement, args: { grid: SlickGrid, level: number }) {
// user could pass a title on top of the custom section
const isSubMenu = args.level > 0;
if (this._gridMenuOptions?.customTitle && !isSubMenu) {
this._customTitleElm = document.createElement('div');
this._customTitleElm.className = 'title';
this._customTitleElm.innerHTML = this._gridMenuOptions.customTitle;
customMenuElm.appendChild(this._customTitleElm);
if (!isSubMenu && (this._gridMenuOptions?.commandTitle || this._gridMenuOptions?.customTitle)) {
this._commandTitleElm = document.createElement('div');
this._commandTitleElm.className = 'title';
this._commandTitleElm.innerHTML = (this._gridMenuOptions.commandTitle || this._gridMenuOptions.customTitle) as string;
commandListElm.appendChild(this._commandTitleElm);
}

for (let i = 0, ln = customItems.length; i < ln; i++) {
for (let i = 0, ln = commandItems.length; i < ln; i++) {
let addClickListener = true;
const item = customItems[i];
const item = commandItems[i];
const callbackArgs = {
grid: this.grid,
menu: this._menuElm,
Expand Down Expand Up @@ -445,14 +465,14 @@ export class SlickGridMenu {
textElm.classList.add(...(item as GridMenuItem).textCssClass!.split(' '));
}

customMenuElm.appendChild(liElm);
commandListElm.appendChild(liElm);

if (addClickListener) {
this._bindingEventService.bind(liElm, 'click', this.handleMenuItemClick.bind(this, item, args.level) as EventListener);
}

// the option/command item could be a sub-menu if it has another list of commands/options
if ((item as GridMenuItem).customItems) {
if ((item as GridMenuItem).commandItems || (item as GridMenuItem).customItems) {
const chevronElm = document.createElement('span');
chevronElm.className = 'sub-item-chevron';
if (this._gridMenuOptions?.subItemChevronClass) {
Expand Down Expand Up @@ -498,10 +518,10 @@ export class SlickGridMenu {

// empty both the picker list & the command list
Utils.emptyElement(this._listElm);
Utils.emptyElement(this._customMenuElm);
Utils.emptyElement(this._commandListElm);

const commandItems = this._gridMenuOptions?.customItems ?? [];
this.populateCustomMenus(commandItems, this._customMenuElm, { grid: this.grid, level: 0 });
const commandItems = this._gridMenuOptions?.commandItems ?? this._gridMenuOptions?.customItems ?? [];
this.populateCommandsMenu(commandItems, this._commandListElm, { grid: this.grid, level: 0 });
this.updateColumnOrder();
this._columnCheckboxes = [];

Expand Down Expand Up @@ -668,11 +688,11 @@ export class SlickGridMenu {
}
}

protected handleMenuItemClick(item: GridMenuItem | 'divider', level = 0, e: DOMMouseOrTouchEvent<HTMLButtonElement | HTMLDivElement>) {
protected handleMenuItemClick(item: GridMenuItem | MenuCommandItem | 'divider', level = 0, e: DOMMouseOrTouchEvent<HTMLButtonElement | HTMLDivElement>) {
if (item !== 'divider' && !item.disabled && !item.divider) {
const command = item.command || '';

if (Utils.isDefined(command) && !item.customItems) {
if (Utils.isDefined(command) && !item.commandItems && !(item as GridMenuItem).customItems) {
const callbackArgs: GridMenuCommandItemCallbackArgs = {
grid: this.grid,
command,
Expand All @@ -684,7 +704,7 @@ export class SlickGridMenu {

// execute action callback when defined
if (typeof item.action === 'function') {
item.action.call(this, e, callbackArgs);
(item as MenuCommandItem).action!.call(this, e, callbackArgs);
}

// does the user want to leave open the Grid Menu after executing a command?
Expand All @@ -696,7 +716,7 @@ export class SlickGridMenu {
// Stop propagation so that it doesn't register as a header click event.
e.preventDefault();
e.stopPropagation();
} else if ((item as GridMenuItem).customItems) {
} else if (item.commandItems || (item as GridMenuItem).customItems) {
this.repositionSubMenu(item, level, e);
} else {
this.destroySubMenus();
Expand All @@ -721,17 +741,17 @@ export class SlickGridMenu {
this.destroySubMenus();
}

/** Update the Titles of each sections (command, customTitle, ...) */
/** Update the Titles of each sections (command, commandTitle, ...) */
updateAllTitles(gridMenuOptions: GridMenuOption) {
if (this._customTitleElm?.innerHTML) {
this._customTitleElm.innerHTML = gridMenuOptions.customTitle || '';
if (this._commandTitleElm?.innerHTML) {
this._commandTitleElm.innerHTML = gridMenuOptions.commandTitle || gridMenuOptions.customTitle || '';
}
if (this._columnTitleElm?.innerHTML) {
this._columnTitleElm.innerHTML = gridMenuOptions.columnTitle || '';
}
}

protected addSubMenuTitleWhenExists(item: GridMenuItem | 'divider', commandOrOptionMenu: HTMLDivElement) {
protected addSubMenuTitleWhenExists(item: GridMenuItem | MenuCommandItem | 'divider', commandOrOptionMenu: HTMLDivElement) {
if (item !== 'divider' && item?.subMenuTitle) {
const subMenuTitleElm = document.createElement('div');
subMenuTitleElm.className = 'slick-menu-title';
Expand All @@ -745,7 +765,7 @@ export class SlickGridMenu {
}
}

protected repositionSubMenu(item: GridMenuItem | 'divider', level: number, e: DOMMouseOrTouchEvent<HTMLButtonElement | HTMLDivElement>) {
protected repositionSubMenu(item: GridMenuItem | MenuCommandItem | 'divider', level: number, e: DOMMouseOrTouchEvent<HTMLButtonElement | HTMLDivElement>) {
// when we're clicking a grid cell OR our last menu type (command/option) differs then we know that we need to start fresh and close any sub-menus that might still be open
if (e.target.classList.contains('slick-cell')) {
this.destroySubMenus();
Expand Down
4 changes: 2 additions & 2 deletions src/models/gridMenuCommandItemCallbackArgs.interface.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import type { Column, GridMenuItem } from './index';
import type { Column, GridMenuItem, MenuCommandItem } from './index';
import type { SlickGrid } from '../slick.grid';


Expand All @@ -14,7 +14,7 @@ export interface GridMenuCommandItemCallbackArgs {
command: string;

/** Menu item selected */
item: GridMenuItem;
item: GridMenuItem | MenuCommandItem;

/** Slick Grid object */
grid: SlickGrid;
Expand Down
4 changes: 2 additions & 2 deletions src/models/gridMenuItem.interface.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import type { GridMenuCallbackArgs, GridMenuCommandItemCallbackArgs, MenuCommandItem } from './index';
import type { SlickEventData } from '../slick.core';

export interface GridMenuItem extends Omit<MenuCommandItem<GridMenuCommandItemCallbackArgs, GridMenuCallbackArgs>, 'commandItems'> {
/** Array of Command Items (title, command, disabled, ...) */
export interface GridMenuItem extends MenuCommandItem<GridMenuCommandItemCallbackArgs, GridMenuCallbackArgs> {
/** @deprecated use `commandItems` instead. Array of Command Items (title, command, disabled, ...) */
customItems?: Array<GridMenuItem | 'divider'>;

// --
Expand Down
10 changes: 8 additions & 2 deletions src/models/gridMenuOption.interface.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,16 @@
import type { Column, GridMenuItem, GridOption, MenuCallbackArgs, } from './index';
import type { Column, GridMenuCallbackArgs, GridMenuCommandItemCallbackArgs, GridMenuItem, GridOption, MenuCallbackArgs, MenuCommandItem, } from './index';

export interface GridMenuOption {
/** Defaults to "Commands" which is the title that shows up over the custom commands list */
customTitle?: string;
commandTitle?: string;

/** Array of command items (title, command, disabled, ...) */
commandItems?: Array<MenuCommandItem<GridMenuCommandItemCallbackArgs, GridMenuCallbackArgs> | 'divider'>;

/** @deprecated use `commandTitle` instead. Defaults to "Commands" which is the title that shows up over the custom commands list */
customTitle?: string;

/** @deprecated use `commandItems` instead. Array of command items (title, command, disabled, ...) */
customItems?: Array<GridMenuItem | 'divider'>;

/** Defaults to 0 (auto), minimum width of grid menu content (command, column list) */
Expand Down
3 changes: 2 additions & 1 deletion src/models/menuCommandItem.interface.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
import type { MenuItem } from './menuItem.interface';
import type { GridMenuCommandItemCallbackArgs } from './gridMenuCommandItemCallbackArgs.interface';
import type { MenuCommandItemCallbackArgs } from './menuCommandItemCallbackArgs.interface';
import type { MenuCallbackArgs } from './menuCallbackArgs.interface';
import type { SlickEventData } from '../slick.core';

export interface MenuCommandItem<A = MenuCommandItemCallbackArgs, R = MenuCallbackArgs> extends MenuItem<R> {
export interface MenuCommandItem<A = MenuCommandItemCallbackArgs | GridMenuCommandItemCallbackArgs, R = MenuCallbackArgs> extends MenuItem<R> {
/** A command identifier to be passed to the onCommand event callback handler (when using "commandItems"). */
command: string;

Expand Down

0 comments on commit 86ced36

Please sign in to comment.