Skip to content

Commit

Permalink
feat: convert GroupItemMetadataProvider Formatter to native HTML for …
Browse files Browse the repository at this point in the history
…CSP (#925)

* feat: convert GroupItemMetadataProvider Formatter to native HTML for CSP
- in order to depend less on the use of `innerHTML`, we should convert internal code that have Formatter to use native HTML element to be more CSP compliant. However please note that the user will have to convert themselve the GroupTotals Formatter to native element as well for full CSP compliance on that section of the code
  • Loading branch information
ghiscoding authored Nov 24, 2023
1 parent b6d02cd commit 7ec4309
Show file tree
Hide file tree
Showing 2 changed files with 29 additions and 13 deletions.
6 changes: 3 additions & 3 deletions src/slick.grid.ts
Original file line number Diff line number Diff line change
Expand Up @@ -524,11 +524,11 @@ export class SlickGrid<TData = any, C extends Column<TData> = Column<TData>, O e
* @param target - target element to apply to
* @param val - input value can be either a string or an HTMLElement
*/
applyHtmlCode(target: HTMLElement, val: string | HTMLElement) {
applyHtmlCode(target: HTMLElement, val: string | HTMLElement | DocumentFragment) {
if (target) {
if (val instanceof HTMLElement) {
if (val instanceof HTMLElement || val instanceof DocumentFragment) {
target.appendChild(val);
} else {
} else if (typeof val === 'string') {
if (this._options.enableHtmlRendering) {
target.innerHTML = this.sanitizeHtmlString(val as string);
} else {
Expand Down
36 changes: 26 additions & 10 deletions src/slick.groupitemmetadataprovider.ts
Original file line number Diff line number Diff line change
Expand Up @@ -59,22 +59,38 @@ export class SlickGroupItemMetadataProvider {
Utils.extend(true, this._options, inputOptions);
}

protected defaultGroupCellFormatter(_row: number, _cell: number, _value: any, _columnDef: Column, item: any): string {
protected defaultGroupCellFormatter(_row: number, _cell: number, _value: any, _columnDef: Column, item: any) {
if (!this._options.enableExpandCollapse) {
return item.title;
}

const indentation = `${item.level * 15}px`;
const toggleClass = item.collapsed ? this._options.toggleCollapsedCssClass : this._options.toggleExpandedCssClass;

return (this._options.checkboxSelect ? '<span class="' + this._options.checkboxSelectCssClass +
' ' + (item.selectChecked ? 'checked' : 'unchecked') + '"></span>' : '') +
'<span class="' + this._options.toggleCssClass + ' ' +
(item.collapsed ? this._options.toggleCollapsedCssClass : this._options.toggleExpandedCssClass) +
'" style="margin-left:' + indentation + '">' +
'</span>' +
'<span class="' + this._options.groupTitleCssClass + '" level="' + item.level + '">' +
item.title +
'</span>';
// use a DocumentFragment to avoid creating an extra div container
const containerElm = document.createDocumentFragment();

// 1. optional row checkbox span to select the entire group rows
if (this._options.checkboxSelect) {
containerElm.appendChild(Utils.createDomElement('span', { className: `${this._options.checkboxSelectCssClass} ${item.selectChecked ? 'checked' : 'unchecked'}` }));
}

// 2. group toggle span
containerElm.appendChild(Utils.createDomElement('span', {
className: `${this._options.toggleCssClass} ${toggleClass}`,
ariaExpanded: String(!item.collapsed),
style: { marginLeft: indentation }
}));

// 3. group title span
const groupTitleElm = Utils.createDomElement('span', { className: this._options.groupTitleCssClass || '' });
groupTitleElm.setAttribute('level', item.level);
(item.title instanceof HTMLElement)
? groupTitleElm.appendChild(item.title)
: this._grid.applyHtmlCode(groupTitleElm, item.title ?? '');
containerElm.appendChild(groupTitleElm);

return containerElm;
}

protected defaultTotalsCellFormatter(_row: number, _cell: number, _value: any, columnDef: Column, item: any, grid: SlickGrid) {
Expand Down

0 comments on commit 7ec4309

Please sign in to comment.