Skip to content

Commit

Permalink
feat(plugins): move external cell related plugins to universal
Browse files Browse the repository at this point in the history
  • Loading branch information
ghiscoding committed Oct 1, 2021
1 parent 1bbf56f commit 11e15d8
Show file tree
Hide file tree
Showing 18 changed files with 1,061 additions and 513 deletions.
Expand Up @@ -63,6 +63,12 @@ export class Example13 {
container: '.demo-container',
},
enableFiltering: false,
enableExcelCopyBuffer: true,
excelCopyBufferOptions: {
onCopyCells: (e, args) => console.log(e, args),
onPasteCells: (e, args) => console.log(e, args),
onCopyCancelled: (e, args) => console.log(e, args),
},
enableCellNavigation: true,
gridHeight: 275,
headerButton: {
Expand Down
8 changes: 7 additions & 1 deletion packages/common/src/enums/slickPluginList.enum.ts
Expand Up @@ -15,7 +15,13 @@ import {
SlickRowMoveManager,
SlickRowSelectionModel,
} from '../interfaces/index';
import { AutoTooltipPlugin } from '../plugins/index';
import {
AutoTooltipPlugin,
// CellExternalCopyManager,
// CellRangeDecorator,
// CellRangeSelector,
// CellSelectionModel,
} from '../plugins/index';

export type SlickPluginList =
AutoTooltipPlugin |
Expand Down

This file was deleted.

1 change: 0 additions & 1 deletion packages/common/src/extensions/index.ts
@@ -1,4 +1,3 @@
export * from './cellExternalCopyManagerExtension';
export * from './checkboxSelectorExtension';
export * from './extensionUtility';
export * from './rowDetailViewExtension';
Expand Down
Expand Up @@ -2,9 +2,9 @@ import {
Column,
CellRange,
FormatterResultObject,
SlickCellExternalCopyManager,
SlickEventData,
} from './index';
import { CellExcelCopyManager, } from '../plugins/cellExcelCopyManager';

export interface ExcelCopyBufferOption<T = any> {
/** defaults to "copied", sets the css className used for copied cells. */
Expand Down Expand Up @@ -48,7 +48,7 @@ export interface ExcelCopyBufferOption<T = any> {
// ------------

/** Fired after extension (plugin) is registered by SlickGrid */
onExtensionRegistered?: (plugin: SlickCellExternalCopyManager) => void;
onExtensionRegistered?: (plugin: CellExcelCopyManager) => void;

/** Fired when a copy cell is triggered */
onCopyCells?: (e: SlickEventData, args: { ranges: CellRange[] }) => void;
Expand Down
@@ -1,6 +1,7 @@
import { SlickCellRangeDecorator, SlickGrid, SlickRange } from './index';
import { CellRange } from './cellRange.interface';
import { SlickEvent } from './slickEvent.interface';
// import { CellRangeDecorator, } from '../plugins/slickCellRangeDecorator';

export interface SlickCellRangeSelector {
pluginName: 'CellRangeSelector'
Expand Down
34 changes: 8 additions & 26 deletions packages/common/src/interfaces/slickRange.interface.ts
Expand Up @@ -12,33 +12,15 @@ export interface SlickRange extends CellRange {
*/
constructor: (fromRow: number, fromCell: number, toRow: number, toCell: number) => void;

/**
* Returns whether a range contains a given cell.
* @method contains
* @param row {Integer}
* @param cell {Integer}
* @return {Boolean}
*/
contains?: (row: number, cell: number) => boolean;
/** Returns whether a range represents a single row. */
isSingleRow: () => boolean;

/**
* Returns whether a range represents a single cell.
* @method isSingleCell
* @return {Boolean}
*/
isSingleCell?: () => boolean;
/** Returns whether a range represents a single cell. */
isSingleCell: () => boolean;

/**
* Returns whether a range represents a single row.
* @method isSingleRow
* @return {Boolean}
*/
isSingleRow?: () => boolean;
/** Returns whether a range contains a given cell. */
contains: (row: number, cell: number) => boolean;

/**
* Returns a readable representation of a range.
* @method toString
* @return {String}
*/
toString?: () => string;
/** Returns a readable representation of a range. */
toString: () => string;
}
@@ -1,38 +1,44 @@
import 'slickgrid/plugins/slick.cellexternalcopymanager';

import {
// TypeScript Helper
GetSlickEventType,

Column,
EditCommand,
EditUndoRedoBuffer,
ExcelCopyBufferOption,
Extension,
SlickCellExternalCopyManager,
SlickCellSelectionModel,
GridOption,
SlickDataView,
SlickEventHandler,
SlickGrid,
SlickNamespace,

// TypeScript Helper
GetSlickEventType,
} from '../interfaces/index';
import { ExtensionUtility } from './extensionUtility';
import { BindingEventService } from '../services/bindingEvent.service';
import { SharedService } from '../services/shared.service';
import { sanitizeHtmlToText } from '../services/domUtilities';
import { CellExternalCopyManager, CellSelectionModel } from './index';

// using external SlickGrid JS libraries
declare const Slick: SlickNamespace;

export class CellExternalCopyManagerExtension implements Extension {
private _addon: SlickCellExternalCopyManager | null = null;
private _addonOptions: ExcelCopyBufferOption | null = null;
private _cellSelectionModel!: SlickCellSelectionModel;
private _eventHandler: SlickEventHandler;
private _commandQueue!: EditCommand[];
private _undoRedoBuffer!: EditUndoRedoBuffer;
private _bindingEventService: BindingEventService;

constructor(private readonly extensionUtility: ExtensionUtility, private readonly sharedService: SharedService) {
/*
This manager enables users to copy/paste data from/to an external Spreadsheet application
such as MS-Excel® or OpenOffice-Spreadsheet.
Since it is not possible to access directly the clipboard in javascript, the plugin uses
a trick to do it's job. After detecting the keystroke, we dynamically create a textarea
where the browser copies/pastes the serialized data.
*/
export class CellExcelCopyManager {
protected _addonOptions!: ExcelCopyBufferOption;
protected _bindingEventService: BindingEventService;
protected _cellExternalCopyManagerPlugin!: CellExternalCopyManager;
protected _cellSelectionModel!: CellSelectionModel;
protected _commandQueue!: EditCommand[];
protected _eventHandler: SlickEventHandler;
protected _grid!: SlickGrid;
protected _undoRedoBuffer!: EditUndoRedoBuffer;
pluginName = 'CellExcelCopyManager';

constructor() {
this._eventHandler = new Slick.EventHandler() as SlickEventHandler;
this._bindingEventService = new BindingEventService();
}
Expand All @@ -49,74 +55,58 @@ export class CellExternalCopyManagerExtension implements Extension {
return this._commandQueue;
}

get undoRedoBuffer(): EditUndoRedoBuffer {
return this._undoRedoBuffer;
}

/** Dispose of the 3rd party addon (plugin) */
dispose() {
// unsubscribe all SlickGrid events
this._eventHandler.unsubscribeAll();
if (this._addon && this._addon.destroy) {
this._addon.destroy();
}
if (this._cellSelectionModel?.destroy) {
this._cellSelectionModel.destroy();
}
this.extensionUtility.nullifyFunctionNameStartingWithOn(this._addonOptions);
this._addonOptions = null;
this._bindingEventService.unbindAll();
get gridOptions(): GridOption {
return this._grid?.getOptions?.() ?? {};
}

/** Get the instance of the SlickGrid addon (control or plugin). */
getAddonInstance(): SlickCellExternalCopyManager | null {
return this._addon;
get undoRedoBuffer(): EditUndoRedoBuffer {
return this._undoRedoBuffer;
}

/** Register the 3rd party addon (plugin) */
register(): SlickCellExternalCopyManager | null {
if (this.sharedService && this.sharedService.slickGrid && this.sharedService.gridOptions) {
this.createUndoRedoBuffer();
this._bindingEventService.bind(document.body, 'keydown', this.handleKeyDown.bind(this) as EventListener);

this._addonOptions = { ...this.getDefaultOptions(), ...this.sharedService.gridOptions.excelCopyBufferOptions } as ExcelCopyBufferOption;
this._cellSelectionModel = new Slick.CellSelectionModel() as SlickCellSelectionModel;
this.sharedService.slickGrid.setSelectionModel(this._cellSelectionModel);
this._addon = new Slick.CellExternalCopyManager(this._addonOptions);
if (this._addon) {
this.sharedService.slickGrid.registerPlugin<SlickCellExternalCopyManager>(this._addon);
init(grid: SlickGrid, options?: ExcelCopyBufferOption) {
this._grid = grid;
this.createUndoRedoBuffer();
this._cellSelectionModel = new CellSelectionModel();
this._grid.setSelectionModel(this._cellSelectionModel as any);
this._bindingEventService.bind(document.body, 'keydown', this.handleBodyKeyDown.bind(this) as EventListener);
this._addonOptions = { ...this.getDefaultOptions(), ...options } as ExcelCopyBufferOption;
this._cellExternalCopyManagerPlugin = new CellExternalCopyManager();
this._cellExternalCopyManagerPlugin.init(this._grid, this._addonOptions);

const onCopyCellsHandler = this._cellExternalCopyManagerPlugin.onCopyCells;
(this._eventHandler as SlickEventHandler<GetSlickEventType<typeof onCopyCellsHandler>>).subscribe(onCopyCellsHandler, (e, args) => {
if (this._addonOptions && typeof this._addonOptions.onCopyCells === 'function') {
this._addonOptions.onCopyCells(e, args);
}
});

// hook to all possible events
if (this.sharedService.slickGrid && this._addonOptions) {
if (this._addon && this._addonOptions.onExtensionRegistered) {
this._addonOptions.onExtensionRegistered(this._addon);
}
const onCopyCancelledHandler = this._cellExternalCopyManagerPlugin.onCopyCancelled;
(this._eventHandler as SlickEventHandler<GetSlickEventType<typeof onCopyCancelledHandler>>).subscribe(onCopyCancelledHandler, (e, args) => {
if (this._addonOptions && typeof this._addonOptions.onCopyCancelled === 'function') {
this._addonOptions.onCopyCancelled(e, args);
}
});

const onCopyCellsHandler = this._addon.onCopyCells;
(this._eventHandler as SlickEventHandler<GetSlickEventType<typeof onCopyCellsHandler>>).subscribe(onCopyCellsHandler, (e, args) => {
if (this._addonOptions && typeof this._addonOptions.onCopyCells === 'function') {
this._addonOptions.onCopyCells(e, args);
}
});
const onPasteCellsHandler = this._cellExternalCopyManagerPlugin.onPasteCells;
(this._eventHandler as SlickEventHandler<GetSlickEventType<typeof onPasteCellsHandler>>).subscribe(onPasteCellsHandler, (e, args) => {
if (this._addonOptions && typeof this._addonOptions.onPasteCells === 'function') {
this._addonOptions.onPasteCells(e, args);
}
});
}

const onCopyCancelledHandler = this._addon.onCopyCancelled;
(this._eventHandler as SlickEventHandler<GetSlickEventType<typeof onCopyCancelledHandler>>).subscribe(onCopyCancelledHandler, (e, args) => {
if (this._addonOptions && typeof this._addonOptions.onCopyCancelled === 'function') {
this._addonOptions.onCopyCancelled(e, args);
}
});
/** @deprecated @use `dispose` Destroy plugin. */
destroy() {
this.dispose();
}

const onPasteCellsHandler = this._addon.onPasteCells;
(this._eventHandler as SlickEventHandler<GetSlickEventType<typeof onPasteCellsHandler>>).subscribe(onPasteCellsHandler, (e, args) => {
if (this._addonOptions && typeof this._addonOptions.onPasteCells === 'function') {
this._addonOptions.onPasteCells(e, args);
}
});
}
return this._addon;
}
return null;
/** Dispose of the 3rd party addon (plugin) */
dispose() {
// unsubscribe all SlickGrid events
this._eventHandler.unsubscribeAll();
this._bindingEventService.unbindAll();
this._cellSelectionModel?.dispose();
this._cellExternalCopyManagerPlugin?.dispose();
}

/** Create an undo redo buffer used by the Excel like copy */
Expand Down Expand Up @@ -164,11 +154,11 @@ export class CellExternalCopyManagerExtension implements Extension {
dataItemColumnValueExtractor: (item: any, columnDef: Column) => {
// 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.sharedService.gridOptions.editable || !columnDef.editor) {
const textExportOptions = { ...this.sharedService.gridOptions.exportOptions, ...this.sharedService.gridOptions.textExportOptions };
if (!this.gridOptions.editable || !columnDef.editor) {
const textExportOptions = { ...this.gridOptions.exportOptions, ...this.gridOptions.textExportOptions };
const isEvaluatingFormatter = (columnDef.exportWithFormatter !== undefined) ? columnDef.exportWithFormatter : (textExportOptions?.exportWithFormatter);
if (columnDef.formatter && isEvaluatingFormatter) {
const formattedOutput = columnDef.formatter(0, 0, item[columnDef.field], columnDef, item, this.sharedService.slickGrid);
const formattedOutput = columnDef.formatter(0, 0, item[columnDef.field], columnDef, item, this._grid);
if (columnDef.sanitizeDataExport || (textExportOptions?.sanitizeDataExport)) {
let outputString = formattedOutput as string;
if (formattedOutput && typeof formattedOutput === 'object' && formattedOutput.hasOwnProperty('text')) {
Expand All @@ -191,14 +181,14 @@ export class CellExternalCopyManagerExtension implements Extension {
includeHeaderWhenCopying: false,
newRowCreator: (count: number) => {
for (let i = 0; i < count; i++) {
this.sharedService.slickGrid.getData<SlickDataView>().addItem({ id: `newRow_${newRowIds++}` });
this._grid.getData<SlickDataView>().addItem({ id: `newRow_${newRowIds++}` });
}
}
};
}

/** Hook an undo shortcut key hook that will redo/undo the copy buffer using Ctrl+(Shift)+Z keyboard events */
private handleKeyDown(e: KeyboardEvent) {
private handleBodyKeyDown(e: KeyboardEvent) {
const keyCode = e.keyCode || e.code;
if (keyCode === 90 && (e.ctrlKey || e.metaKey)) {
if (e.shiftKey) {
Expand All @@ -208,4 +198,4 @@ export class CellExternalCopyManagerExtension implements Extension {
}
}
}
}
}

0 comments on commit 11e15d8

Please sign in to comment.