Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
37 changes: 37 additions & 0 deletions .github/pull_request_template.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
<!-- PR title should be using conventional commit with a length below 73 chars. See https://www.conventionalcommits.org/en/v1.0.0/ -->
<!-- if this PR fixes an issue, please add it on a separate line for proper linking and following this structure "fixes #123" (replace 123 with the correct issue number) -->

## Summary

<!-- Describe the purpose of this pull request and link any related issue. -->

## Why

<!-- Optional reasons explaining why you think this PR can be useful -->

## Changes

<!-- List the important implementation or documentation changes. -->

## Validation

<!-- List the tests, builds, lint, formatting, or other checks that were run. -->

## Comments

<!-- Any other optional comments or website links to add -->

## AI / LLM assistance

- AI / LLM assistance used:
- [ ] No
- [ ] Yes
- If **Yes**:
- **which tool/model**:
- **how was it used**:

## Checklist

- [ ] The changes are limited to only one scope (if not please explain why in the comments above).
- [ ] Tests were added or updated where appropriate.
- [ ] Documentation was updated where appropriate.
34 changes: 21 additions & 13 deletions cypress/e2e/example-0031-row-span-employees.cy.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,14 @@ describe('Example - colspan/rowspan - Employees Timesheets', { retries: 1 }, ()
cy.get('.grid-canvas-right .slick-cell:not(.frozen)').should('have.length.above', 60);
});

it('should hide Employee ID with hidden while keeping the complete column definition list', () => {
cy.get('[data-test="toggle-employee-id"]').click();
cy.get('#myGrid .slick-header-column').should('have.length', 18);
cy.get('[data-row=0] > .slick-cell.l0').should('not.exist');
cy.get('[data-test="toggle-employee-id"]').click();
cy.get('#myGrid .slick-header-column').should('have.length', 19);
});

describe('Spanning', () => {
it('should expect "Davolio", "Check Mail", and "Development" to all have rowspan of 2 in morning hours', () => {
cy.get(`[data-row=0] > .slick-cell.l1.r1.rowspan`).should('contain', 'Davolio');
Expand Down Expand Up @@ -450,25 +458,25 @@ describe('Example - colspan/rowspan - Employees Timesheets', { retries: 1 }, ()
cy.get('[data-test="toggle-employee-id"]').click();
});

it('should expect EmployeeID to follow columns at index 0 column index', () => {
cy.get(`[data-row=0] > .slick-cell.l0.r0.rowspan`).should('contain', 'Davolio');
cy.get(`[data-row=0] > .slick-cell.l0.r0.rowspan`).should(($el) => expect(parseInt(`${$el.outerHeight()}`, 10)).to.eq(GRID_ROW_HEIGHT * 2));
it('should preserve the original cell indexes while EmployeeID is hidden', () => {
cy.get(`[data-row=0] > .slick-cell.l1.r1.rowspan`).should('contain', 'Davolio');
cy.get(`[data-row=0] > .slick-cell.l1.r1.rowspan`).should(($el) => expect(parseInt(`${$el.outerHeight()}`, 10)).to.eq(GRID_ROW_HEIGHT * 2));

cy.get(`[data-row=2] > .slick-cell.l1.r3.rowspan`).should('contain', 'Check Mail');
cy.get(`[data-row=2] > .slick-cell.l1.r3.rowspan`).should(($el) => expect(parseInt(`${$el.outerHeight()}`, 10)).to.eq(GRID_ROW_HEIGHT * 2));
cy.get(`[data-row=2] > .slick-cell.l2.r4.rowspan`).should('contain', 'Check Mail');
cy.get(`[data-row=2] > .slick-cell.l2.r4.rowspan`).should(($el) => expect(parseInt(`${$el.outerHeight()}`, 10)).to.eq(GRID_ROW_HEIGHT * 2));

cy.get(`[data-row=8] > .slick-cell.l6.r8.rowspan`).should('contain', 'Development');
cy.get(`[data-row=8] > .slick-cell.l6.r8.rowspan`).should(($el) => expect(parseInt(`${$el.outerHeight()}`, 10)).to.eq(GRID_ROW_HEIGHT * 2));
cy.get(`[data-row=8] > .slick-cell.l7.r9.rowspan`).should('contain', 'Development');
cy.get(`[data-row=8] > .slick-cell.l7.r9.rowspan`).should(($el) => expect(parseInt(`${$el.outerHeight()}`, 10)).to.eq(GRID_ROW_HEIGHT * 2));
});

it('should expect "Lunch Break" to be moved to the left by 1 index less', () => {
cy.get(`[data-row=0] > .slick-cell.l9.r11.rowspan`).should('contain', 'Lunch Break');
cy.get(`[data-row=0] > .slick-cell.l9.r11.rowspan`).should(($el) => expect(parseInt(`${$el.outerHeight()}`, 10)).to.eq(GRID_ROW_HEIGHT * 10));
it('should preserve the original Lunch Break cell index', () => {
cy.get(`[data-row=0] > .slick-cell.l10.r12.rowspan`).should('contain', 'Lunch Break');
cy.get(`[data-row=0] > .slick-cell.l10.r12.rowspan`).should(($el) => expect(parseInt(`${$el.outerHeight()}`, 10)).to.eq(GRID_ROW_HEIGHT * 10));
});

it('should expect "Development" to be moved to the left by 1 index less', () => {
cy.get(`[data-row=1] > .slick-cell.l12.r13.rowspan`).should('contain', 'Development');
cy.get(`[data-row=1] > .slick-cell.l12.r13.rowspan`).should(($el) => expect(parseInt(`${$el.outerHeight()}`, 10)).to.eq(GRID_ROW_HEIGHT * 5));
it('should preserve the original afternoon Development cell index', () => {
cy.get(`[data-row=1] > .slick-cell.l13.r14.rowspan`).should('contain', 'Development');
cy.get(`[data-row=1] > .slick-cell.l13.r14.rowspan`).should(($el) => expect(parseInt(`${$el.outerHeight()}`, 10)).to.eq(GRID_ROW_HEIGHT * 5));
});
});

Expand Down
54 changes: 35 additions & 19 deletions cypress/e2e/example-colspan.cy.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
describe('Example - Column Span & Header Grouping', { retries: 1 }, () => {
const GRID_ROW_HEIGHT = 25;
const fullTitles = ['Title', 'Duration', '% Complete', 'Start', 'Finish', 'Effort Driven'];
const fullTitles = ['Title', 'Duration', 'Start', 'Finish', '% Complete', 'Effort Driven'];
for (let i = 0; i < 30; i++) {
fullTitles.push(`Mock${i}`);
}
Expand All @@ -19,31 +18,48 @@ describe('Example - Column Span & Header Grouping', { retries: 1 }, () => {
});

it('should expect 1st row to be 1 column spanned to the entire width', () => {
cy.get(`[style*="top: ${GRID_ROW_HEIGHT * 0}px;"] > .slick-cell:nth(0)`).should('contain', 'Task 0');
cy.get(`[style*="top: ${GRID_ROW_HEIGHT * 0}px;"] > .slick-cell.l0.r5`).should('exist');
cy.get(`[style*="top: ${GRID_ROW_HEIGHT * 0}px;"] > .slick-cell:nth(1)`).should('not.exist');
cy.get('[data-row=0] > .slick-cell:nth(0)').should('contain', 'Task 0');
cy.get('[data-row=0] > .slick-cell.l0.r5').should('exist');
cy.get('[data-row=0] > .slick-cell:nth(1)').should('not.exist');
});

it('should expect 2nd row to be 4 columns and not be spanned', () => {
cy.get(`[style*="top: ${GRID_ROW_HEIGHT * 1}px;"] > .slick-cell:nth(0)`).should('contain', 'Task 1');
cy.get(`[style*="top: ${GRID_ROW_HEIGHT * 1}px;"] > .slick-cell.l0.r0`).should('exist');
cy.get(`[style*="top: ${GRID_ROW_HEIGHT * 1}px;"] > .slick-cell:nth(1)`).should('contain', '5 days');
cy.get(`[style*="top: ${GRID_ROW_HEIGHT * 1}px;"] > .slick-cell:nth(1).l1.r3`).should('exist');
cy.get(`[style*="top: ${GRID_ROW_HEIGHT * 1}px;"] > .slick-cell:nth(2)`).should('contain', '01/05/2009');
cy.get(`[style*="top: ${GRID_ROW_HEIGHT * 1}px;"] > .slick-cell:nth(3)`).contains(/(true|false)/);
cy.get('[data-row=1] > .slick-cell:nth(0)').should('contain', 'Task 1');
cy.get('[data-row=1] > .slick-cell.l0.r0').should('exist');
cy.get('[data-row=1] > .slick-cell:nth(1)').should('contain', '5 days');
cy.get('[data-row=1] > .slick-cell:nth(1).l1.r3').should('exist');
cy.get('[data-row=1] > .slick-cell:nth(2)').contains(/\d+$/);
cy.get('[data-row=1] > .slick-cell:nth(3)').contains(/(true|false)/);
});

it('should expect 3rd row to be 1 column spanned to the entire width', () => {
cy.get(`[style*="top: ${GRID_ROW_HEIGHT * 2}px;"] > .slick-cell:nth(0)`).should('contain', 'Task 2');
cy.get(`[style*="top: ${GRID_ROW_HEIGHT * 2}px;"] > .slick-cell.l0.r5`).should('exist');
cy.get(`[style*="top: ${GRID_ROW_HEIGHT * 2}px;"] > .slick-cell:nth(1)`).should('not.exist');
cy.get('[data-row=2] > .slick-cell:nth(0)').should('contain', 'Task 2');
cy.get('[data-row=2] > .slick-cell.l0.r5').should('exist');
cy.get('[data-row=2] > .slick-cell:nth(1)').should('not.exist');
});

it('should expect 4th row to be 4 columns and not be spanned', () => {
cy.get(`[style*="top: ${GRID_ROW_HEIGHT * 3}px;"] > .slick-cell:nth(0)`).should('contain', 'Task 3');
cy.get(`[style*="top: ${GRID_ROW_HEIGHT * 3}px;"] > .slick-cell:nth(1)`).should('contain', '5 days');
cy.get(`[style*="top: ${GRID_ROW_HEIGHT * 3}px;"] > .slick-cell:nth(2)`).should('contain', '01/05/2009');
cy.get(`[style*="top: ${GRID_ROW_HEIGHT * 3}px;"] > .slick-cell:nth(3)`).contains(/(true|false)/);
it('should expect 4th row to contain the Duration colspan followed by the analysis columns', () => {
cy.get('[data-row=3] > .slick-cell:nth(0)').should('contain', 'Task 3');
cy.get('[data-row=3] > .slick-cell:nth(1)').should('contain', '5 days');
cy.get('[data-row=3] > .slick-cell:nth(2)').contains(/\d+$/);
cy.get('[data-row=3] > .slick-cell:nth(3)').contains(/(true|false)/);
});

it('should hide Finish while keeping it in getColumns and preserve the original colspan indexes', () => {
cy.get('[data-test="hide-finish-column"]').click();
cy.get('#myGrid .slick-header-column').should('have.length', 5);
cy.get('[data-row=1] > .slick-cell.l1.r3').should('contain', '5 days');
cy.get('[data-row=1] > .slick-cell.l4.r4').contains(/\d+$/);
cy.get('[data-row=1] > .slick-cell.l5.r5').contains(/(true|false)/);
cy.get('[data-test="hide-finish-column"]').click();
});

it('should spread Duration colspan across hidden columns when enabled', () => {
cy.get('[data-test="hide-finish-column"]').click();
cy.get('[data-test="spread-colspan-button"]').click();
cy.get('[data-row=1] > .slick-cell.l1.r4').should('contain', '5 days');
cy.get('[data-test="spread-colspan-button"]').click();
cy.get('[data-test="hide-finish-column"]').click();
});

describe('Basic Key Navigations', () => {
Expand Down
2 changes: 1 addition & 1 deletion cypress/e2e/example-frozen-columns-and-column-group.cy.ts
Original file line number Diff line number Diff line change
Expand Up @@ -102,7 +102,7 @@ describe('Example - Row Grouping Titles', () => {
});

it('should be able to call column picker from the pre-header', () => {
const fullPreTitlesWithoutId = ['Common Factor', 'Period', 'Period', 'Analysis'];
const fullPreTitlesWithoutId = ['Common Factor', 'Period', 'Analysis'];
const fullTitlesWithoutId = ['Title', 'Duration', 'Start', 'Finish', '% Complete', 'Effort Driven'];
const fullTitlesWithGroup = ['#', 'Common Factor - Title', 'Common Factor - Duration', 'Period - Start', 'Period - Finish', 'Analysis - % Complete', 'Analysis - Effort Driven'];

Expand Down
2 changes: 1 addition & 1 deletion cypress/e2e/example-variable-row-height-frozen.cy.ts
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ describe('Example - Variable Row Height with Frozen Columns/Rows', { retries: 1
it('should scroll both panes to a far row (top) keeping pane agreement', () => {
cy.contains('button', 'Scroll both to row 300').click();
// scrollRowToTop lands row 300 as the first visible row in both grids' scrolling panes
cy.window().then(win => {
cy.window().should(win => {
expect((win as any).gridA.getViewport().top).to.eq(300);
expect((win as any).gridB.getViewport().top).to.eq(300);
});
Expand Down
2 changes: 1 addition & 1 deletion cypress/e2e/example-variable-row-height-spans.cy.ts
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ describe('Example - Variable Row Height with Cell Spans', { retries: 1 }, () =>
it('should scroll a far span head to the top with consistent geometry', () => {
cy.contains('button', 'Scroll far span').click();
// scrollRowToTop lands row 299 as the first visible row (not merely into view at the bottom)
cy.window().then(win => {
cy.window().should(win => {
expect((win as any).grid.getViewport().top).to.eq(299);
});
cy.get('#myGrid .slick-row[data-row=299] > .slick-cell.l0')
Expand Down
29 changes: 6 additions & 23 deletions examples/example-0031-row-span-employees.html
Original file line number Diff line number Diff line change
Expand Up @@ -245,29 +245,12 @@ <h2>
// if column index(es) aren't changing then "invalidateRows()" or "invalidate()" might be sufficient
// however, when column index(es) changed then you will have to call "remapAllColumnsRowSpan()" to clear & reevaluate the rowspan cache
function toggleEmployeeIdVisibility() {
const newMetadata = {};
showEmployeeId = !showEmployeeId;

// direction to calculate new column indexes (-1 or +1 on the column index)
// e.g. metadata = `{0:{columns:{1:{rowspan: 2}}}}` if we hide then new result is `{0:{columns:{0:{rowspan: 2}}}}`
const dir = showEmployeeId ? 1 : -1;
for (let row of Object.keys(metadata)) {
newMetadata[row] = { columns: {} };
for (let col of Object.keys(metadata[row].columns)) {
newMetadata[row].columns[Number(col) + dir] = metadata[row].columns[col];
}
}

// update column definitions
if (showEmployeeId) {
columns.unshift({ id: "employeeID", name: "Employee ID", field: "employeeID", width: 100 });
} else {
columns.splice(0, 1);
}
grid.setColumns(columns);

// update & remap rowspans
metadata = newMetadata;
// Keep the complete column list and switch visibility with the hidden property.
// This is the breaking-change behavior introduced by the column visibility migration.
grid.setOptions({ frozenColumn: showEmployeeId ? 0 : -1 });
grid.updateColumnById("employeeID", { hidden: !showEmployeeId });
grid.updateColumns();
grid.remapAllColumnsRowSpan();
grid.invalidate();
}
Expand Down Expand Up @@ -372,4 +355,4 @@ <h2>
}
</script>
</body>
</html>
</html>
33 changes: 26 additions & 7 deletions examples/example-colspan.html
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,10 @@ <h2>
<ul>
<li>column span</li>
</ul>
<div style="margin-bottom: 10px">
<button class="btn" data-test="hide-finish-column" onclick="toggleFinishColumn()">Hide/Show Finish Column</button>
<button class="btn" data-test="spread-colspan-button" onclick="toggleSpreadHiddenColspan()">Toggle Spreading of ColSpan with Hidden Columns</button>
</div>
<h2>View Source:</h2>
<ul>
<li><A href="https://github.com/6pac/SlickGrid/blob/master/examples/example-colspan.html" target="_sourcewindow"> View the source for this example on Github</a></li>
Expand All @@ -41,18 +45,20 @@ <h2>View Source:</h2>
<script>
var grid;
var columns = [
{id: "title", name: "Title", field: "title"},
{id: "duration", name: "Duration", field: "duration"},
{id: "%", name: "% Complete", field: "percentComplete", selectable: false, width: 100},
{id: "start", name: "Start", field: "start"},
{id: "finish", name: "Finish", field: "finish"},
{id: "effort-driven", name: "Effort Driven", field: "effortDriven", width: 100}
{id: "title", name: "Title", field: "title", columnGroup: "Common Factor"},
{id: "duration", name: "Duration", field: "duration", columnGroup: "Common Factor"},
{id: "start", name: "Start", field: "start", columnGroup: "Period"},
{id: "finish", name: "Finish", field: "finish", columnGroup: "Period"},
{id: "%", name: "% Complete", field: "percentComplete", selectable: false, width: 100, columnGroup: "Analysis"},
{id: "effort-driven", name: "Effort Driven", field: "effortDriven", width: 100, columnGroup: "Analysis"}
];

var options = {
enableCellNavigation: true,
enableColumnReorder: false
enableColumnReorder: false,
spreadHiddenColspan: false
};
var isSpreadHiddenColspan = false;

document.addEventListener("DOMContentLoaded", function() {
var data = [];
Expand Down Expand Up @@ -91,6 +97,19 @@ <h2>View Source:</h2>

grid.setSelectionModel(new Slick.CellSelectionModel());
});

function toggleFinishColumn() {
var finishColumn = grid.getColumnById("finish");
grid.updateColumnById("finish", { hidden: !finishColumn.hidden });
grid.updateColumns();
}

function toggleSpreadHiddenColspan() {
isSpreadHiddenColspan = !isSpreadHiddenColspan;
grid.setOptions({ spreadHiddenColspan: isSpreadHiddenColspan });
grid.resetActiveCell();
grid.invalidate();
}
</script>
</body>
</html>
2 changes: 1 addition & 1 deletion examples/example-draggable-header-grouping.html
Original file line number Diff line number Diff line change
Expand Up @@ -164,7 +164,7 @@ <h2>View Source:</h2>

for (var i = 0; i < columns.length; i++) {
m = columns[i];
if (m) {
if (m && !m.hidden) {
if (lastColumnGroup === m.columnGroup && i > 0) {
widthTotal += m.width || 0;
headerElm.style.width = `${widthTotal - headerColumnWidthDiff}px`;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ <h2>
<br/>
<h2>View Source:</h2>
<ul>
<li><A href="https://github.com/6pac/SlickGrid/blob/master/examples/example-frozen-columns-and-column-group.html" target="_sourcewindow"> View the source for this example on Github</a></li>
<li><A href="https://github.com/6pac/SlickGrid/blob/master/examples/example-frozen-columns-and-column-group-hidden-col.html" target="_sourcewindow"> View the source for this example on Github</a></li>
</ul>
</div>
</div>
Expand Down Expand Up @@ -220,14 +220,14 @@ <h2>View Source:</h2>

document.querySelector('#chkHideColumn1').addEventListener("change", function(e) {
let hideCol = document.querySelector('#chkHideColumn1').checked || false;
columns[2].hidden = hideCol;
grid.updateColumnById('duration', { hidden: hideCol });
grid.updateColumns();
CreateAddlHeaderRow();
});

document.querySelector('#chkHideColumn2').addEventListener("change", function(e) {
let hideCol = document.querySelector('#chkHideColumn2').checked || false;
columns[4].hidden = hideCol;
grid.updateColumnById('finish', { hidden: hideCol });
grid.updateColumns();
CreateAddlHeaderRow();
});
Expand Down
2 changes: 1 addition & 1 deletion examples/example-frozen-columns-and-column-group.html
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,7 @@ <h2>View Source:</h2>

for (let i = start; i < end; i++) {
m = columns[i];
if (m) {
if (m && !m.hidden) {
if (lastColumnGroup === m.columnGroup && i>start) {
widthTotal += m.width;
header.style.width = `${widthTotal - headerColumnWidthDiff}px`;
Expand Down
4 changes: 3 additions & 1 deletion examples/example-multi-grid-basic.html
Original file line number Diff line number Diff line change
Expand Up @@ -94,7 +94,9 @@ <h2>View Source:</h2>

// Create 2nd Grid with its own ColumnPicker/GridMenu
var data02 = CreateData();
var columns02 = columns.slice(0);
var columns02 = columns.map(function(column) {
return Slick.Utils.extend(true, {}, column);
});
var options02 = Slick.Utils.extend({}, options);
grid02 = new Slick.Grid("#myGrid02", data02, columns02, options02);
new Slick.Controls.ColumnPicker(columns02, grid02, options02);
Expand Down
2 changes: 1 addition & 1 deletion examples/example-variable-row-height-frozen.html
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ <h2>Controls</h2>
<button onclick="runChecks()">Run frozen geometry self-checks</button>
<button onclick="growRowA()">A: grow row 2 by 10px (invalidateRowHeights)</button>
<button onclick="growFrozenRowB()">B: grow frozen row 0 by 10px (invalidateRowHeights)</button>
<button onclick="gridA.scrollRowToTop(300); gridB.scrollRowToTop(300);">Scroll both to row 300 (top)</button>
<button onclick="gridA.scrollRowToTop(300); gridB.scrollRowToTop(300);">Scroll both to row 300</button>
<div id="checkResults" style="white-space:pre; font-family:monospace; font-size:12px; margin-top:8px;"></div>
</div>
</div>
Expand Down
Loading
Loading