Skip to content

Commit

Permalink
feat: add sub-menus to CellMenu/ContextMenu plugins
Browse files Browse the repository at this point in the history
- also merge command/option code since we had a lot of duplicate code to do roughly the same thing but with different list (command/options)
  • Loading branch information
ghiscoding-SE committed Oct 18, 2023
1 parent e215137 commit 6e41e8e
Show file tree
Hide file tree
Showing 7 changed files with 462 additions and 285 deletions.
182 changes: 177 additions & 5 deletions cypress/e2e/example-plugin-contextmenu.cy.ts
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ describe('Example - Context Menu & Cell Menu', () => {
.contains('Action');

cy.get('.slick-cell-menu')
.should('not.exist')
.should('not.exist');
});

it('should open the Context Menu and expect onBeforeMenuShow then onAfterMenuShow to show in the console log', () => {
Expand Down Expand Up @@ -147,11 +147,11 @@ describe('Example - Context Menu & Cell Menu', () => {
.should('exist');
});

it('should change the Effort Driven to "False" in that same Action and then expect the "Command 2" to enabled and clickable', () => {
it('should change the Effort Driven to "False" in that same Action and then expect the "Command 2" to be enabled and clickable', () => {
const stub = cy.stub();
cy.on('window:alert', stub);

cy.get('.slick-cell-menu .slick-cell-menu-option-list')
cy.get('.slick-cell-menu.level-0 .slick-cell-menu-option-list')
.find('.slick-cell-menu-item')
.contains('False')
.click();
Expand All @@ -167,6 +167,72 @@ describe('Example - Context Menu & Cell Menu', () => {
.then(() => expect(stub.getCall(0)).to.be.calledWith('Command 2'));
});

it('should change the Effort Driven to "True" by using sub-options in that same Action and then expect the "Command 2" to be disabled and not clickable and "Delete Row" to not be shown', () => {
const stub = cy.stub();
cy.on('window:alert', stub);

cy.get('#myGrid')
.find('.slick-row .slick-cell:nth(7)')
.contains('Action')
.click({ force: true });

cy.get('.slick-cell-menu.level-0 .slick-cell-menu-option-list')
.find('.slick-cell-menu-item')
.contains('Sub-Options')
.click();

cy.get('.slick-cell-menu.level-1 .slick-cell-menu-option-list')
.find('.slick-cell-menu-item')
.contains('True')
.click();

cy.get('#myGrid')
.find('.slick-row .slick-cell:nth(7)')
.contains('Action')
.click({ force: true });

cy.get('.slick-cell-menu .slick-cell-menu-item.slick-cell-menu-item-disabled')
.contains('Command 2');

cy.get('.slick-cell-menu .slick-cell-menu-item')
.contains('Delete Row')
.should('not.exist');
});

it('should change the Effort Driven back to "False" by using sub-options in that same Action and then expect the "Command 2" to enabled and clickable and also show "Delete Row" command', () => {
const stub = cy.stub();
cy.on('window:alert', stub);

cy.get('#myGrid')
.find('.slick-row .slick-cell:nth(7)')
.contains('Action')
.click({ force: true });

cy.get('.slick-cell-menu.level-0 .slick-cell-menu-option-list')
.find('.slick-cell-menu-item')
.contains('Sub-Options')
.click();

cy.get('.slick-cell-menu.level-1 .slick-cell-menu-option-list')
.find('.slick-cell-menu-item')
.contains('False')
.click();

cy.get('#myGrid')
.find('.slick-row .slick-cell:nth(7)')
.contains('Action')
.click({ force: true });

cy.get('.slick-cell-menu .slick-cell-menu-item')
.contains('Delete Row')
.should('exist');

cy.get('.slick-cell-menu .slick-cell-menu-item')
.contains('Command 2')
.click()
.then(() => expect(stub.getCall(0)).to.be.calledWith('Command 2'));
});

it('should expect the Context Menu now have the "Help" menu when Effort Driven is set to False', () => {
const commands = ['Copy Cell Value', 'Delete Row', '', 'Help', 'Command (always disabled)'];

Expand Down Expand Up @@ -213,6 +279,112 @@ describe('Example - Context Menu & Cell Menu', () => {
.should('not.exist');
});

it('should be able to open Cell Menu and click on Export->PDF sub-commands to see 1 cell menu + 1 sub-menu then clicking on PDF should call alert action', () => {
const subCommands = ['PDF', 'Excel'];
const stub = cy.stub();
cy.on('window:alert', stub);

cy.get('#myGrid')
.find('.slick-row .slick-cell:nth(7)')
.contains('Action')
.click({ force: true });

cy.get('.slick-cell-menu.level-0 .slick-cell-menu-command-list')
.find('.slick-cell-menu-item')
.contains('Export')
.click();

cy.get('.slick-cell-menu.level-1 .slick-cell-menu-command-list')
.should('exist')
.find('.slick-cell-menu-item')
.each(($command, index) => expect($command.text()).to.eq(subCommands[index]));

cy.get('.slick-cell-menu.level-1 .slick-cell-menu-command-list')
.find('.slick-cell-menu-item')
.contains('PDF')
.click()
.then(() => expect(stub.getCall(0)).to.be.calledWith('Exporting as PDF'));
});

it('should be able to open Cell Menu and click on Export->Excel-> sub-commands to see 1 cell menu + 1 sub-menu then clicking on PDF should call alert action', () => {
const subCommands1 = ['PDF', 'Excel'];
const subCommands2 = ['Excel (csv)', 'Excel (xls)'];
const stub = cy.stub();
cy.on('window:alert', stub);

cy.get('#myGrid')
.find('.slick-row .slick-cell:nth(7)')
.contains('Action')
.click({ force: true });

cy.get('.slick-cell-menu.level-0 .slick-cell-menu-command-list')
.find('.slick-cell-menu-item')
.contains('Export')
.click();

cy.get('.slick-cell-menu.level-1 .slick-cell-menu-command-list')
.should('exist')
.find('.slick-cell-menu-item')
.each(($command, index) => expect($command.text()).to.eq(subCommands1[index]));

cy.get('.slick-cell-menu.level-1 .slick-cell-menu-command-list')
.find('.slick-cell-menu-item')
.contains('Excel')
.click();

cy.get('.slick-cell-menu.level-2 .slick-cell-menu-command-list')
.should('exist')
.find('.slick-cell-menu-item')
.each(($command, index) => expect($command.text()).to.eq(subCommands2[index]));

cy.get('.slick-cell-menu.level-2 .slick-cell-menu-command-list')
.find('.slick-cell-menu-item')
.contains('Excel (xls)')
.click()
.then(() => expect(stub.getCall(0)).to.be.calledWith('Exporting as Excel (xls)'));
});

it('should open Export->Excel sub-menu & open again Sub-Options on top and expect sub-menu to be recreated with that Sub-Options list instead of the Export->Excel list', () => {
const subCommands1 = ['PDF', 'Excel'];
const subCommands2 = ['Excel (csv)', 'Excel (xls)'];
const subOptions = ['True', 'False'];

cy.get('#myGrid')
.find('.slick-row .slick-cell:nth(7)')
.contains('Action')
.click({ force: true });

cy.get('.slick-cell-menu.level-0 .slick-cell-menu-command-list')
.find('.slick-cell-menu-item')
.contains('Export')
.click();

cy.get('.slick-cell-menu.level-1 .slick-cell-menu-command-list')
.should('exist')
.find('.slick-cell-menu-item')
.each(($command, index) => expect($command.text()).to.eq(subCommands1[index]));

cy.get('.slick-cell-menu.level-1 .slick-cell-menu-command-list')
.find('.slick-cell-menu-item')
.contains('Excel')
.click();

cy.get('.slick-cell-menu.level-2 .slick-cell-menu-command-list')
.should('exist')
.find('.slick-cell-menu-item')
.each(($command, index) => expect($command.text()).to.eq(subCommands2[index]));

cy.get('.slick-cell-menu.level-0 .slick-cell-menu-option-list')
.find('.slick-cell-menu-item')
.contains('Sub-Options')
.click();

cy.get('.slick-cell-menu.level-1 .slick-cell-menu-option-list')
.should('exist')
.find('.slick-cell-menu-item')
.each(($option, index) => expect($option.text()).to.eq(subOptions[index]));
});

it('should click on the "Show Commands & Priority Options" button and see both list when opening Context Menu', () => {
cy.get('button')
.contains('Show Commands & Priority Options')
Expand Down Expand Up @@ -320,8 +492,8 @@ describe('Example - Context Menu & Cell Menu', () => {
.click();
});

it('should click on the "Show Action Commands Only" button and see both list when opening Context Menu', () => {
const commands = ['Command 1', 'Command 2', 'Delete Row', '', 'Help', 'Disabled Command'];
it('should click on the "Show Action Commands Only" button and see both list when opening Cell Menu', () => {
const commands = ['Command 1', 'Command 2', 'Delete Row', '', 'Help', 'Disabled Command', '', 'Export'];

cy.get('button')
.contains('Show Action Commands Only')
Expand Down
40 changes: 33 additions & 7 deletions examples/example-plugin-contextmenu.html
Original file line number Diff line number Diff line change
Expand Up @@ -84,10 +84,10 @@
<body>
<table width="100%">
<tr>
<td valign="top" width="50%">
<td valign="top" width="50%" style="padding-left: 0px">
<div id="myGrid" class="slick-container" style="width:650px;height:700px;"></div>
</td>
<td valign="top">
<td valign="top" style="display: block">
<h2>
<h2>
<a href="/examples/index.html" style="text-decoration: none; font-size: 22px">&#x2302;</a>
Expand Down Expand Up @@ -285,10 +285,13 @@ <h2>View Source:</h2>

switch (command) {
case "command1":
alert('Command 1');
break;
case "command2":
alert('Command 2');
alert(args.item.title);
break;
case "export-csv":
case "export-pdf":
case "export-xls":
alert("Exporting as " + args.item.title);
break;
case "copy-text":
copyCellValue(args.value);
Expand Down Expand Up @@ -352,7 +355,22 @@ <h2>View Source:</h2>
"divider",
// { divider: true },
{ command: "help", title: "Help", iconCssClass: "sgi sgi-help-circle-outline" },
{ command: "something", title: "Disabled Command", disabled: true }
{ command: "something", title: "Disabled Command", disabled: true },
"divider",
{
// we can also have multiple sub-items
command: 'export', title: 'Export',
commandItems: [
{ command: "export-pdf", title: "PDF" },
{
command: 'sub-menu', title: 'Excel', cssClass: "green",
commandItems: [
{ command: "export-csv", title: "Excel (csv)" },
{ command: "export-xls", title: "Excel (xls)" },
]
}
]
}
],
optionTitle: "Change Effort Driven",
optionItems: [
Expand All @@ -373,6 +391,13 @@ <h2>View Source:</h2>
return (!args.dataContext.effortDriven);
}
},
{
// we can also have multiple sub-items
option: null, title: "Sub-Options (demo)", optionItems: [
{ option: true, title: "True", iconCssClass: 'sgi sgi-checkbox-marked-outline green' },
{ option: false, title: "False", iconCssClass: 'sgi sgi-checkbox-blank-outline pink' },
]
}
]
}
}
Expand Down Expand Up @@ -450,7 +475,7 @@ <h2>View Source:</h2>
document.addEventListener("DOMContentLoaded", function() {
dataView = new Slick.Data.DataView();
grid = new Slick.Grid("#myGrid", dataView, columns, gridOptions);
cellMenuPlugin = new Slick.Plugins.CellMenu({ hideMenuOnScroll: true });
cellMenuPlugin = new Slick.Plugins.CellMenu({ hideMenuOnScroll: true, subItemChevronClass: 'sgi sgi-chevron-right' });
contextMenuPlugin = new Slick.Plugins.ContextMenu(contextMenuOptions);
var columnpicker = new Slick.Controls.ColumnPicker(columns, grid, gridOptions);

Expand Down Expand Up @@ -542,6 +567,7 @@ <h2>View Source:</h2>

// subscribe to Cell Menu onOptionSelected event (or use the action callback on each option)
cellMenuPlugin.onOptionSelected.subscribe(function (e, args) {
console.log('onOptionSelected', args)
// e.preventDefault(); // you could do if you wish to keep the menu open
var dataContext = args && args.dataContext;

Expand Down
3 changes: 3 additions & 0 deletions src/models/cellMenuOption.interface.ts
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,9 @@ export interface CellMenuOption {
/** Optional Title of the Option section, it will be hidden when nothing is provided */
optionTitle?: string;

/** CSS class that can be added on the right side of a sub-item parent (typically a chevron-right icon) */
subItemChevronClass?: string;

// --
// action/override callbacks

Expand Down
3 changes: 3 additions & 0 deletions src/models/menuCommandItem.interface.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,9 @@ export interface MenuCommandItem<A = MenuCommandItemCallbackArgs, R = MenuCallba
/** A command identifier to be passed to the onCommand event callback handler (when using "commandItems"). */
command: string;

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

// --
// action/override callbacks

Expand Down
3 changes: 3 additions & 0 deletions src/models/menuOptionItem.interface.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,9 @@ export interface MenuOptionItem extends MenuItem {
/** An option returned by the onOptionSelected (or action) event callback handler. */
option: any;

/** Array of Option Items (title, command, disabled, ...) */
optionItems?: Array<MenuOptionItem | 'divider'>;

// --
// action/override callbacks

Expand Down
Loading

0 comments on commit 6e41e8e

Please sign in to comment.