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.
Original file line number Diff line number Diff line change
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
Original file line number Diff line number Diff line change
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
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
export * from './cellExternalCopyManagerExtension';
export * from './checkboxSelectorExtension';
export * from './extensionUtility';
export * from './rowDetailViewExtension';
Expand Down
Original file line number Diff line number Diff line change
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
Original file line number Diff line number Diff line change
@@ -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
Original file line number Diff line number Diff line change
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;
}
Original file line number Diff line number Diff line change
@@ -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 {
}
}
}
}
}
Loading

0 comments on commit 11e15d8

Please sign in to comment.