@progress/kendo-angular-grid
Version:
Kendo UI Grid for Angular - high performance data grid with paging, filtering, virtualization, CRUD, and more.
222 lines (221 loc) • 11.5 kB
JavaScript
/**-----------------------------------------------------------------------------------------
* Copyright © 2025 Progress Software Corporation. All rights reserved.
* Licensed under commercial license. See LICENSE.md in the project root for more information
*-------------------------------------------------------------------------------------------*/
import { Injectable } from '@angular/core';
import { ColumnComponent } from '../columns/column.component';
import { isPresent } from '@progress/kendo-angular-common';
import { ContextService } from './provider.service';
import { groupBy } from '@progress/kendo-data-query';
import * as i0 from "@angular/core";
import * as i1 from "./provider.service";
/**
* @hidden
*/
export class ClipboardService {
contextService;
targetColField;
targetRowIndex;
constructor(contextService) {
this.contextService = contextService;
}
createClipboardData(data, columns, options) {
let result = {
gridItems: [],
dataString: ''
};
const fieldCols = columns.flatMap(c => c instanceof ColumnComponent && isPresent(c.field) ? [c] : []);
const clipboardData = { items: [], dataStrings: [] };
const colFields = fieldCols.map(c => c.field);
if (options.wholeRow) {
this.targetColField = fieldCols[0]?.field;
this.targetRowIndex = data[0].dataRowIndex;
data.forEach(item => {
clipboardData.items.push({ dataItem: { ...item.dataItem }, fields: colFields });
clipboardData.dataStrings.push(this.itemToString(item.dataItem, fieldCols));
});
result = {
gridItems: options.operationType === 'cut' ? clipboardData.items.map(item => {
item.fields.forEach(field => item.dataItem[field] = null);
return item;
}) : [...clipboardData.items],
dataString: options.copyHeaders ? this.addHeaders(clipboardData.dataStrings.join(`\r\n`), fieldCols) : clipboardData.dataStrings.join(`\n`)
};
}
else {
if (options.target === 'selection') {
const { tabular, groups } = this.groupSelection();
const selectionDirective = this.contextService.grid.selectionDirective;
const colIdentifier = selectionDirective.columnKey;
if (tabular) {
const selectionKeys = groups[0].items.map(item => item.columnKey);
const selectedFieldCols = columns.flatMap((c, i) => (c instanceof ColumnComponent && c.field) && isPresent((selectionKeys.find(k => typeof colIdentifier === 'function' ? k === colIdentifier(c, i) : k === i))) ? [c] : []);
const selectedColFields = selectedFieldCols.map(c => c.field);
this.targetColField = selectedColFields[0];
result.dataString = data.flatMap(item => {
const itemString = this.itemToString(item.dataItem, selectedFieldCols);
const existingItem = isPresent(itemString);
if (!isPresent(this.targetRowIndex) && isPresent(itemString)) {
this.targetRowIndex = item.dataRowIndex;
}
if (options.operationType === 'cut') {
selectedColFields.forEach(f => item.dataItem[f] = null);
}
result.gridItems.push({
dataItem: item.dataItem,
fields: selectedColFields
});
return existingItem ? [itemString] : [];
}).join(`\r\n`);
if (options.copyHeaders) {
result.dataString = this.addHeaders(result.dataString, selectedFieldCols);
}
}
else { // split per row (uneven rows)
const rowIdentifier = selectionDirective.selectionKey;
result.dataString = data.flatMap(item => {
// determine cols per item
const key = rowIdentifier ?
typeof rowIdentifier === 'string' ? item.dataItem[rowIdentifier] : rowIdentifier({ index: item.dataRowIndex, dataItem: item.dataItem }) :
item.dataRowIndex;
const selectionKeys = groups.find(gr => gr.value === key).items.map(item => item.columnKey);
const selectedFieldCols = columns.flatMap((c, i) => (c instanceof ColumnComponent && c.field) && isPresent(selectionKeys.find(k => typeof colIdentifier === 'function' ? k === colIdentifier(c, i) : k === i)) ? [c] : []);
const selectedColFields = selectedFieldCols.map(c => c.field);
if (!this.targetColField) {
this.targetColField = selectedColFields[0];
}
const itemString = this.itemToString(item.dataItem, selectedFieldCols);
const existingItem = isPresent(itemString);
if (!isPresent(this.targetRowIndex) && existingItem) {
this.targetRowIndex = item.dataRowIndex;
}
if (existingItem) {
if (options.operationType === 'cut') {
selectedColFields.forEach(f => item.dataItem[f] = null);
}
result.gridItems.push({
dataItem: item.dataItem,
fields: selectedColFields
});
}
return existingItem ? options.copyHeaders ? [this.addHeaders(itemString, selectedFieldCols)] : [itemString] : [];
}).join(`\r\n`);
}
}
else {
const item = data[0];
const col = columns[item.colIndex];
const colField = col.field;
const title = col.title;
const copiedData = item.dataItem[colField];
this.targetRowIndex = item.dataRowIndex;
this.targetColField = colField;
if (options.operationType === 'cut' && colField) {
item.dataItem[colField] = null;
}
result = {
gridItems: [{
dataItem: item.dataItem,
fields: colField ? [colField] : []
}],
dataString: options.copyHeaders ? [title || colField, copiedData].join(`\r\n`) : colField ? copiedData : ``
};
}
}
return result;
}
getGridData(data, columns, targetType, targetRowIndex, options) {
const separator = data.includes(`\r\n`) ? `\r\n` : data.includes(`\n`) ? `\n` : null;
const dataRows = separator ? data.split(separator).filter(rowData => rowData.length) : [data];
this.targetRowIndex = targetRowIndex;
if (targetType === 'activeCell') {
if (options.wholeRow) {
this.targetColField = columns.find(c => c instanceof ColumnComponent && c.field)?.field;
}
else {
const activeCellIndex = this.contextService.grid.activeCell.colIndex;
for (let i = 0; i < columns.length; i++) {
const col = columns[i];
if (col instanceof ColumnComponent && col.field && i >= activeCellIndex) {
this.targetColField = col.field;
break;
}
}
}
}
else {
if (options.wholeRow || !options.isCellSelection) {
this.targetColField = (columns.filter(c => c instanceof ColumnComponent && c.field))[0]['field'];
}
else {
const { groups } = this.groupSelection();
const selectionDirective = this.contextService.grid.selectionDirective;
const colIdentifier = selectionDirective.columnKey;
const visibleCols = columns.filter(c => c.isVisible);
const selectionKeys = groups[0].items.map(item => item.columnKey);
const selectedFieldCols = visibleCols.flatMap((c, i) => (c instanceof ColumnComponent && c.field) && isPresent(selectionKeys.find(k => typeof colIdentifier === 'function' ? k === colIdentifier(c, i) : k === i)) ? [c] : []);
const selectedColFields = selectedFieldCols.map(c => c.field);
this.targetColField = selectedColFields[0];
}
}
const items = dataRows.map(rowString => {
const cells = rowString.includes(`\t`) ? rowString.split(`\t`) : [rowString];
const colFields = columns.flatMap(c => (c instanceof ColumnComponent) && c.field ? [c.field] : []);
const targetColFieldIndex = colFields.indexOf(this.targetColField);
const affectedFields = colFields.slice(targetColFieldIndex, targetColFieldIndex + cells.length);
const item = {};
colFields.slice(targetColFieldIndex, targetColFieldIndex + cells.length).forEach((colField, index) => item[colField] = cells[index]);
return {
dataItem: item,
fields: affectedFields
};
});
return items;
}
itemToString = (item, cols) => {
if (!cols.length) {
return null;
}
return cols.map(col => item[col.field]).join(`\t`);
};
groupSelection() {
const selection = this.contextService.grid.selection;
const groups = groupBy(selection, [{ field: 'itemKey' }])
.map(gr => {
gr.items.sort((a, b) => a.columnKey - b.columnKey);
return gr;
});
for (let i = 1; i < groups.length; i++) {
if (!this.areEqual(groups[i].items, groups[i - 1].items)) {
return {
tabular: false,
groups
};
}
}
return {
tabular: true,
groups
};
}
areEqual(arr1, arr2) {
if (arr1.length !== arr2.length) {
return false;
}
for (let i = 0; i < arr1.length; i++) {
if (arr1[i].columnKey !== arr2[i].columnKey) {
return false;
}
}
return true;
}
addHeaders(initialData, cols) {
const headersRowData = cols.map(c => c.title || c.field).join(`\t`);
return `${headersRowData}\r\n${initialData}`;
}
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: ClipboardService, deps: [{ token: i1.ContextService }], target: i0.ɵɵFactoryTarget.Injectable });
static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: ClipboardService });
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: ClipboardService, decorators: [{
type: Injectable
}], ctorParameters: function () { return [{ type: i1.ContextService }]; } });