Files
blockly/core/serialization/workspace_comments.ts
Beka Westberg dabb11f4cb feat!: add ability to copy and paste workspace comments (#8024)
* chore: add support for copying and pasting workspace comments

* chore: fix build

* fix: PR comments
2024-04-15 14:43:58 -07:00

144 lines
4.1 KiB
TypeScript

/**
* @license
* Copyright 2024 Google LLC
* SPDX-License-Identifier: Apache-2.0
*/
import {ISerializer} from '../interfaces/i_serializer.js';
import {Workspace} from '../workspace.js';
import * as priorities from './priorities.js';
import type {WorkspaceComment} from '../comments/workspace_comment.js';
import * as eventUtils from '../events/utils.js';
import {Coordinate} from '../utils/coordinate.js';
import * as serializationRegistry from './registry.js';
import {Size} from '../utils/size.js';
export interface State {
id?: string;
text?: string;
x?: number;
y?: number;
width?: number;
height?: number;
collapsed?: boolean;
editable?: boolean;
movable?: boolean;
deletable?: boolean;
}
/** Serializes the state of the given comment to JSON. */
export function save(
comment: WorkspaceComment,
{
addCoordinates = false,
saveIds = true,
}: {
addCoordinates?: boolean;
saveIds?: boolean;
} = {},
): State {
const workspace = comment.workspace;
const state: State = Object.create(null);
state.height = comment.getSize().height;
state.width = comment.getSize().width;
if (saveIds) state.id = comment.id;
if (addCoordinates) {
const loc = comment.getRelativeToSurfaceXY();
state.x = workspace.RTL ? workspace.getWidth() - loc.x : loc.x;
state.y = loc.y;
}
if (comment.getText()) state.text = comment.getText();
if (comment.isCollapsed()) state.collapsed = true;
if (!comment.isOwnEditable()) state.editable = false;
if (!comment.isOwnMovable()) state.movable = false;
if (!comment.isOwnDeletable()) state.deletable = false;
return state;
}
/** Appends the comment defined by the given state to the given workspace. */
export function append(
state: State,
workspace: Workspace,
{recordUndo = false}: {recordUndo?: boolean} = {},
): WorkspaceComment {
const prevRecordUndo = eventUtils.getRecordUndo();
eventUtils.setRecordUndo(recordUndo);
const comment = workspace.newComment(state.id);
if (state.text !== undefined) comment.setText(state.text);
if (state.x !== undefined || state.y !== undefined) {
const defaultLoc = comment.getRelativeToSurfaceXY();
let x = state.x ?? defaultLoc.x;
x = workspace.RTL ? workspace.getWidth() - x : x;
const y = state.y ?? defaultLoc.y;
comment.moveTo(new Coordinate(x, y));
}
if (state.width !== undefined || state.height) {
const defaultSize = comment.getSize();
comment.setSize(
new Size(
state.width ?? defaultSize.width,
state.height ?? defaultSize.height,
),
);
}
if (state.collapsed !== undefined) comment.setCollapsed(state.collapsed);
if (state.editable !== undefined) comment.setEditable(state.editable);
if (state.movable !== undefined) comment.setMovable(state.movable);
if (state.deletable !== undefined) comment.setDeletable(state.deletable);
eventUtils.setRecordUndo(prevRecordUndo);
return comment;
}
// Alias to disambiguate saving within the serializer.
const saveComment = save;
/** Serializer for saving and loading workspace comment state. */
export class WorkspaceCommentSerializer implements ISerializer {
priority = priorities.WORKSPACE_COMMENTS;
/**
* Returns the state of all workspace comments in the given workspace.
*/
save(workspace: Workspace): State[] | null {
const commentStates = [];
for (const comment of workspace.getTopComments()) {
const state = saveComment(comment as AnyDuringMigration, {
addCoordinates: true,
saveIds: true,
});
if (state) commentStates.push(state);
}
return commentStates.length ? commentStates : null;
}
/**
* Deserializes the comments defined by the given state into the given
* workspace.
*/
load(state: State[], workspace: Workspace) {
for (const commentState of state) {
append(commentState, workspace, {recordUndo: eventUtils.getRecordUndo()});
}
}
/** Disposes of any comments that exist on the given workspace. */
clear(workspace: Workspace) {
for (const comment of workspace.getTopComments()) {
comment.dispose();
}
}
}
serializationRegistry.register(
'workspaceComments',
new WorkspaceCommentSerializer(),
);