Skip to content

Commit

Permalink
[IMP] clipboard: keep cell formatting when copy/pasting cells from on…
Browse files Browse the repository at this point in the history
…e spreadsheet to another

Currently, copy/pasting cells from one spreadsheet to another external spreadsheet removes all cell formatting and only keeps cell values. This is because the model clipboard is invalidated from one instance to another.

This commit solves the issue by adding a new custom type in the browser clipboard object and using the content saved in this key to re-create the cell formatting in the new spreadsheet.

Task: 3597039
  • Loading branch information
Rachico committed Apr 16, 2024
1 parent 2da2a04 commit 4c94ede
Show file tree
Hide file tree
Showing 13 changed files with 371 additions and 40 deletions.
9 changes: 8 additions & 1 deletion src/actions/menu_items_actions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,14 @@ async function paste(env: SpreadsheetChildEnv, pasteOption?: ClipboardPasteOptio
case "ok":
const target = env.model.getters.getSelectedZones();
if (osClipboard && osClipboard.content !== spreadsheetClipboard) {
interactivePasteFromOS(env, target, osClipboard.content, pasteOption);
interactivePasteFromOS(
env,
target,
{
"text/plain": osClipboard.content,
},
pasteOption
);
} else {
interactivePaste(env, target, pasteOption);
}
Expand Down
10 changes: 5 additions & 5 deletions src/clipboard_handlers/tables_clipboard.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import {
ClipboardPasteTarget,
CoreTableType,
HeaderIndex,
Range,
RangeData,
Style,
TableConfig,
UID,
Expand All @@ -21,7 +21,7 @@ interface TableStyle {
}

interface CopiedTable {
range: Range;
range: RangeData;
config: TableConfig;
type: CoreTableType;
}
Expand Down Expand Up @@ -71,7 +71,7 @@ export class TableClipboardHandler extends AbstractCellClipboardHandler<
}
tableCellsInRow.push({
table: {
range: coreTable.range,
range: coreTable.range.rangeData,
config: coreTable.config,
type: coreTable.type,
},
Expand Down Expand Up @@ -131,7 +131,7 @@ export class TableClipboardHandler extends AbstractCellClipboardHandler<
if (tableCell.table) {
this.dispatch("REMOVE_TABLE", {
sheetId: content.sheetId,
target: [tableCell.table.range.zone],
target: [this.getters.getRangeFromRangeData(tableCell.table.range).zone],
});
}
}
Expand Down Expand Up @@ -174,7 +174,7 @@ export class TableClipboardHandler extends AbstractCellClipboardHandler<
) {
if (tableCell.table && !options?.pasteOption) {
const { range: tableRange } = tableCell.table;
const zoneDims = zoneToDimension(tableRange.zone);
const zoneDims = zoneToDimension(this.getters.getRangeFromRangeData(tableRange).zone);
const newTableZone = {
left: position.col,
top: position.row,
Expand Down
8 changes: 7 additions & 1 deletion src/components/grid/grid.ts
Original file line number Diff line number Diff line change
Expand Up @@ -647,7 +647,13 @@ export class Grid extends Component<Props, SpreadsheetChildEnv> {
// the paste actually comes from o-spreadsheet itself
interactivePaste(this.env, target);
} else {
interactivePasteFromOS(this.env, target, content);
interactivePasteFromOS(this.env, target, {
[ClipboardMIMEType.PlainText]: ev.clipboardData.getData(ClipboardMIMEType.PlainText),
[ClipboardMIMEType.Html]: ev.clipboardData.getData(ClipboardMIMEType.Html),
[ClipboardMIMEType.OSpreadsheet]: ev.clipboardData.getData(
ClipboardMIMEType.OSpreadsheet
),
});
}
if (isCutOperation) {
await this.env.clipboard.write({ [ClipboardMIMEType.PlainText]: "" });
Expand Down
10 changes: 7 additions & 3 deletions src/helpers/ui/paste_interactive.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { CommandResult, DispatchResult } from "../..";
import { ClipboardContent, CommandResult, DispatchResult } from "../..";
import { _t } from "../../translation";
import { ClipboardPasteOptions, SpreadsheetChildEnv, Zone } from "../../types";

Expand Down Expand Up @@ -37,9 +37,13 @@ export function interactivePaste(
export function interactivePasteFromOS(
env: SpreadsheetChildEnv,
target: Zone[],
text: string,
clipboardContent: ClipboardContent,
pasteOption?: ClipboardPasteOptions
) {
const result = env.model.dispatch("PASTE_FROM_OS_CLIPBOARD", { target, text, pasteOption });
const result = env.model.dispatch("PASTE_FROM_OS_CLIPBOARD", {
target,
clipboardContent,
pasteOption,
});
handlePasteResult(env, result);
}
31 changes: 28 additions & 3 deletions src/plugins/ui_stateful/clipboard.ts
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ export class ClipboardPlugin extends UIPlugin {
static getters = [
"getClipboardContent",
"getClipboardTextContent",
"getClipboardCellFormattingContent",
"isCutOperation",
"isPaintingFormat",
] as const;
Expand All @@ -68,7 +69,9 @@ export class ClipboardPlugin extends UIPlugin {
const zones = this.getters.getSelectedZones();
return this.isCutAllowedOn(zones);
case "PASTE_FROM_OS_CLIPBOARD": {
const copiedData = this.convertOSClipboardData(cmd.text);
const copiedData = this.convertOSClipboardData(
cmd.clipboardContent[ClipboardMIMEType.PlainText]
);
const pasteOption =
cmd.pasteOption || (this.paintFormatStatus !== "inactive" ? "onlyFormat" : undefined);
return this.isPasteAllowed(cmd.target, copiedData, { pasteOption });
Expand Down Expand Up @@ -125,7 +128,13 @@ export class ClipboardPlugin extends UIPlugin {
this.copiedData = this.copy(cmd.type, zones);
break;
case "PASTE_FROM_OS_CLIPBOARD": {
this.copiedData = this.convertOSClipboardData(cmd.text);
if (cmd.clipboardContent[ClipboardMIMEType.OSpreadsheet]) {
this.copiedData = JSON.parse(cmd.clipboardContent[ClipboardMIMEType.OSpreadsheet]);
} else {
this.copiedData = this.convertOSClipboardData(
cmd.clipboardContent[ClipboardMIMEType.PlainText]
);
}
const pasteOption =
cmd.pasteOption || (this.paintFormatStatus !== "inactive" ? "onlyFormat" : undefined);
this.paste(cmd.target, {
Expand Down Expand Up @@ -278,7 +287,7 @@ export class ClipboardPlugin extends UIPlugin {
}
}

private convertOSClipboardData(clipboardData: string): {} {
private convertOSClipboardData(clipboardData: string | undefined): {} {
this._isCutOperation = false;
const handlers: ClipboardHandler<any>[] = clipboardHandlersRegistries.figureHandlers
.getAll()
Expand Down Expand Up @@ -460,13 +469,29 @@ export class ClipboardPlugin extends UIPlugin {
return this.getPlainTextContent();
}

getClipboardCellFormattingContent(): string {
return this.getCellFormattingContent();
}

getClipboardContent(): ClipboardContent {
return {
[ClipboardMIMEType.PlainText]: this.getPlainTextContent(),
[ClipboardMIMEType.Html]: this.getHTMLContent(),
[ClipboardMIMEType.OSpreadsheet]: this.getCellFormattingContent(),
};
}

private getCellFormattingContent(): string {
const zones = this.getters.getSelectedZones();
const clipboardData = this.getClipboardData(zones);
let copiedCellFormattingData = {};
for (const handler of this.selectClipboardHandlers(clipboardData)) {
const data = handler.copy(clipboardData);
copiedCellFormattingData = { ...copiedCellFormattingData, ...data };
}
return JSON.stringify(copiedCellFormattingData);
}

private getPlainTextContent(): string {
if (!this.copiedData?.cells) {
return "\t";
Expand Down
6 changes: 6 additions & 0 deletions src/types/clipboard.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import { HeaderIndex, UID, Zone } from "./misc";
export enum ClipboardMIMEType {
PlainText = "text/plain",
Html = "text/html",
OSpreadsheet = "web application/o-spreadsheet",
}

export type ClipboardContent = { [type in ClipboardMIMEType]?: string };
Expand All @@ -15,6 +16,11 @@ export interface ClipboardOptions {
export type ClipboardPasteOptions = "onlyFormat" | "asValue";
export type ClipboardOperation = "CUT" | "COPY";

export type ClipboardPasteContent = {
plainText: string;
cellFormatting?: string;
};

export type ClipboardCellData = {
zones: Zone[];
rowsIndexes: HeaderIndex[];
Expand Down
4 changes: 2 additions & 2 deletions src/types/commands.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ import {
} from "./misc";

import { ChartDefinition } from "./chart/chart";
import { ClipboardPasteOptions } from "./clipboard";
import { ClipboardContent, ClipboardPasteOptions } from "./clipboard";
import { FigureSize } from "./figure";
import { SearchOptions } from "./find_and_replace";
import { Image } from "./image";
Expand Down Expand Up @@ -685,7 +685,7 @@ export interface CancelPaintFormatCommand {
export interface PasteFromOSClipboardCommand {
type: "PASTE_FROM_OS_CLIPBOARD";
target: Zone[];
text: string;
clipboardContent: ClipboardContent;
pasteOption?: ClipboardPasteOptions;
}

Expand Down
2 changes: 1 addition & 1 deletion src/types/table.ts
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ export interface TableElementStyle {
size?: number;
}

interface TableBorder extends Border {
export interface TableBorder extends Border {
// used to describe borders inside of a zone
horizontal?: BorderDescr;
vertical?: BorderDescr;
Expand Down

0 comments on commit 4c94ede

Please sign in to comment.