Skip to content

Commit

Permalink
feat(plugins): make it possible to use both Header Button/Menu together
Browse files Browse the repository at this point in the history
  • Loading branch information
ghiscoding committed Sep 15, 2021
1 parent 139e24a commit 965bd58
Show file tree
Hide file tree
Showing 13 changed files with 544 additions and 191 deletions.
15 changes: 14 additions & 1 deletion examples/webpack-demo-vanilla-bundle/src/examples/example13.html
Original file line number Diff line number Diff line change
Expand Up @@ -9,5 +9,18 @@ <h3 class="title is-3">
</div>
</h3>

<div class="grid13">
<h5 class="title is-4">Grid 1</h5>

<div class="grid13-1">
</div>

<br />

<div class="columns">
<div class="column field is-narrow">
<h5 class="title is-4">Grid 2 - <span class="subtitle is-5">with both Header Buttons & Menus</span></h5>
</div>
</div>

<div class="grid13-2">
</div>
10 changes: 10 additions & 0 deletions examples/webpack-demo-vanilla-bundle/src/examples/example13.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
/* 1st grid */
.grid13-2 {
--slick-header-button-float: right;
}

/* 2nd grid */
.grid13-2 {
--slick-header-button-margin: -2px 0 50px 0;
--slick-header-button-float: left;
}
138 changes: 86 additions & 52 deletions examples/webpack-demo-vanilla-bundle/src/examples/example13.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,51 +8,54 @@ import { Slicker, SlickVanillaGridBundle } from '@slickgrid-universal/vanilla-bu

import { ExampleGridOptions } from './example-grid-options';
import '../material-styles.scss';
import './example02.scss';
import './example13.scss';

let columnsWithHighlightingById = {};

// create a custom Formatter to highlight negative values in red
const highlightingFormatter = (_row, _cell, value, columnDef) => {
if (columnsWithHighlightingById[columnDef.id] && value < 0) {
return `<div style="color:red; font-weight:bold;">${value}</div>`;
} else {
return value;
}
};
let columns1WithHighlightingById = {};
let columns2WithHighlightingById = {};

export class Example13 {
private _bindingEventService: BindingEventService;
columnDefinitions: Column[];
gridOptions: GridOption;
dataset: any[];
commandQueue = [];
sgb: SlickVanillaGridBundle;
excelExportService: ExcelExportService;
columnDefinitions1: Column[];
columnDefinitions2: Column[];
gridOptions1: GridOption;
gridOptions2: GridOption;
dataset1: any[];
dataset2: any[];
sgb1: SlickVanillaGridBundle;
sgb2: SlickVanillaGridBundle;
excelExportService1: ExcelExportService;
excelExportService2: ExcelExportService;

constructor() {
this.excelExportService = new ExcelExportService();
this.excelExportService1 = new ExcelExportService();
this.excelExportService2 = new ExcelExportService();
this._bindingEventService = new BindingEventService();
columnsWithHighlightingById = {};
columns1WithHighlightingById = {};
columns2WithHighlightingById = {};
}

attached() {
this.initializeGrid();
this.dataset = this.loadData();
const gridContainerElm = document.querySelector<HTMLDivElement>(`.grid13`);
this.dataset1 = this.loadData(200, 1);
this.dataset2 = this.loadData(200, 2);
const gridContainerElm1 = document.querySelector<HTMLDivElement>(`.grid13-1`);
const gridContainerElm2 = document.querySelector<HTMLDivElement>(`.grid13-2`);

this.sgb = new Slicker.GridBundle(gridContainerElm, this.columnDefinitions, { ...ExampleGridOptions, ...this.gridOptions }, this.dataset);
this.sgb1 = new Slicker.GridBundle(gridContainerElm1, this.columnDefinitions1, { ...ExampleGridOptions, ...this.gridOptions1 }, this.dataset1);
this.sgb2 = new Slicker.GridBundle(gridContainerElm2, this.columnDefinitions2, { ...ExampleGridOptions, ...this.gridOptions2 }, this.dataset2);
}

dispose() {
this.sgb?.dispose();
this.sgb1?.dispose();
this.sgb2?.dispose();
this._bindingEventService.unbindAll();
}

initializeGrid() {
this.columnDefinitions = [];
this.columnDefinitions1 = [];
this.columnDefinitions2 = [];

this.gridOptions = {
this.gridOptions1 = {
enableAutoResize: true,
enableHeaderButton: true,
enableHeaderMenu: false,
Expand All @@ -61,40 +64,71 @@ export class Example13 {
},
enableFiltering: false,
enableCellNavigation: true,
gridHeight: 275,
headerButton: {
// you can use the "onCommand" (in Grid Options) and/or the "action" callback (in Column Definition)
onCommand: (_e, args) => {
const column = args.column;
const button = args.button;
const command = args.command;

if (command === 'toggle-highlight') {
if (button.cssClass === 'mdi mdi-lightbulb-on color-danger') {
delete columnsWithHighlightingById[column.id];
button.cssClass = 'mdi mdi-lightbulb-outline color-warning faded';
button.tooltip = 'Highlight negative numbers.';
} else {
columnsWithHighlightingById[column.id] = true;
button.cssClass = 'mdi mdi-lightbulb-on color-danger';
button.tooltip = 'Remove highlight.';
}
this.sgb.slickGrid.invalidate();
}
}
onCommand: (_e, args) => this.handleOnCommand(_e, args, 1)
}
};

// grid 2 options, same as grid 1 + extras
this.gridOptions2 = {
...this.gridOptions1,
enableHeaderMenu: true,
enableFiltering: true,
headerButton: {
// when floating to left, you might want to inverse the icon orders
inverseOrder: true,
onCommand: (_e, args) => this.handleOnCommand(_e, args, 2)
}
};
}

loadData() {
handleOnCommand(_e, args, gridNo: 1 | 2) {
const column = args.column;
const button = args.button;
const command = args.command;

if (command === 'toggle-highlight') {
if (button.cssClass === 'mdi mdi-lightbulb-on color-danger') {
if (gridNo === 1) {
delete columns1WithHighlightingById[column.id];
} else {
delete columns2WithHighlightingById[column.id];
}
button.cssClass = 'mdi mdi-lightbulb-outline color-warning faded';
button.tooltip = 'Highlight negative numbers.';
} else {
if (gridNo === 1) {
columns1WithHighlightingById[column.id] = true;
} else {
columns2WithHighlightingById[column.id] = true;
}
button.cssClass = 'mdi mdi-lightbulb-on color-danger';
button.tooltip = 'Remove highlight.';
}
this[`sgb${gridNo}`].slickGrid.invalidate();
}
}

loadData(count: number, gridNo: 1 | 2) {
// Set up some test columns.
for (let i = 0; i < 10; i++) {
this.columnDefinitions.push({
this[`columnDefinitions${gridNo}`].push({
id: i,
name: 'Column ' + String.fromCharCode('A'.charCodeAt(0) + i),
field: i + '',
width: i === 0 ? 70 : 100, // have the 2 first columns wider
filterable: true,
sortable: true,
formatter: highlightingFormatter,
formatter: (_row, _cell, value, columnDef) => {
if (gridNo === 1 && columns1WithHighlightingById[columnDef.id] && value < 0) {
return `<div style="color:red; font-weight:bold;">${value}</div>`;
} else if (gridNo === 2 && columns2WithHighlightingById[columnDef.id] && value < 0) {
return `<div style="color:red; font-weight:bold;">${value}</div>`;
}
return value;
},
header: {
buttons: [
{
Expand All @@ -121,8 +155,8 @@ export class Example13 {
}

// Set multiple buttons on the first column to demonstrate overflow.
this.columnDefinitions[0].name = 'Resize me!';
this.columnDefinitions[0].header = {
this[`columnDefinitions${gridNo}`][0].name = 'Resize me!';
this[`columnDefinitions${gridNo}`][0].header = {
buttons: [
{
cssClass: 'mdi mdi-message-text',
Expand Down Expand Up @@ -152,8 +186,8 @@ export class Example13 {
};

// Set a button on the second column to demonstrate hover.
this.columnDefinitions[1].name = 'Hover me!';
this.columnDefinitions[1].header = {
this[`columnDefinitions${gridNo}`][1].name = 'Hover me!';
this[`columnDefinitions${gridNo}`][1].header = {
buttons: [
{
cssClass: 'mdi mdi-help-circle-outline',
Expand All @@ -168,10 +202,10 @@ export class Example13 {

// mock a dataset
const mockDataset = [];
for (let i = 0; i < 100; i++) {
for (let i = 0; i < count; i++) {
const d = (mockDataset[i] = {});
d['id'] = i;
for (let j = 0; j < this.columnDefinitions.length; j++) {
for (let j = 0; j < this[`columnDefinitions${gridNo}`].length; j++) {
d[j] = Math.round(Math.random() * 10) - 5;
}
}
Expand Down
6 changes: 6 additions & 0 deletions packages/common/src/interfaces/headerButton.interface.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,4 +17,10 @@ export interface HeaderButton extends HeaderButtonOption {
export interface HeaderButtonOption {
/** an extra CSS class to add to the menu button */
buttonCssClass?: string;

/**
* defaults to false, since the default is right floating, we create the buttons in reverse order
* but if we align to left via CSS we might want to inverse the order
*/
inverseOrder?: boolean;
}
18 changes: 18 additions & 0 deletions packages/common/src/plugins/__tests__/headerButton.plugin.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -343,5 +343,23 @@ describe('HeaderButton Plugin', () => {
`<div class="slick-header-button mdi mdi-lightbulb-on" title="Highlight negative numbers."></div>
<div class="slick-header-button mdi mdi-lightbulb-outline"></div>`));
});

it('should populate 2x Header Buttons but in an inversed order "inverseOrder" flag is enabled and the "disabled" property is set on the 2nd button', () => {
const headerDiv = document.createElement('div');
headerDiv.className = 'slick-header-column';

plugin.dispose();
plugin.init({ inverseOrder: true });
delete columnsMock[0].header.buttons[1].showOnHover;
columnsMock[0].header.buttons[1].disabled = true;

const eventData = { ...new Slick.EventData(), preventDefault: jest.fn() };
gridStub.onHeaderCellRendered.notify({ column: columnsMock[0], node: headerDiv, grid: gridStub }, eventData, gridStub);

// add Header Buttons which are visible (2x buttons)
expect(removeExtraSpaces(headerDiv.innerHTML)).toBe(removeExtraSpaces(
`<div class="slick-header-button mdi mdi-lightbulb-outline"></div>
<div class="slick-header-button slick-header-button-disabled mdi mdi-lightbulb-on" title="Highlight negative numbers."></div>`));
});
});
});
8 changes: 7 additions & 1 deletion packages/common/src/plugins/headerButton.plugin.ts
Original file line number Diff line number Diff line change
Expand Up @@ -95,7 +95,13 @@ export class HeaderButtonPlugin {
const column = args.column;

if (column.header?.buttons && Array.isArray(column.header.buttons)) {
// Append buttons in reverse order since they are floated to the right.
// inverse the button (typically used when icons are floating left)
if (this._addonOptions?.inverseOrder) {
column.header.buttons.reverse();
}

// Append buttons in reverse order (unless they were inversed at previous line)
// since they are floated to the right (unless specified as inversed by the user)
let i = column.header.buttons.length;
while (i--) {
const button = column.header.buttons[i];
Expand Down
6 changes: 5 additions & 1 deletion packages/common/src/plugins/headerMenu.plugin.ts
Original file line number Diff line number Diff line change
Expand Up @@ -276,12 +276,16 @@ export class HeaderMenuPlugin extends MenuBaseClass<HeaderMenu> {
if (Array.isArray(columnDefinitions) && gridOptions.enableHeaderMenu) {
columnDefinitions.forEach((columnDef: Column) => {
if (columnDef && !columnDef.excludeFromHeaderMenu) {
if (!columnDef.header || !columnDef.header.menu) {
if (!columnDef.header) {
columnDef.header = {
menu: {
items: []
}
};
} else if (!columnDef.header.menu) {
// we might have header buttons without header menu,
// so only initialize the header menu without overwrite header buttons
columnDef.header.menu = { items: [] };
}
const columnHeaderMenuItems: Array<MenuCommandItem | 'divider'> = columnDef?.header?.menu?.items ?? [];

Expand Down
2 changes: 1 addition & 1 deletion packages/common/src/styles/_variables-theme-material.scss
Original file line number Diff line number Diff line change
Expand Up @@ -96,7 +96,7 @@ $grid-menu-title-font-size: 18px !default;
$header-button-hidden-margin-right: -6px !default;
$header-button-height: 18px !default;
$header-button-width: 18px !default;
$header-button-margin: -7px 0 100px 0 !default;
$header-button-margin: -4px 0 100px 0 !default;
$header-menu-button-height: 25px !default;
$header-menu-button-icon-font-size: 24px !default;
$header-menu-button-icon-width: 24px !default;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -116,7 +116,7 @@ $grid-menu-title-font-size: 18px !default;
$header-button-hidden-margin-right: -6px !default;
$header-button-height: 18px !default;
$header-button-width: 18px !default;
$header-button-margin: -7px 0 100px 0 !default;
$header-button-margin: -4px 0 100px 0 !default;
$header-menu-button-height: 25px !default;
$header-menu-button-icon-font-size: 26px !default;
$header-menu-button-icon-color: #706e6b !default;
Expand Down
1 change: 1 addition & 0 deletions packages/common/src/styles/_variables.scss
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,7 @@ $header-row-filter-padding: 4px !default;
$header-column-height: calc(17px * #{$header-row-count}) !default; // header is calculated by rows to show
$header-column-background-active: darken($grid-header-background, 5%) !default;
$header-column-background-hover: darken($grid-header-background, 2%) !default;
$header-column-name-margin-right: 5px !default;
$header-border-top: 0 none !default; // header, column titles, that is without the Filters
$header-border-right: 0 none !default;
$header-border-bottom: 0 none !default;
Expand Down
4 changes: 4 additions & 0 deletions packages/common/src/styles/slick-bootstrap.scss
Original file line number Diff line number Diff line change
Expand Up @@ -271,6 +271,7 @@
margin-left: 0;
}
}

.slick-header-column {
height: var(--slick-header-column-height, $header-column-height);
line-height: var(--slick-font-size-base, $font-size-base);
Expand All @@ -283,6 +284,9 @@
&.ui-state-default {
@include resetSlickCell();
}
.slick-column-name {
margin-right: var(--slick-header-column-name-margin-right, $header-column-name-margin-right);
}

$slickgridHoverHeaderColor: var(--slick-text-color, $text-color);
$slickgridSortingHeaderColor: var(--slick-text-color, $text-color);
Expand Down
1 change: 1 addition & 0 deletions packages/common/src/styles/slick-plugins.scss
Original file line number Diff line number Diff line change
Expand Up @@ -284,6 +284,7 @@
* This makes all "float:right" elements after it that spill over to the next line
* display way below the lower boundary of the column thus hiding them.
*/
display: inline;
float: var(--slick-header-button-float, $header-button-float);
vertical-align: var(--slick-header-button-vertical-align, $header-button-vertical-align);
margin: var(--slick-header-button-margin, $header-button-margin);
Expand Down
Loading

0 comments on commit 965bd58

Please sign in to comment.