Skip to content
This repository was archived by the owner on Jun 1, 2025. It is now read-only.
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
12 changes: 10 additions & 2 deletions src/app/examples/grid-formatter.component.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { Component, OnInit } from '@angular/core';
import { Column, FieldType, Formatter, Formatters, GridOption } from './../modules/angular-slickgrid';
import { Column, FieldType, Formatter, Formatters, GridOption, SelectedRange } from './../modules/angular-slickgrid';

// create my custom Formatter with the Formatter type
const myCustomCheckmarkFormatter: Formatter = (row, cell, value, columnDef, dataContext) => {
Expand Down Expand Up @@ -46,13 +46,21 @@ export class GridFormatterComponent implements OnInit {
},
enableAutoResize: true,
enableCellNavigation: true,
enableExcelCopyBuffer: true,

// you customize the date separator through "formatterOptions"
/*
formatterOptions: {
dateSeparator: '.'
},
*/

// when using the ExcelCopyBuffer, you can see what the selection range is
enableExcelCopyBuffer: true,
excelCopyBufferOptions: {
onCopyCells: (e, args: { ranges: SelectedRange[] }) => console.log('onCopyCells', args.ranges),
onPasteCells: (e, args: { ranges: SelectedRange[] }) => console.log('onPasteCells', args.ranges),
onCopyCancelled: (e, args: { ranges: SelectedRange[] }) => console.log('onCopyCancelled', args.ranges),
}
};

// mock a dataset
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { Injectable } from '@angular/core';
import { Column, Extension, ExtensionName } from '../models/index';
import { Column, ExcelCopyBufferOption, Extension, ExtensionName, SelectedRange } from '../models/index';
import { ExtensionUtility } from './extensionUtility';
import { sanitizeHtmlToText } from '../services/utilities';
import { SharedService } from '../services/shared.service';
Expand All @@ -10,12 +10,15 @@ declare var $: any;

@Injectable()
export class CellExternalCopyManagerExtension implements Extension {
private _eventHandler: any = new Slick.EventHandler();
private _extension: any;
private _undoRedoBuffer: any;

constructor(private extensionUtility: ExtensionUtility, private sharedService: SharedService) { }

dispose() {
// unsubscribe all SlickGrid events
this._eventHandler.unsubscribeAll();
if (this._extension && this._extension.destroy) {
this._extension.destroy();
}
Expand All @@ -27,49 +30,34 @@ export class CellExternalCopyManagerExtension implements Extension {
this.extensionUtility.loadExtensionDynamically(ExtensionName.cellExternalCopyManager);
this.createUndoRedoBuffer();
this.hookUndoShortcutKey();
let newRowIds = 0;
const pluginOptions = {
clipboardCommandHandler: (editCommand: any) => {
this._undoRedoBuffer.queueAndExecuteCommand.call(this._undoRedoBuffer, editCommand);
},
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 isEvaluatingFormatter = (columnDef.exportWithFormatter !== undefined) ? columnDef.exportWithFormatter : (this.sharedService.gridOptions.exportOptions && this.sharedService.gridOptions.exportOptions.exportWithFormatter);
if (columnDef.formatter && isEvaluatingFormatter) {
const formattedOutput = columnDef.formatter(0, 0, item[columnDef.field], columnDef, item, this.sharedService.grid);
if (columnDef.sanitizeDataExport || (this.sharedService.gridOptions.exportOptions && this.sharedService.gridOptions.exportOptions.sanitizeDataExport)) {
let outputString = formattedOutput as string;
if (formattedOutput && typeof formattedOutput === 'object' && formattedOutput.hasOwnProperty('text')) {
outputString = formattedOutput.text;
}
if (outputString === null) {
outputString = '';
}
return sanitizeHtmlToText(outputString);
}
return formattedOutput;
}
}
// else use the default "dataItemColumnValueExtractor" from the plugin itself
// we can do that by setting back the getter with null
return null;
},
readOnlyMode: false,
includeHeaderWhenCopying: false,
newRowCreator: (count: number) => {
for (let i = 0; i < count; i++) {
const item = {
id: 'newRow_' + newRowIds++
};
this.sharedService.grid.getData().addItem(item);
}
}
};

const pluginOptions = { ...this.getDefaultOptions(), ...this.sharedService.gridOptions.excelCopyBufferOptions } as ExcelCopyBufferOption;
this.sharedService.grid.setSelectionModel(new Slick.CellSelectionModel());
this._extension = new Slick.CellExternalCopyManager(pluginOptions);
this.sharedService.grid.registerPlugin(this._extension);

// hook to all possible events
if (this.sharedService.grid && this.sharedService.gridOptions.excelCopyBufferOptions) {
if (this.sharedService.gridOptions.excelCopyBufferOptions.onExtensionRegistered) {
this.sharedService.gridOptions.excelCopyBufferOptions.onExtensionRegistered(this._extension);
}
this._eventHandler.subscribe(this._extension.onCopyCells, (e: any, args: { ranges: SelectedRange[] }) => {
if (this.sharedService.gridOptions.excelCopyBufferOptions && typeof this.sharedService.gridOptions.excelCopyBufferOptions.onCopyCells === 'function') {
this.sharedService.gridOptions.excelCopyBufferOptions.onCopyCells(e, args);
}
});
this._eventHandler.subscribe(this._extension.onCopyCancelled, (e: any, args: { ranges: SelectedRange[] }) => {
if (this.sharedService.gridOptions.excelCopyBufferOptions && typeof this.sharedService.gridOptions.excelCopyBufferOptions.onCopyCancelled === 'function') {
this.sharedService.gridOptions.excelCopyBufferOptions.onCopyCancelled(e, args);
}
});
this._eventHandler.subscribe(this._extension.onPasteCells, (e: any, args: { ranges: SelectedRange[] }) => {
if (this.sharedService.gridOptions.excelCopyBufferOptions && typeof this.sharedService.gridOptions.excelCopyBufferOptions.onPasteCells === 'function') {
this.sharedService.gridOptions.excelCopyBufferOptions.onPasteCells(e, args);
}
});
}

return this._extension;
}
return null;
Expand Down Expand Up @@ -104,6 +92,53 @@ export class CellExternalCopyManagerExtension implements Extension {
};
}

/**
* @return default plugin (addon) options
*/
private getDefaultOptions(): ExcelCopyBufferOption {
let newRowIds = 0;

return {
clipboardCommandHandler: (editCommand: any) => {
this._undoRedoBuffer.queueAndExecuteCommand.call(this._undoRedoBuffer, editCommand);
},
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 isEvaluatingFormatter = (columnDef.exportWithFormatter !== undefined) ? columnDef.exportWithFormatter : (this.sharedService.gridOptions.exportOptions && this.sharedService.gridOptions.exportOptions.exportWithFormatter);
if (columnDef.formatter && isEvaluatingFormatter) {
const formattedOutput = columnDef.formatter(0, 0, item[columnDef.field], columnDef, item, this.sharedService.grid);
if (columnDef.sanitizeDataExport || (this.sharedService.gridOptions.exportOptions && this.sharedService.gridOptions.exportOptions.sanitizeDataExport)) {
let outputString = formattedOutput as string;
if (formattedOutput && typeof formattedOutput === 'object' && formattedOutput.hasOwnProperty('text')) {
outputString = formattedOutput.text;
}
if (outputString === null) {
outputString = '';
}
return sanitizeHtmlToText(outputString);
}
return formattedOutput;
}
}
// else use the default "dataItemColumnValueExtractor" from the plugin itself
// we can do that by setting back the getter with null
return null;
},
readOnlyMode: false,
includeHeaderWhenCopying: false,
newRowCreator: (count: number) => {
for (let i = 0; i < count; i++) {
const item = {
id: 'newRow_' + newRowIds++
};
this.sharedService.grid.getData().addItem(item);
}
}
};
}

/** Attach an undo shortcut key hook that will redo/undo the copy buffer */
private hookUndoShortcutKey() {
// undo shortcut
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
import { Column } from './column.interface';
import { SelectedRange } from './selectedRange.interface';

export interface ExcelCopyBufferOption {
/** defaults to "copied", sets the css className used for copied cells. */
copiedCellStyle?: string;

/** defaults to "copy-manager", sets the layer key for setting css values of copied cells. */
copiedCellStyleLayerKey?: string;

/** option to specify a custom column value extractor function */
dataItemColumnValueExtractor?: (item: any, columnDef: Column) => any;

/** option to specify a custom column value setter function */
dataItemColumnValueSetter?: (item: any, columnDef: Column, value: any) => any;

/** option to specify a custom handler for paste actions */
clipboardCommandHandler?: (editCommand: any) => void;

/** set to true and the plugin will take the name property from each column (which is usually what appears in your header) and put that as the first row of the text that's copied to the clipboard */
includeHeaderWhenCopying?: boolean;

/** option to specify a custom DOM element which to will be added the hidden textbox. It's useful if the grid is inside a modal dialog. */
bodyElement?: HTMLElement;

/** optional handler to run when copy action initializes */
onCopyInit?: any;

/** optional handler to run when copy action is complete */
onCopySuccess?: any;

/** function to add rows to table if paste overflows bottom of table, if this function is not provided new rows will be ignored. */
newRowCreator?: (count: number) => void;

/** suppresses paste */
readOnlyMode?: boolean;

/** option to specify a custom column header value extractor function */
headerColumnValueExtractor?: (columnDef: Column) => any;


// --
// Events
// ------------

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

/** Fired when a copy cell is triggered */
onCopyCells?: (e: Event, args: { ranges: SelectedRange[] }) => void;

/** Fired when the command to copy the cells is cancelled */
onCopyCancelled?: (e: Event, args: { ranges: SelectedRange[] }) => void;

/** Fired when the user paste cells to the grid */
onPasteCells?: (e: Event, args: { ranges: SelectedRange[] }) => void;
}
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import {
CheckboxSelector,
DraggableGrouping,
EditCommand,
ExcelCopyBufferOption,
ExportOption,
FormatterOption,
GridMenu,
Expand Down Expand Up @@ -217,6 +218,9 @@ export interface GridOption {
/** Do we want to enable localization translation (i18n)? */
enableTranslate?: boolean;

/** Options for the ExcelCopyBuffer Extension */
excelCopyBufferOptions?: ExcelCopyBufferOption;

/** Do we want explicit grid initialization? */
explicitInitialization?: boolean;

Expand Down
2 changes: 2 additions & 0 deletions src/app/modules/angular-slickgrid/models/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ export * from './editorValidator.interface';
export * from './editorValidatorOutput.interface';
export * from './elementPosition.interface';
export * from './emitterType.enum';
export * from './excelCopyBufferOption.interface';
export * from './exportOption.interface';
export * from './extension.interface';
export * from './extensionModel.interface';
Expand Down Expand Up @@ -85,6 +86,7 @@ export * from './queryArgument.interface';
export * from './rowDetailView.interface';
export * from './rowMoveManager.interface';
export * from './searchTerm.type';
export * from './selectedRange.interface';
export * from './selectOption.interface';
export * from './slickEvent.interface';
export * from './sortChangedArgs.interface';
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
export interface SelectedRange {
/** Selection start from which cell? */
fromCell: number;

/** Selection start from which row? */
fromRow: number;

/** Selection goes to which cell? */
toCell: number;

/** Selection goes to which row? */
toRow: number;

/** Does the selection contain a row & cell number? */
contains?: (row: number, cell: number) => boolean;

/** Is it a Single Cell Selection? */
isSingleCell?: () => boolean;

/** Is it a Single Row Selection? */
isSingleRow?: () => boolean;

/** Output print to string */
toString?: () => string;
}