Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

chore: add CSP header example, backported from PR #884 #891

Merged
merged 3 commits into from
Oct 30, 2023
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
1 change: 1 addition & 0 deletions cypress/integration/example-colspan.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ describe('Example - Column Span & Header Grouping', { retries: 1 }, () => {
it('should display Example title', () => {
cy.visit(`${Cypress.config('baseExampleUrl')}/example-colspan.html`);
cy.get('h2').contains('Demonstrates');
cy.get('h2 + ul > li').first().contains('column span');
});

it('should have exact column titles', () => {
Expand Down
52 changes: 52 additions & 0 deletions cypress/integration/example-csp-header.spec.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
describe('Example CSP Header - with Column Span & Header Grouping', () => {
// NOTE: everywhere there's a * 2 is because we have a top+bottom (frozen rows) containers even after Unfreeze Columns/Rows
const GRID_ROW_HEIGHT = 25;
const fullTitles = ['Title', 'Duration', '% Complete', 'Start', 'Finish', 'Effort Driven'];
for (let i = 0; i < 30; i++) {
fullTitles.push(`Mock${i}`);
}

beforeEach(() => {
// create a console.log spy for later use
cy.window().then((win) => {
cy.spy(win.console, "log");
});
});

it('should display Example title', () => {
cy.visit(`${Cypress.config('baseExampleUrl')}/example-csp-header.html`);
cy.get('h2').contains('Demonstrates');
cy.get('h2 + ul > li').first().contains('column span');
});

it('should have exact column titles', () => {
cy.get('#myGrid')
.find('.slick-header-columns')
.children()
.each(($child, index) => expect($child.text()).to.eq(fullTitles[index]));
});

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: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:nth(1)`).should('contain', '5 days');
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)/);
});

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: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)/);
});
});
44 changes: 44 additions & 0 deletions examples/example-csp-header.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
<!DOCTYPE HTML>
<html>
<head>
<link rel="shortcut icon" type="image/ico" href="favicon.ico" />
<link rel="stylesheet" href="../slick.grid.css" type="text/css"/>
<link rel="stylesheet" href="examples.css" type="text/css"/>
<!-- <meta http-equiv="Content-Security-Policy" content="default-src 'self' https://cdn.jsdelivr.net 'nonce-random-string' 'nonce-browser-sync'; require-trusted-types-for 'script'; trusted-types dompurify"> -->
<meta http-equiv="Content-Security-Policy" content="require-trusted-types-for 'script'; trusted-types dompurify">
</head>
<body>
<table width="100%">
<tr>
<td valign="top" width="50%">
<div id="myGrid"></div>
</td>
<td valign="top">
<h2>
<a href="/examples/index.html" id="link">&#x2302;</a>
Demonstrates:
</h2>
<ul>
<li>column span</li>
</ul>
<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>
</ul>
</td>
</tr>
</table>

<script src="https://cdn.jsdelivr.net/npm/sortablejs/Sortable.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/dompurify@3.0.6/dist/purify.min.js"></script>
<!-- <script src="./example-csp-policy.js"></script> -->

<script src="../slick.core.js"></script>
<script src="../slick.interactions.js"></script>
<script src="../slick.grid.js"></script>
<script src="../plugins/slick.cellrangedecorator.js"></script>
<script src="../plugins/slick.cellrangeselector.js"></script>
<script src="../plugins/slick.cellselectionmodel.js"></script>
<script src="./example-csp-header.js"></script>
</body>
</html>
61 changes: 61 additions & 0 deletions examples/example-csp-header.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
document.addEventListener("DOMContentLoaded", function () {
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 }
];

var options = {
enableCellNavigation: true,
enableColumnReorder: false,
sanitizer: (html) => window.DOMPurify.sanitize(html, { RETURN_TRUSTED_TYPE: true })
};
let gridElement = document.getElementById("myGrid");
gridElement.style.width = "600px";
gridElement.style.height = "500px";

let linkElement = document.getElementById("link");
//text-decoration: none; font-size: 22px
linkElement.style.textDecoration = "none";
linkElement.style.fontSize = "22px";

var data = [];
for (var i = 0; i < 500; i++) {
data[i] = {
title: "Task " + i,
duration: "5 days",
percentComplete: Math.round(Math.random() * 100),
start: "01/01/2009",
finish: "01/05/2009",
effortDriven: (i % 5 === 0)
};
}

data.getItemMetadata = function (row) {
if (row % 2 === 1) {
return {
"columns": {
"duration": {
"colspan": 3
}
}
};
} else {
return {
"columns": {
0: {
"colspan": "*"
}
}
};
}
};

grid = new Slick.Grid("#myGrid", data, columns, options);

grid.setSelectionModel(new Slick.CellSelectionModel());
});
13 changes: 9 additions & 4 deletions examples/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -79,10 +79,15 @@ <h2>Grouping</h2>
<h2>Other Features</h2>
<div>
<ul>
<li><a href="example-explicit-initialization.html">Explicit initialization</a></li>
<li><a href="example9-row-reordering.html">Row selection &amp; reordering</a></li>
<li><a href="example10-async-post-render.html">Using background post-rendering to add graphs</a></li>
<li><a href="example10-async-post-render-cleanup.html">Background post-rendering with async cleanup</a></li>
<li><a href="./example-explicit-initialization.html">Explicit initialization</a></li>
<li><a href="./example9-row-reordering.html">Row selection &amp; reordering</a></li>
<li><a href="./example9-row-reordering-simple.html">Row reordering (simple example without delete)</a></li>
<li><a href="./example10-async-post-render.html">Using background post-rendering to add graphs</a></li>
<li><a href="./example10a-async-post-render-cleanup.html">Background post-rendering with async cleanup</a></li>
<li><a href="./example-auto-scroll-when-dragging.html">Auto scroll when dragging</a></li>
<li><a href="./example-column-hidden.html">Grid with Hidden Columns</a></li>
<li><a href="./example-frozen-columns-and-column-group-hidden-col.html">Frozen Grid with Hidden Columns</a></li>
<li><a href="./example-csp-header.html">CSP Header (Content Security Policy)</a></li>
</ul>
</div>
<h2>Bootstrap, Dynamic Grids and Third Party component editors</h2>
Expand Down
15 changes: 10 additions & 5 deletions slick.grid.js
Original file line number Diff line number Diff line change
Expand Up @@ -1287,7 +1287,8 @@ if (typeof Slick === "undefined") {
const headerRowTarget = hasFrozenColumns() ? ((i <= options.frozenColumn) ? _headerRowL : _headerRowR) : _headerRowL;

const header = utils.createDomElement('div', { id: `${uid + m.id}`, dataset: { id: m.id }, className: 'ui-state-default slick-header-column', title: m.toolTip || '' }, headerTarget);
utils.createDomElement('span', { className: 'slick-column-name', innerHTML: sanitizeHtmlString(m.name) }, header);
const colNameElm = utils.createDomElement('span', { className: 'slick-column-name' }, header);
colNameElm.innerHTML = sanitizeHtmlString(m.name);
utils.width(header, m.width - headerColumnWidthDiff);

let classname = m.headerCssClass || null;
Expand Down Expand Up @@ -2743,7 +2744,8 @@ if (typeof Slick === "undefined") {
// headers have not yet been created, create a new node
let header = getHeader(columnDef);
headerColEl = utils.createDomElement('div', { id: dummyHeaderColElId, className: 'ui-state-default slick-header-column', }, header);
utils.createDomElement('span', { className: 'slick-column-name', innerHTML: sanitizeHtmlString(columnDef.name) }, headerColEl);
const colNameElm = utils.createDomElement('span', { className: 'slick-column-name' }, headerColEl);
colNameElm.innerHTML = sanitizeHtmlString(columnDef.name);
clone.style.cssText = 'position: absolute; visibility: hidden;right: auto;text-overflow: initial;white-space: nowrap;';
if (columnDef.headerCssClass) {
headerColEl.classList.add(...columnDef.headerCssClass.split(' '));
Expand Down Expand Up @@ -4125,7 +4127,8 @@ if (typeof Slick === "undefined") {
return;
}

var x = utils.createDomElement('div', { innerHTML: sanitizeHtmlString(stringArray.join('')) });
var x = document.createElement('div');
x.innerHTML = sanitizeHtmlString(stringArray.join(''));
var processedRow;
var node;
while ((processedRow = processedRows.pop()) != null) {
Expand Down Expand Up @@ -4185,8 +4188,10 @@ if (typeof Slick === "undefined") {

if (!rows.length) { return; }

let x = utils.createDomElement('div', { innerHTML: sanitizeHtmlString(stringArrayL.join('')) });
let xRight = utils.createDomElement('div', { innerHTML: sanitizeHtmlString(stringArrayR.join('')) });
const x = document.createElement('div');
const xRight = document.createElement('div');
x.innerHTML = sanitizeHtmlString(stringArrayL.join(''));
xRight.innerHTML = sanitizeHtmlString(stringArrayR.join(''));

for (var i = 0, ii = rows.length; i < ii; i++) {
if (( hasFrozenRows ) && ( rows[i] >= actualFrozenRow )) {
Expand Down