Skip to content

Commit

Permalink
feat(footer): add Footer Totals Row and fix footer styling (#1576)
Browse files Browse the repository at this point in the history
- this new demo was mainly doable before but this PR also includes CSS styling fixes for the footer totals to show up correctly including fixes for the Dark Mode as well
  • Loading branch information
ghiscoding authored Jun 15, 2024
1 parent 4398f1d commit 809903a
Show file tree
Hide file tree
Showing 9 changed files with 260 additions and 11 deletions.
2 changes: 2 additions & 0 deletions examples/vite-demo-vanilla-bundle/src/app-routing.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ import Example20 from './examples/example20';
import Example21 from './examples/example21';
import Example22 from './examples/example22';
import Example23 from './examples/example23';
import Example24 from './examples/example24';

export class AppRouting {
constructor(private config: RouterConfig) {
Expand Down Expand Up @@ -53,6 +54,7 @@ export class AppRouting {
{ route: 'example21', name: 'example21', view: './examples/example21.html', viewModel: Example21, title: 'Example21', },
{ route: 'example22', name: 'example22', view: './examples/example22.html', viewModel: Example22, title: 'Example22', },
{ route: 'example23', name: 'example23', view: './examples/example23.html', viewModel: Example23, title: 'Example23', },
{ route: 'example24', name: 'example24', view: './examples/example24.html', viewModel: Example24, title: 'Example24', },
{ route: '', redirect: 'example01' },
{ route: '**', redirect: 'example01' }
];
Expand Down
3 changes: 3 additions & 0 deletions examples/vite-demo-vanilla-bundle/src/app.html
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,9 @@ <h4 class="is-size-4 has-text-white">Slickgrid-Universal</h4>
<a class="navbar-item" onclick.delegate="loadRoute('example23')">
Example23 - Excel Export Formulas
</a>
<a class="navbar-item" onclick.delegate="loadRoute('example24')">
Example24 - Footer Totals Row
</a>
</div>
</div>
</div>
Expand Down
12 changes: 1 addition & 11 deletions examples/vite-demo-vanilla-bundle/src/examples/example20.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,6 @@ export default class Example20 {
dataset: any[] = [];
gridOptions!: GridOption;
gridContainerElm: HTMLDivElement;
isWithPagination = true;
sgb: SlickVanillaGridBundle;

attached() {
Expand All @@ -35,7 +34,7 @@ export default class Example20 {
// let's wrap the grid resize in a delay & show the grid only after the resize
setTimeout(() => {
this.sgb = new Slicker.GridBundle(shadowObj.gridContainer as HTMLDivElement, this.columnDefinitions, { ...ExampleGridOptions, ...this.gridOptions }, this.dataset);
this.sgb.resizerService.resizeGrid();
this.sgb.resizerService.resizeGrid(150);
shadowObj.gridContainer.style.opacity = '1';
}, 50);
}
Expand Down Expand Up @@ -124,13 +123,4 @@ export default class Example20 {

return datasetTmp;
}

// Toggle the Grid Pagination
// IMPORTANT, the Pagination MUST BE CREATED on initial page load before you can start toggling it
// Basically you cannot toggle a Pagination that doesn't exist (must created at the time as the grid)
togglePagination() {
this.isWithPagination = !this.isWithPagination;
this.sgb.paginationService!.togglePaginationVisibility(this.isWithPagination);
this.sgb.slickGrid!.setSelectedRows([]);
}
}
25 changes: 25 additions & 0 deletions examples/vite-demo-vanilla-bundle/src/examples/example24.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
<h3 class="title is-3">
Example 24 - Footer Totals Row
<span class="subtitle">(with Salesforce Theme)</span>
<span class="d-inline-flex">
<button class="button is-small" onclick.delegate="toggleDarkMode()" data-test="toggle-dark-mode">
<span class="mdi mdi-theme-light-dark"></span>
<span> Toggle Light/Dark</span>
</button>
</span>

<div class="subtitle code-link">
<span class="is-size-6">see</span>
<a class="is-size-5" target="_blank"
href="https://github.com/ghiscoding/slickgrid-universal/blob/master/examples/vite-demo-vanilla-bundle/src/examples/example24.ts">
<span class="mdi mdi-link-variant"></span> code
</a>
</div>
</h3>

<h6 class="title is-6 italic">
Display a totals row at the end of the grid.
</h6>

<div class="grid24">
</div>
143 changes: 143 additions & 0 deletions examples/vite-demo-vanilla-bundle/src/examples/example24.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,143 @@
import { type Column, Editors, FieldType, type GridOption, SlickEventHandler, } from '@slickgrid-universal/common';
import { Slicker, type SlickVanillaGridBundle } from '@slickgrid-universal/vanilla-bundle';

import { ExampleGridOptions } from './example-grid-options';
import { BindingEventService } from '@slickgrid-universal/binding';

const NB_ITEMS = 100;

export default class Example20 {
private _bindingEventService: BindingEventService;
private _darkMode = false;
private _eventHandler: SlickEventHandler;

columnDefinitions: Column[] = [];
dataset: any[] = [];
gridOptions!: GridOption;
gridContainerElm: HTMLDivElement;
sgb: SlickVanillaGridBundle;

constructor() {
this._bindingEventService = new BindingEventService();
}

attached() {
this._eventHandler = new SlickEventHandler();

// define the grid options & columns and then create the grid itself
this.defineGrid();

// mock some data (different in each dataset)
this.dataset = this.getData(NB_ITEMS);
this.gridContainerElm = document.querySelector<HTMLDivElement>('.grid24') as HTMLDivElement;

this.sgb = new Slicker.GridBundle(document.querySelector('.grid24') as HTMLDivElement, this.columnDefinitions, { ...ExampleGridOptions, ...this.gridOptions }, this.dataset);
this.updateAllTotals();

// bind any of the grid events
this._bindingEventService.bind(this.gridContainerElm, 'oncolumnsreordered', this.handleOnColumnsReordered.bind(this));
this._bindingEventService.bind(this.gridContainerElm, 'oncellchange', this.handleOnCellChange.bind(this));

document.body.classList.add('salesforce-theme');
}

dispose() {
this._eventHandler.unsubscribeAll();
this.sgb?.dispose();
this.gridContainerElm.remove();
document.querySelector('.demo-container')?.classList.remove('dark-mode');
document.body.setAttribute('data-theme', 'light');
}

/* Define grid Options and Columns */
defineGrid() {
const columnDefs: Column[] = [];
for (let i = 0; i < 10; i++) {
columnDefs.push({
id: i,
name: String.fromCharCode('A'.charCodeAt(0) + i),
field: String(i),
type: FieldType.number,
width: 58,
editor: { model: Editors.integer }
});
}
this.columnDefinitions = columnDefs;

this.gridOptions = {
autoEdit: true,
autoCommitEdit: true,
editable: true,
darkMode: this._darkMode,
gridHeight: 450,
gridWidth: 800,
enableCellNavigation: true,
rowHeight: 33,
createFooterRow: true,
showFooterRow: true,
footerRowHeight: 35
};
}

getData(itemCount: number) {
// mock a dataset
const datasetTmp: any[] = [];
for (let i = 0; i < itemCount; i++) {
const d = (datasetTmp[i] = {} as any);
d.id = i;
for (let j = 0; j < this.columnDefinitions.length; j++) {
d[j] = Math.round(Math.random() * 10);
}
}

return datasetTmp;
}

handleOnCellChange(e) {
const args = e?.detail?.args;
this.updateTotal(args.cell);
}

handleOnColumnsReordered() {
this.updateAllTotals();
}

toggleDarkMode() {
this._darkMode = !this._darkMode;
this.toggleBodyBackground();
this.sgb.gridOptions = { ...this.sgb.gridOptions, darkMode: this._darkMode };
this.sgb.slickGrid?.setOptions({ darkMode: this._darkMode });
this.updateAllTotals();
}

toggleBodyBackground() {
if (this._darkMode) {
document.body.setAttribute('data-theme', 'dark');
document.querySelector('.demo-container')?.classList.add('dark-mode');
} else {
document.body.setAttribute('data-theme', 'light');
document.querySelector('.demo-container')?.classList.remove('dark-mode');
}
}

updateAllTotals() {
let columnIdx = this.sgb.slickGrid?.getColumns().length || 0;
while (columnIdx--) {
this.updateTotal(columnIdx);
}
}

updateTotal(cell: number) {
const columnId = this.sgb.slickGrid?.getColumns()[cell].id as number;

let total = 0;
let i = this.dataset.length;
while (i--) {
total += (parseInt(this.dataset[i][columnId], 10) || 0);
}
const columnElement = this.sgb.slickGrid?.getFooterRowColumn(columnId);
if (columnElement) {
columnElement.textContent = `Sum: ${total}`;
}
}
}
3 changes: 3 additions & 0 deletions examples/vite-demo-vanilla-bundle/src/styles.scss
Original file line number Diff line number Diff line change
Expand Up @@ -128,4 +128,7 @@ input.is-narrow {
}
.justify-center {
justify-content: center;
}
.italic {
font-style: italic;
}
11 changes: 11 additions & 0 deletions packages/common/src/styles/_variables.scss
Original file line number Diff line number Diff line change
Expand Up @@ -881,6 +881,16 @@ $slick-viewport-border-right: 0 none !default;
$slick-viewport-border-bottom: 0 none !default;
$slick-viewport-border-left: 0 none !default;

/* SlickGrid built-in Footer */
$slick-grid-footer-display: flex !default;
$slick-grid-footer-align-items: center !default;
$slick-grid-footer-justify-content: normal !default;
$slick-grid-footer-top-border-top: 1px solid #d0d0d0 !default;
$slick-grid-footer-bg-color: #fafaf9 !default;
$slick-grid-footer-font-size: 13px !default;
$slick-grid-footer-font-style: normal !default;
$slick-grid-footer-font-weight: bold !default;

/* Custom Footer */
$slick-footer-bg-color: transparent !default;
$slick-footer-font-size: $slick-font-size-base !default;
Expand Down Expand Up @@ -1012,6 +1022,7 @@ $slick-dark-text-color: #d4d4d4;
--slick-grid-menu-icon-btn-color: #ededed;
--slick-row-mouse-hover-color: #2c3034;
--slick-header-background-color: #1c1c1c;
--slick-grid-footer-bg-color: #1c1c1c;
--slick-header-text-color: #e4e4e4;
--slick-hover-header-color: var(--slick-base-dark-text-color);
--slick-header-row-background-color: #2d2d2d;
Expand Down
14 changes: 14 additions & 0 deletions packages/common/src/styles/slick-grid.scss
Original file line number Diff line number Diff line change
Expand Up @@ -582,6 +582,20 @@
}
}

.slick-footerrow {
border-top: var(--slick-grid-footer-top-border-top, $slick-grid-footer-top-border-top);
background-color: var(--slick-grid-footer-bg-color, $slick-grid-footer-bg-color);
.slick-footerrow-columns {
.slick-footerrow-column {
display: var(--slick-grid-footer-display, $slick-grid-footer-display);
align-items: var(--slick-grid-footer-align-items, $slick-grid-footer-align-items);
justify-content: var(--slick-grid-footer-justify-content, $slick-grid-footer-justify-content);
font-size: var(--slick-grid-footer-font-size, $slick-grid-footer-font-size);
font-style: var(--slick-grid-footer-font-style, $slick-grid-footer-font-style);
font-weight: var(--slick-grid-footer-font-weight, $slick-grid-footer-font-weight);
}
}
}
.slick-header-columns {
background: var(--slick-grid-header-background, $slick-grid-header-background);
background-color: var(--slick-header-background-color, $slick-header-background-color);
Expand Down
58 changes: 58 additions & 0 deletions test/cypress/e2e/example24.cy.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
describe('Example 24 - Footer Totals Row', () => {
const fullTitles = ['A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J'];
const GRID_ROW_HEIGHT = 33;

it('should display Example title', () => {
cy.visit(`${Cypress.config('baseUrl')}/example24`);
cy.get('h3').should('contain', 'Example 24 - Footer Totals Row');
cy.get('h3 span.subtitle').should('contain', '(with Salesforce Theme)');
});

it('should have exact Column Header Titles in the grid', () => {
cy.get('.grid24')
.find('.slick-header-columns:nth(0)')
.children()
.each(($child, index) => expect($child.text()).to.eq(fullTitles[index]));
});

it('should have a total sum displayed in the footer for each column', () => {
for (let i = 0; i < 10; i++) {
cy.get(`.slick-footerrow-columns .slick-footerrow-column:nth(${i})`)
.should($span => {
const totalStr = $span.text();
const totalVal = Number(totalStr.replace('Sum: ', ''));

expect(totalStr).to.contain('Sum:');
expect(totalVal).to.gte(400);
});

}
});

it('should be able to increase cell value by a number of 5 and expect column sum to be increased by 5 as well', () => {
let cellVal = 0;
let totalVal = 0;
const increasingVal = 50;

cy.get(`[style="top: ${GRID_ROW_HEIGHT * 0}px;"] > .slick-cell:nth(0)`)
.should($span => {
cellVal = Number($span.text());
expect(cellVal).to.gte(0);
});
cy.get('.slick-footerrow-columns .slick-footerrow-column:nth(0)')
.should($span => {
totalVal = parseInt($span.text().replace('Sum: ', ''));
expect(totalVal).to.gte(400);
});

cy.get(`[style="top: ${GRID_ROW_HEIGHT * 0}px;"] > .slick-cell:nth(0)`).click();
cy.get('.editor-0').type(`${increasingVal}{enter}`);
cy.wait(1);

cy.get('.slick-footerrow-columns .slick-footerrow-column:nth(0)')
.should($span => {
const newTotalVal = parseInt($span.text().replace('Sum: ', ''));
expect(newTotalVal).to.eq(totalVal - cellVal + increasingVal);
});
});
});

0 comments on commit 809903a

Please sign in to comment.