import {
Style,
TableStyles,
Table,
CellRange,
createCellRange4Dto,
asTableStyles,
asTableMergedRegions,
TableMergedRegions,
Value,
TableCellDataType,
asTableCellDataType,
DataType,
} from 'fittable-core/model';
import {
TableChangeWritter,
TableChangeWritterFactory,
Args,
} from 'fittable-core/operations';
export type CellCopyChange = Args<'cell-copy'> & { cellRange: unknown };
export class CellCopyChangeWritter implements TableChangeWritter {
private readonly styledTable?: Table & TableStyles;
private readonly mergedRegionsTable?: Table & TableMergedRegions;
private readonly cellDataTypeTable?: Table & TableCellDataType;
constructor(
private readonly table: Table,
private readonly change: CellCopyChange
) {
this.styledTable = asTableStyles(table);
this.mergedRegionsTable = asTableMergedRegions(this.table);
this.cellDataTypeTable = asTableCellDataType(this.table);
}
public run(): void {
const text: string = this.createCliboardText();
const htmlText: Blob = new Blob([text], { type: 'text/html' });
const data: ClipboardItem[] = [
new ClipboardItem({ 'text/html': htmlText }),
];
navigator.clipboard.write(data).then(
(): void => {
console.log('Copied to clipboard successfully!');
},
(error: unknown): void => {
console.error('Unable to write to clipboard!', error);
}
);
}
private createCliboardText(): string {
let text = '
';
const cellRange: CellRange = createCellRange4Dto(this.change.cellRange);
const fromRowId: number = cellRange.getFrom().getRowId();
const fromColId: number = cellRange.getFrom().getColId();
const toRowId: number = cellRange.getTo().getRowId();
const toColId: number = cellRange.getTo().getColId();
for (let i: number = fromRowId; i <= toRowId; i++) {
text += '';
for (let j: number = fromColId; j <= toColId; j++) {
text += this.createHtmlCell(i, j);
}
text += '
';
}
text += '
';
return text;
}
private createHtmlCell(rowId: number, colId: number): string {
if (this.isMergedHiddenCell(rowId, colId)) {
return '';
} else {
let attributes = '';
attributes += this.getMergedRegionsAtt(rowId, colId);
attributes += this.getCssStyleAtt(rowId, colId);
attributes += this.getCellDataTypeAtt(rowId, colId);
const value: Value | undefined = this.table.getCellValue(rowId, colId);
if (value === undefined) {
return ` | `;
} else {
let text: string = '' + value;
text = text.replaceAll('\n', '
');
return `${text} | `;
}
}
}
private isMergedHiddenCell(rowId: number, colId: number): boolean {
let isHiddenCell = false;
if (this.mergedRegionsTable) {
this.mergedRegionsTable.forEachMergedCell(
(row: number, col: number): void => {
if (isHiddenCell) return;
if (row === rowId && col === colId) return;
const rowSpan: number =
this.mergedRegionsTable?.getRowSpan(row, col) ?? 0;
const colSpan: number =
this.mergedRegionsTable?.getColSpan(row, col) ?? 0;
isHiddenCell =
rowId >= row &&
rowId < row + rowSpan &&
colId >= col &&
colId < col + colSpan;
}
);
}
return isHiddenCell;
}
private getMergedRegionsAtt(rowId: number, colId: number): string {
const rowSpan: number =
this.mergedRegionsTable?.getRowSpan(rowId, colId) ?? 0;
const colSpan: number =
this.mergedRegionsTable?.getColSpan(rowId, colId) ?? 0;
const rowSpanAtt: string = rowSpan > 1 ? ` rowspan="${rowSpan}"` : '';
const colSpanAtt: string = colSpan > 1 ? ` colspan="${colSpan}"` : '';
return rowSpanAtt + colSpanAtt;
}
private getCellDataTypeAtt(rowId: number, colId: number): string {
let result = '';
const dataType: DataType | undefined =
this.cellDataTypeTable?.getCellDataType(rowId, colId);
if (dataType) {
result += ` data-data-type-name="${dataType.getName()}"`;
if (dataType.getFormat()) {
result += ` data-data-type-format="${dataType.getFormat()}"`;
}
}
return result;
}
private getCssStyleAtt(rowId: number, colId: number): string {
if (!this.styledTable) return '';
const styleName: string | undefined = //
this.styledTable.getCellStyleName(rowId, colId);
const style: Style | undefined = styleName
? this.styledTable.getStyle(styleName)
: undefined;
return style ? ` style="${style.toCssText()}"` : '';
}
}
export class CellCopyChangeWritterFactory implements TableChangeWritterFactory {
public createTableChangeWritter(
table: Table,
change: CellCopyChange
): TableChangeWritter {
return new CellCopyChangeWritter(table, change);
}
}