Files
blockly/core/comments/rendered_workspace_comment.ts
Beka Westberg ed403d0b77 feat!: change gestures to look at selected when dragging (#7991)
* feat: change gestures to look at selected when dragging

* chore: fix tests

* chore: format

* chore: PR comments
2024-04-04 08:52:43 -07:00

197 lines
5.6 KiB
TypeScript

/**
* @license
* Copyright 2024 Google LLC
* SPDX-License-Identifier: Apache-2.0
*/
import {WorkspaceComment} from './workspace_comment.js';
import {WorkspaceSvg} from '../workspace_svg.js';
import {CommentView} from './comment_view.js';
import {Coordinate} from '../utils/coordinate.js';
import {Rect} from '../utils/rect.js';
import {Size} from '../utils/size.js';
import {IBoundedElement} from '../interfaces/i_bounded_element.js';
import {IRenderedElement} from '../interfaces/i_rendered_element.js';
import * as dom from '../utils/dom.js';
import {IDraggable} from '../interfaces/i_draggable.js';
import {CommentDragStrategy} from '../dragging/comment_drag_strategy.js';
import * as browserEvents from '../browser_events.js';
import * as common from '../common.js';
import {ISelectable} from '../interfaces/i_selectable.js';
export class RenderedWorkspaceComment
extends WorkspaceComment
implements IBoundedElement, IRenderedElement, IDraggable, ISelectable
{
/** The class encompassing the svg elements making up the workspace comment. */
private view: CommentView;
public readonly workspace: WorkspaceSvg;
private dragStrategy = new CommentDragStrategy(this);
/** Constructs the workspace comment, including the view. */
constructor(workspace: WorkspaceSvg, id?: string) {
super(workspace, id);
this.workspace = workspace;
this.view = new CommentView(workspace);
// Set the size to the default size as defined in the superclass.
this.view.setSize(this.getSize());
this.view.setEditable(this.isEditable());
this.addModelUpdateBindings();
browserEvents.conditionalBind(
this.view.getSvgRoot(),
'pointerdown',
this,
this.startGesture,
);
}
/**
* Adds listeners to the view that updates the model (i.e. the superclass)
* when changes are made to the view.
*/
private addModelUpdateBindings() {
this.view.addTextChangeListener(
(_, newText: string) => void super.setText(newText),
);
this.view.addSizeChangeListener(
(_, newSize: Size) => void super.setSize(newSize),
);
this.view.addOnCollapseListener(
() => void super.setCollapsed(this.view.isCollapsed()),
);
this.view.addDisposeListener(() => {
if (!this.isDeadOrDying()) this.dispose();
});
}
/** Sets the text of the comment. */
override setText(text: string): void {
// setText will trigger the change listener that updates
// the model aka superclass.
this.view.setText(text);
}
/** Sets the size of the comment. */
override setSize(size: Size) {
// setSize will trigger the change listener that updates
// the model aka superclass.
this.view.setSize(size);
}
/** Sets whether the comment is collapsed or not. */
override setCollapsed(collapsed: boolean) {
// setCollapsed will trigger the change listener that updates
// the model aka superclass.
this.view.setCollapsed(collapsed);
}
/** Sets whether the comment is editable or not. */
override setEditable(editable: boolean): void {
super.setEditable(editable);
// Use isEditable rather than isOwnEditable to account for workspace state.
this.view.setEditable(this.isEditable());
}
/** Returns the root SVG element of this comment. */
getSvgRoot(): SVGElement {
return this.view.getSvgRoot();
}
/** Returns the bounding rectangle of this comment in workspace coordinates. */
getBoundingRectangle(): Rect {
const loc = this.getRelativeToSurfaceXY();
const size = this.getSize();
return new Rect(loc.y, loc.y + size.height, loc.x, loc.x + size.width);
}
/** Move the comment by the given amounts in workspace coordinates. */
moveBy(dx: number, dy: number, reason?: string[] | undefined): void {
const loc = this.getRelativeToSurfaceXY();
const newLoc = new Coordinate(loc.x + dx, loc.y + dy);
this.moveTo(newLoc, reason);
}
/** Moves the comment to the given location in workspace coordinates. */
override moveTo(location: Coordinate, reason?: string[] | undefined): void {
super.moveTo(location, reason);
this.view.moveTo(location);
}
/**
* Moves the comment during a drag. Doesn't fire move events.
*
* @internal
*/
moveDuringDrag(location: Coordinate): void {
this.location = location;
this.view.moveTo(location);
}
/**
* Adds the dragging CSS class to this comment.
*
* @internal
*/
setDragging(dragging: boolean): void {
if (dragging) {
dom.addClass(this.getSvgRoot(), 'blocklyDragging');
} else {
dom.removeClass(this.getSvgRoot(), 'blocklyDragging');
}
}
/** Disposes of the view. */
override dispose() {
this.disposing = true;
if (!this.view.isDeadOrDying()) this.view.dispose();
super.dispose();
}
/**
* Starts a gesture because we detected a pointer down on the comment
* (that wasn't otherwise gobbled up, e.g. by resizing).
*/
private startGesture(e: PointerEvent) {
const gesture = this.workspace.getGesture(e);
if (gesture) {
gesture.handleCommentStart(e, this);
common.setSelected(this);
}
}
/** Returns whether this comment is movable or not. */
isMovable(): boolean {
return this.dragStrategy.isMovable();
}
/** Starts a drag on the comment. */
startDrag(): void {
this.dragStrategy.startDrag();
}
/** Drags the comment to the given location. */
drag(newLoc: Coordinate): void {
this.dragStrategy.drag(newLoc);
}
/** Ends the drag on the comment. */
endDrag(): void {
this.dragStrategy.endDrag();
}
/** Moves the comment back to where it was at the start of a drag. */
revertDrag(): void {
this.dragStrategy.revertDrag();
}
select(): void {}
unselect(): void {}
}