diff --git a/core/comments/rendered_workspace_comment.ts b/core/comments/rendered_workspace_comment.ts index f69662a3e47..ee713d9ffd8 100644 --- a/core/comments/rendered_workspace_comment.ts +++ b/core/comments/rendered_workspace_comment.ts @@ -15,6 +15,7 @@ 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'; export class RenderedWorkspaceComment extends WorkspaceComment @@ -39,6 +40,13 @@ export class RenderedWorkspaceComment this.view.setEditable(this.isEditable()); this.addModelUpdateBindings(); + + browserEvents.conditionalBind( + this.view.getSvgRoot(), + 'pointerdown', + this, + this.startGesture, + ); } /** @@ -144,6 +152,17 @@ export class RenderedWorkspaceComment 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); + } + } + /** Returns whether this comment is movable or not. */ isMovable(): boolean { return this.dragStrategy.isMovable(); diff --git a/core/gesture.ts b/core/gesture.ts index 406e8d5f160..a6ca1552818 100644 --- a/core/gesture.ts +++ b/core/gesture.ts @@ -37,6 +37,7 @@ import type {IIcon} from './interfaces/i_icon.js'; import {IDragger} from './interfaces/i_dragger.js'; import * as registry from './registry.js'; import {IDraggable} from './interfaces/i_draggable.js'; +import {RenderedWorkspaceComment} from './comments.js'; /** * Note: In this file "start" refers to pointerdown @@ -85,6 +86,12 @@ export class Gesture { */ private startBlock: BlockSvg | null = null; + /** + * The comment that the gesture started on, or null if it did not start on a + * comment. + */ + private startComment: RenderedWorkspaceComment | null = null; + /** * The block that this gesture targets. If the gesture started on a * shadow block, this is the first non-shadow parent of the block. If the @@ -315,6 +322,23 @@ export class Gesture { return true; } + /** + * Update this gesture to record whether a comment is being dragged. + * This function should be called on a pointermove event the first time + * the drag radius is exceeded. It should be called no more than once per + * gesture. + * + * @returns True if a comment is being dragged. + */ + private updateIsDraggingComment(e: PointerEvent): boolean { + if (!this.startComment) { + return false; + } + + this.startDraggingComment(e); + return true; + } + /** * Check whether to start a block drag. If a block should be dragged, either * from the flyout or in the workspace, create the necessary BlockDragger and @@ -394,11 +418,14 @@ export class Gesture { if (this.updateIsDraggingBlock(e)) { return; } + if (this.updateIsDraggingComment(e)) { + return; + } // Then check if it's a workspace drag. this.updateIsDraggingWorkspace(); } - /** Create a block dragger and start dragging the selected block. */ + /** Start dragging the selected block. */ private startDraggingBlock(e: PointerEvent) { this.dragging = true; this.dragger = this.createDragger(this.targetBlock!, this.startWorkspace_!); @@ -406,7 +433,7 @@ export class Gesture { this.dragger.onDrag(e, this.currentDragDeltaXY); } - /** Create a bubble dragger and start dragging the selected bubble. */ + /** Start dragging the selected bubble. */ private startDraggingBubble(e: PointerEvent) { if (!this.startBubble) { throw new Error( @@ -427,6 +454,27 @@ export class Gesture { this.dragger.onDrag(e, this.currentDragDeltaXY); } + /** Start dragging the selected comment. */ + private startDraggingComment(e: PointerEvent) { + if (!this.startComment) { + throw new Error( + 'Cannot update dragging the comment because the start ' + + 'comment is undefined', + ); + } + if (!this.startWorkspace_) { + throw new Error( + 'Cannot update dragging the comment because the start ' + + 'workspace is undefined', + ); + } + + this.dragging = true; + this.dragger = this.createDragger(this.startComment, this.startWorkspace_); + this.dragger.onDragStart(e); + this.dragger.onDrag(e, this.currentDragDeltaXY); + } + private createDragger( draggable: IDraggable, workspace: WorkspaceSvg, @@ -893,6 +941,24 @@ export class Gesture { this.mostRecentEvent = e; } + /** + * Handle a pointerdown event on a workspace comment. + * + * @param e A pointerdown event. + * @param comment The comment the event hit. + * @internal + */ + handleCommentStart(e: PointerEvent, comment: RenderedWorkspaceComment) { + if (this.gestureHasStarted) { + throw Error( + 'Tried to call gesture.handleCommentStart, ' + + 'but the gesture had already been started.', + ); + } + this.setStartComment(comment); + this.mostRecentEvent = e; + } + /* Begin functions defining what actions to take to execute clicks on each * type of target. Any developer wanting to add behaviour on clicks should * modify only this code. */ @@ -1049,6 +1115,18 @@ export class Gesture { } } + /** + * Record the comment that a gesture started on + * + * @param comment The comment the gesture started on. + * @internal + */ + setStartComment(comment: RenderedWorkspaceComment) { + if (!this.startComment) { + this.startComment = comment; + } + } + /** * Record the block that a gesture started on, and set the target block * appropriately.