diff --git a/.eslintrc b/.eslintrc
index 73cd4ae56..ddda4685d 100644
--- a/.eslintrc
+++ b/.eslintrc
@@ -39,6 +39,7 @@
"@typescript-eslint/no-empty-function": "off",
"@typescript-eslint/no-explicit-any": "off",
"@typescript-eslint/no-non-null-assertion": "off",
+ "@typescript-eslint/no-inferrable-types": "error",
"@typescript-eslint/no-unused-vars": ["error", { "argsIgnorePattern": "^_", "destructuredArrayIgnorePattern": "^_" }],
"@typescript-eslint/quotes": ["error", "single", { "allowTemplateLiterals": true }],
"@typescript-eslint/semi": "error",
diff --git a/.husky/pre-push b/.husky/pre-push
new file mode 100644
index 000000000..3867a0feb
--- /dev/null
+++ b/.husky/pre-push
@@ -0,0 +1 @@
+npm run lint
diff --git a/.prettierignore b/.prettierignore
new file mode 100644
index 000000000..fa29cdfff
--- /dev/null
+++ b/.prettierignore
@@ -0,0 +1 @@
+**
\ No newline at end of file
diff --git a/examples/vite-demo-vanilla-bundle/src/examples/example19.html b/examples/vite-demo-vanilla-bundle/src/examples/example19.html
index 95581f7d2..759f9ac72 100644
--- a/examples/vite-demo-vanilla-bundle/src/examples/example19.html
+++ b/examples/vite-demo-vanilla-bundle/src/examples/example19.html
@@ -18,8 +18,10 @@
- Grid - using enableExcelCopyBuffer
which uses SlickCellSelectionModel
- The complete first row and the cells C - E of the second row are not allowing to paste values.
+ Grid - using enableExcelCopyBuffer
which uses SlickCellSelectionModel
+ The complete first row and the cells C - E of the second row are not allowing to paste values.
+ Additionally the columns are configured to exportWithFormatter
and a custom formatter that renders the cells coordinates or value if available.
+ When selecting one or more cells and pressing CTRL + C, the ExcelCopyBuffer will be filled with the formatter outputs of the selected cells.
{
+ if (value !== null && value !== undefined) {
+ return value;
+ }
+
+ return `${row + 1}:${cell + 1}`;
+ },
width: 60,
editor: { model: Editors.text }
});
diff --git a/package.json b/package.json
index 180cf9525..feae8cef6 100644
--- a/package.json
+++ b/package.json
@@ -45,7 +45,8 @@
"lint": "eslint packages --ext .ts",
"test": "jest --runInBand --coverage=true --config ./test/jest.config.ts",
"test:ci": "jest --runInBand --coverage=true --ci --config ./test/jest.config.ts",
- "test:watch": "cross-env TZ='America/New_York' jest --watch --config ./test/jest.config.ts"
+ "test:watch": "cross-env TZ='America/New_York' jest --watch --config ./test/jest.config.ts",
+ "prepare": "husky"
},
"comments": {
"new-version": "To create a new version with Lerna-Lite, simply run the following script (1) 'roll-new-release'.",
@@ -74,6 +75,7 @@
"eslint-plugin-import": "^2.29.1",
"eslint-plugin-node": "^11.1.0",
"flatpickr": "^4.6.13",
+ "husky": "^9.0.10",
"jest": "^29.7.0",
"jest-cli": "^29.7.0",
"jest-environment-jsdom": "^29.7.0",
@@ -95,9 +97,5 @@
"funding": {
"type": "ko_fi",
"url": "https://ko-fi.com/ghiscoding"
- },
- "prettier": {
- "singleQuote": true,
- "printWidth": 120
}
}
\ No newline at end of file
diff --git a/packages/common/src/core/slickCore.ts b/packages/common/src/core/slickCore.ts
index 4d10bf3ad..1d31195ff 100644
--- a/packages/common/src/core/slickCore.ts
+++ b/packages/common/src/core/slickCore.ts
@@ -447,7 +447,7 @@ export class SlickGroup extends SlickNonDataItem {
* @property groupingKey
* @type {Object}
*/
- groupingKey: string = '';
+ groupingKey = '';
constructor() {
super();
diff --git a/packages/common/src/core/slickDataview.ts b/packages/common/src/core/slickDataview.ts
index e978116cf..85f10068a 100644
--- a/packages/common/src/core/slickDataview.ts
+++ b/packages/common/src/core/slickDataview.ts
@@ -1040,7 +1040,7 @@ export class SlickDataView implements CustomD
return retval;
}
- protected compileFilter(stopRunningIfCSPSafeIsActive: boolean = false): FilterFn | null {
+ protected compileFilter(stopRunningIfCSPSafeIsActive = false): FilterFn | null {
if (stopRunningIfCSPSafeIsActive) {
return null;
}
@@ -1081,7 +1081,7 @@ export class SlickDataView implements CustomD
return fn;
}
- protected compileFilterWithCaching(stopRunningIfCSPSafeIsActive: boolean = false): FilterFn | null {
+ protected compileFilterWithCaching(stopRunningIfCSPSafeIsActive = false): FilterFn | null {
if (stopRunningIfCSPSafeIsActive) {
return null;
}
diff --git a/packages/common/src/extensions/__tests__/slickCellExcelCopyManager.spec.ts b/packages/common/src/extensions/__tests__/slickCellExcelCopyManager.spec.ts
index 8555a59ed..283a25993 100644
--- a/packages/common/src/extensions/__tests__/slickCellExcelCopyManager.spec.ts
+++ b/packages/common/src/extensions/__tests__/slickCellExcelCopyManager.spec.ts
@@ -1,10 +1,10 @@
import type { EditCommand, Formatter, GridOption } from '../../interfaces/index';
-import { Formatters } from '../../formatters';
import { SharedService } from '../../services/shared.service';
import { SlickCellExcelCopyManager } from '../slickCellExcelCopyManager';
import { SlickCellSelectionModel } from '../slickCellSelectionModel';
import { SlickCellExternalCopyManager } from '../slickCellExternalCopyManager';
import { SlickEvent, SlickEventData, SlickGrid, SlickRange } from '../../core/index';
+import { Editors } from '../../editors';
jest.mock('flatpickr', () => { });
@@ -17,6 +17,8 @@ const gridStub = {
getData: jest.fn(),
getOptions: jest.fn(),
getSelectionModel: jest.fn(),
+ getActiveCell: jest.fn(),
+ getCellEditor: jest.fn(),
getEditorLock: () => getEditorLockMock,
focus: jest.fn(),
registerPlugin: jest.fn(),
@@ -356,14 +358,36 @@ describe('CellExcelCopyManager', () => {
expect(output).toBe('John');
});
- it('should return null when calling "dataItemColumnValueExtractor" callback without editable', () => {
+ it('should return null when calling "dataItemColumnValueExtractor" callback with editable and editor, which is active on the current cell', () => {
+ jest.spyOn(gridStub, 'getOptions').mockReturnValue(gridOptionsMock);
+ plugin.init(gridStub);
+ (gridStub.getCellEditor as jest.Mock).mockReturnValue({});
+ (gridStub.getActiveCell as jest.Mock).mockReturnValue({ row: 6, cell: 6 });
+
+ const output = plugin.addonOptions!.dataItemColumnValueExtractor!({ firstName: 'John ', lastName: 'Doe' }, { id: 'firstName', field: 'firstName', exportWithFormatter: true, editor: { model: Editors.text }, formatter: myBoldFormatter}, 6, 6);
+
+ expect(output).toBeNull();
+ });
+
+ it('should forward provided row and cell to formatter when calling "dataItemColumnValueExtractor"', () => {
+ jest.spyOn(SharedService.prototype, 'gridOptions', 'get').mockReturnValue(gridOptionsMock);
+ plugin.init(gridStub);
+
+ const rowCellFormatter: Formatter = (row, cell) => `${row}:${cell}`;
+ const output = plugin.addonOptions!.dataItemColumnValueExtractor!({ firstName: 'John ', lastName: 'Doe' }, { id: 'firstName', field: 'firstName', exportWithFormatter: true, formatter: rowCellFormatter }, 6, 6);
+
+ expect(output).toBe('6:6');
+ });
+
+ it('should format output even if not editable and an editor is configured but a formatter is defined', () => {
gridOptionsMock.editable = false;
jest.spyOn(SharedService.prototype, 'gridOptions', 'get').mockReturnValue(gridOptionsMock);
plugin.init(gridStub);
- const output = plugin.addonOptions!.dataItemColumnValueExtractor!({ firstName: 'John ', lastName: 'Doe' }, { id: 'firstName', field: 'firstName' });
+ const rowCellFormatter: Formatter = (row, cell) => `${row}:${cell}`;
+ const output = plugin.addonOptions!.dataItemColumnValueExtractor!({ firstName: 'John ', lastName: 'Doe' }, { id: 'firstName', field: 'firstName', exportWithFormatter: true, editor: { model: Editors.text }, formatter: rowCellFormatter }, 6, 6);
- expect(output).toBeNull();
+ expect(output).toBe('6:6');
});
});
});
\ No newline at end of file
diff --git a/packages/common/src/extensions/slickCellExcelCopyManager.ts b/packages/common/src/extensions/slickCellExcelCopyManager.ts
index a1fa1a736..2a4a141d9 100644
--- a/packages/common/src/extensions/slickCellExcelCopyManager.ts
+++ b/packages/common/src/extensions/slickCellExcelCopyManager.ts
@@ -142,13 +142,16 @@ export class SlickCellExcelCopyManager {
clipboardCommandHandler: (editCommand: EditCommand) => {
this._undoRedoBuffer.queueAndExecuteCommand.call(this._undoRedoBuffer, editCommand);
},
- dataItemColumnValueExtractor: (item: any, columnDef: Column) => {
+ dataItemColumnValueExtractor: (item: any, columnDef: Column, row = 0, cell = 0) => {
// when grid or cell is not editable, we will possibly evaluate the Formatter if it was passed
// to decide if we evaluate the Formatter, we will use the same flag from Export which is "exportWithFormatter"
- if (!this.gridOptions.editable || !columnDef.editor) {
+ const activeCell = this._grid.getActiveCell();
+ const isActiveEditorCurrentCell = this._grid.getCellEditor() && activeCell?.row === row && activeCell?.cell === cell;
+
+ if (!this.gridOptions.editable || !columnDef.editor || !isActiveEditorCurrentCell) {
const isEvaluatingFormatter = (columnDef.exportWithFormatter !== undefined) ? columnDef.exportWithFormatter : (this.gridOptions.textExportOptions?.exportWithFormatter);
if (columnDef.formatter && isEvaluatingFormatter) {
- const formattedOutput = columnDef.formatter(0, 0, item[columnDef.field], columnDef, item, this._grid);
+ const formattedOutput = columnDef.formatter(row, cell, item[columnDef.field], columnDef, item, this._grid);
const cellResult = isPrimitiveOrHTML(formattedOutput) ? formattedOutput : (formattedOutput as FormatterResultWithHtml).html || (formattedOutput as FormatterResultWithText).text;
if (columnDef.sanitizeDataExport || (this.gridOptions.textExportOptions?.sanitizeDataExport)) {
const outputString = (cellResult instanceof HTMLElement) ? cellResult.innerHTML : cellResult as string;
diff --git a/packages/common/src/extensions/slickCellExternalCopyManager.ts b/packages/common/src/extensions/slickCellExternalCopyManager.ts
index ebb73d0f5..d22872538 100644
--- a/packages/common/src/extensions/slickCellExternalCopyManager.ts
+++ b/packages/common/src/extensions/slickCellExternalCopyManager.ts
@@ -115,9 +115,9 @@ export class SlickCellExternalCopyManager {
return getHtmlStringOutput(columnDef.name || '', 'innerHTML');
}
- getDataItemValueForColumn(item: any, columnDef: Column, event: SlickEventData) {
+ getDataItemValueForColumn(item: any, columnDef: Column, row: number, cell: number, event: SlickEventData) {
if (typeof this._addonOptions.dataItemColumnValueExtractor === 'function') {
- const val = this._addonOptions.dataItemColumnValueExtractor(item, columnDef) as string | HTMLElement;
+ const val = this._addonOptions.dataItemColumnValueExtractor(item, columnDef, row, cell) as string | HTMLElement;
if (val) {
return (val instanceof HTMLElement) ? stripTags(val.innerHTML) : val;
}
@@ -433,7 +433,7 @@ export class SlickCellExternalCopyManager {
? stripTags((columns[j].name as HTMLElement).innerHTML)
: columns[j].name as string;
if (colName.length > 0 && !columns[j].hidden) {
- clipTextCells.push(this.getDataItemValueForColumn(dt, columns[j], e));
+ clipTextCells.push(this.getDataItemValueForColumn(dt, columns[j], i, j, e));
}
}
clipTextRows.push(clipTextCells.join('\t'));
diff --git a/packages/common/src/interfaces/excelCopyBufferOption.interface.ts b/packages/common/src/interfaces/excelCopyBufferOption.interface.ts
index 09e2002a0..5cc7d89fa 100644
--- a/packages/common/src/interfaces/excelCopyBufferOption.interface.ts
+++ b/packages/common/src/interfaces/excelCopyBufferOption.interface.ts
@@ -17,7 +17,7 @@ export interface ExcelCopyBufferOption {
copiedCellStyleLayerKey?: string;
/** option to specify a custom column value extractor function */
- dataItemColumnValueExtractor?: (item: any, columnDef: Column) => string | HTMLElement | DocumentFragment | FormatterResultWithHtml | FormatterResultWithText | null;
+ dataItemColumnValueExtractor?: (item: any, columnDef: Column, row?: number, cell?: number) => string | HTMLElement | DocumentFragment | FormatterResultWithHtml | FormatterResultWithText | null;
/** option to specify a custom column value setter function */
dataItemColumnValueSetter?: (item: any, columnDef: Column, value: any) => string | FormatterResultWithHtml | FormatterResultWithText | null;
diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml
index 518ed7ead..4d0ef6ecf 100644
--- a/pnpm-lock.yaml
+++ b/pnpm-lock.yaml
@@ -62,6 +62,9 @@ importers:
flatpickr:
specifier: ^4.6.13
version: 4.6.13
+ husky:
+ specifier: ^9.0.10
+ version: 9.0.10
jest:
specifier: ^29.7.0
version: 29.7.0(@types/node@20.11.16)(ts-node@10.9.2)
@@ -5277,6 +5280,12 @@ packages:
engines: {node: '>=16.17.0'}
dev: true
+ /husky@9.0.10:
+ resolution: {integrity: sha512-TQGNknoiy6bURzIO77pPRu+XHi6zI7T93rX+QnJsoYFf3xdjKOur+IlfqzJGMHIK/wXrLg+GsvMs8Op7vI2jVA==}
+ engines: {node: '>=18'}
+ hasBin: true
+ dev: true
+
/iconv-lite@0.4.24:
resolution: {integrity: sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==}
engines: {node: '>=0.10.0'}