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

make "ctrl + c" great again #1379

Merged
merged 9 commits into from
Feb 8, 2024
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 .eslintrc
Original file line number Diff line number Diff line change
Expand Up @@ -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",
ghiscoding marked this conversation as resolved.
Show resolved Hide resolved
"@typescript-eslint/no-unused-vars": ["error", { "argsIgnorePattern": "^_", "destructuredArrayIgnorePattern": "^_" }],
"@typescript-eslint/quotes": ["error", "single", { "allowTemplateLiterals": true }],
"@typescript-eslint/semi": "error",
Expand Down
1 change: 1 addition & 0 deletions .husky/pre-push
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
npm run lint
1 change: 1 addition & 0 deletions .prettierignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
**
6 changes: 4 additions & 2 deletions examples/vite-demo-vanilla-bundle/src/examples/example19.html
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,10 @@ <h3 class="title is-3">
</h3>

<h5 class="title is-5 mb-3">
Grid - using <code>enableExcelCopyBuffer</code> which uses <code>SlickCellSelectionModel</code><br />
The complete first row and the cells C - E of the second row are not allowing to paste values.
<p>Grid - using <code>enableExcelCopyBuffer</code> which uses <code>SlickCellSelectionModel</code></p>
<p>The complete first row and the cells C - E of the second row are not allowing to paste values. </p>
<p>Additionally the columns are configured to <code>exportWithFormatter</code> 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.</p>
</h5>
<h6 class="title is-6">
<button class="button is-small is-primary" onclick.delegate="togglePagination()"
Expand Down
8 changes: 8 additions & 0 deletions examples/vite-demo-vanilla-bundle/src/examples/example19.ts
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,14 @@ export default class Example19 {
: String.fromCharCode('A'.charCodeAt(0) + (Math.floor(i / 26)) - 1) + String.fromCharCode('A'.charCodeAt(0) + (i % 26)),
field: String(i),
minWidth: 60,
exportWithFormatter: true,
formatter: (row, cell, value) => {
if (value !== null && value !== undefined) {
return value;
}

return `${row + 1}:${cell + 1}`;
},
width: 60,
editor: { model: Editors.text }
});
Expand Down
8 changes: 3 additions & 5 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -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'.",
Expand Down Expand Up @@ -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",
Expand All @@ -95,9 +97,5 @@
"funding": {
"type": "ko_fi",
"url": "https://ko-fi.com/ghiscoding"
},
"prettier": {
"singleQuote": true,
"printWidth": 120
}
}
2 changes: 1 addition & 1 deletion packages/common/src/core/slickCore.ts
Original file line number Diff line number Diff line change
Expand Up @@ -447,7 +447,7 @@ export class SlickGroup extends SlickNonDataItem {
* @property groupingKey
* @type {Object}
*/
groupingKey: string = '';
groupingKey = '';

constructor() {
super();
Expand Down
4 changes: 2 additions & 2 deletions packages/common/src/core/slickDataview.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1040,7 +1040,7 @@ export class SlickDataView<TData extends SlickDataItem = any> implements CustomD
return retval;
}

protected compileFilter(stopRunningIfCSPSafeIsActive: boolean = false): FilterFn<TData> | null {
protected compileFilter(stopRunningIfCSPSafeIsActive = false): FilterFn<TData> | null {
if (stopRunningIfCSPSafeIsActive) {
return null;
}
Expand Down Expand Up @@ -1081,7 +1081,7 @@ export class SlickDataView<TData extends SlickDataItem = any> implements CustomD
return fn;
}

protected compileFilterWithCaching(stopRunningIfCSPSafeIsActive: boolean = false): FilterFn<TData> | null {
protected compileFilterWithCaching(stopRunningIfCSPSafeIsActive = false): FilterFn<TData> | null {
if (stopRunningIfCSPSafeIsActive) {
return null;
}
Expand Down
Original file line number Diff line number Diff line change
@@ -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', () => { });

Expand All @@ -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(),
Expand Down Expand Up @@ -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: '<b>John</b>', 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: '<b>John</b>', 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: '<b>John</b>', lastName: 'Doe' }, { id: 'firstName', field: 'firstName' });
const rowCellFormatter: Formatter = (row, cell) => `${row}:${cell}`;
const output = plugin.addonOptions!.dataItemColumnValueExtractor!({ firstName: '<b>John</b>', lastName: 'Doe' }, { id: 'firstName', field: 'firstName', exportWithFormatter: true, editor: { model: Editors.text }, formatter: rowCellFormatter }, 6, 6);

expect(output).toBeNull();
expect(output).toBe('6:6');
});
});
});
9 changes: 6 additions & 3 deletions packages/common/src/extensions/slickCellExcelCopyManager.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}
Expand Down Expand Up @@ -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'));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ export interface ExcelCopyBufferOption<T = any> {
copiedCellStyleLayerKey?: string;

/** option to specify a custom column value extractor function */
dataItemColumnValueExtractor?: (item: any, columnDef: Column<T>) => string | HTMLElement | DocumentFragment | FormatterResultWithHtml | FormatterResultWithText | null;
dataItemColumnValueExtractor?: (item: any, columnDef: Column<T>, row?: number, cell?: number) => string | HTMLElement | DocumentFragment | FormatterResultWithHtml | FormatterResultWithText | null;

/** option to specify a custom column value setter function */
dataItemColumnValueSetter?: (item: any, columnDef: Column<T>, value: any) => string | FormatterResultWithHtml | FormatterResultWithText | null;
Expand Down
9 changes: 9 additions & 0 deletions pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading