Files
blockly/core/clipboard/workspace_comment_paster.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

95 lines
2.6 KiB
TypeScript

/**
* @license
* Copyright 2023 Google LLC
* SPDX-License-Identifier: Apache-2.0
*/
import {IPaster} from '../interfaces/i_paster.js';
import {ICopyData} from '../interfaces/i_copyable.js';
import {Coordinate} from '../utils/coordinate.js';
import {WorkspaceSvg} from '../workspace_svg.js';
import * as registry from './registry.js';
import * as commentSerialiation from '../serialization/workspace_comments.js';
import * as eventUtils from '../events/utils.js';
import * as common from '../common.js';
import {RenderedWorkspaceComment} from '../comments/rendered_workspace_comment.js';
export class WorkspaceCommentPaster
implements IPaster<WorkspaceCommentCopyData, RenderedWorkspaceComment>
{
static TYPE = 'workspace-comment';
paste(
copyData: WorkspaceCommentCopyData,
workspace: WorkspaceSvg,
coordinate?: Coordinate,
): RenderedWorkspaceComment | null {
const state = copyData.commentState;
if (coordinate) {
state['x'] = coordinate.x;
state['y'] = coordinate.y;
}
eventUtils.disable();
let comment;
try {
comment = commentSerialiation.append(
state,
workspace,
) as RenderedWorkspaceComment;
moveCommentToNotConflict(comment);
} finally {
eventUtils.enable();
}
if (!comment) return null;
if (eventUtils.isEnabled()) {
eventUtils.fire(new (eventUtils.get(eventUtils.COMMENT_CREATE))(comment));
}
common.setSelected(comment);
return comment;
}
}
function moveCommentToNotConflict(comment: RenderedWorkspaceComment) {
const workspace = comment.workspace;
const translateDistance = 30;
const coord = comment.getRelativeToSurfaceXY();
const offset = new Coordinate(0, 0);
// getRelativeToSurfaceXY is really expensive, so we want to cache this.
const otherCoords = workspace
.getTopComments(false)
.filter((otherComment) => otherComment.id !== comment.id)
.map((c) => c.getRelativeToSurfaceXY());
while (
commentOverlapsOtherExactly(Coordinate.sum(coord, offset), otherCoords)
) {
offset.translate(
workspace.RTL ? -translateDistance : translateDistance,
translateDistance,
);
}
comment.moveTo(Coordinate.sum(coord, offset));
}
function commentOverlapsOtherExactly(
coord: Coordinate,
otherCoords: Coordinate[],
): boolean {
return otherCoords.some(
(otherCoord) =>
Math.abs(otherCoord.x - coord.x) <= 1 &&
Math.abs(otherCoord.y - coord.y) <= 1,
);
}
export interface WorkspaceCommentCopyData extends ICopyData {
commentState: commentSerialiation.State;
}
registry.register(WorkspaceCommentPaster.TYPE, new WorkspaceCommentPaster());