Skip to content

Commit

Permalink
[IMP] clipboard: keep cell formatting when copy/pasting cells from a …
Browse files Browse the repository at this point in the history
…spreadsheet to another
  • Loading branch information
Rachico committed Apr 15, 2024
1 parent f83afcc commit 0c59953
Show file tree
Hide file tree
Showing 10 changed files with 328 additions and 19 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
1 change: 1 addition & 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 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 0c59953

Please sign in to comment.