Skip to content

Commit 9a0619a

Browse files
authored
fix: Drag and Resize events for workspace comments (#8217)
* feat: Added a comment_drag event. * Add workspace comment resize events. * Addressing PR feedback. * Fixed chai imports in new test files. * Addressing more PR feedback.
1 parent be268e3 commit 9a0619a

14 files changed

+469
-14
lines changed

core/bump_objects.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ import type {BlockCreate} from './events/events_block_create.js';
1212
import type {BlockMove} from './events/events_block_move.js';
1313
import type {CommentCreate} from './events/events_comment_create.js';
1414
import type {CommentMove} from './events/events_comment_move.js';
15+
import type {CommentResize} from './events/events_comment_resize.js';
1516
import type {ViewportChange} from './events/events_viewport.js';
1617
import * as eventUtils from './events/utils.js';
1718
import type {IBoundedElement} from './interfaces/i_bounded_element.js';
@@ -163,8 +164,9 @@ function extractObjectFromEvent(
163164
break;
164165
case eventUtils.COMMENT_CREATE:
165166
case eventUtils.COMMENT_MOVE:
167+
case eventUtils.COMMENT_RESIZE:
166168
object = workspace.getCommentById(
167-
(e as CommentCreate | CommentMove).commentId!,
169+
(e as CommentCreate | CommentMove | CommentResize).commentId!,
168170
) as RenderedWorkspaceComment;
169171
break;
170172
}

core/comments/comment_view.ts

Lines changed: 19 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -125,7 +125,7 @@ export class CommentView implements IRenderedElement {
125125
workspace.getLayerManager()?.append(this, layers.BLOCK);
126126

127127
// Set size to the default size.
128-
this.setSize(this.size);
128+
this.setSizeWithoutFiringEvents(this.size);
129129

130130
// Set default transform (including inverted scale for RTL).
131131
this.moveTo(new Coordinate(0, 0));
@@ -298,7 +298,7 @@ export class CommentView implements IRenderedElement {
298298
* Sets the size of the comment in workspace units, and updates the view
299299
* elements to reflect the new size.
300300
*/
301-
setSize(size: Size) {
301+
setSizeWithoutFiringEvents(size: Size) {
302302
const topBarSize = this.topBarBackground.getBBox();
303303
const deleteSize = this.deleteIcon.getBBox();
304304
const foldoutSize = this.foldoutIcon.getBBox();
@@ -309,7 +309,6 @@ export class CommentView implements IRenderedElement {
309309
size,
310310
this.calcMinSize(topBarSize, foldoutSize, deleteSize),
311311
);
312-
const oldSize = this.size;
313312
this.size = size;
314313

315314
this.svgRoot.setAttribute('height', `${size.height}`);
@@ -328,7 +327,15 @@ export class CommentView implements IRenderedElement {
328327
resizeSize,
329328
);
330329
this.updateResizeHandlePosition(size, resizeSize);
330+
}
331331

332+
/**
333+
* Sets the size of the comment in workspace units, updates the view
334+
* elements to reflect the new size, and triggers size change listeners.
335+
*/
336+
setSize(size: Size) {
337+
const oldSize = this.size;
338+
this.setSizeWithoutFiringEvents(size);
332339
this.onSizeChange(oldSize, this.size);
333340
}
334341

@@ -472,7 +479,7 @@ export class CommentView implements IRenderedElement {
472479

473480
/**
474481
* Triggers listeners when the size of the comment changes, either
475-
* progrmatically or manually by the user.
482+
* programmatically or manually by the user.
476483
*/
477484
private onSizeChange(oldSize: Size, newSize: Size) {
478485
// Loop through listeners backwards in case they remove themselves.
@@ -550,13 +557,17 @@ export class CommentView implements IRenderedElement {
550557
browserEvents.unbind(this.resizePointerMoveListener);
551558
this.resizePointerMoveListener = null;
552559
}
560+
// When ending a resize drag, notify size change listeners to fire an event.
561+
this.setSize(this.size);
553562
}
554563

555564
/** Resizes the comment in response to a drag on the resize handle. */
556565
private onResizePointerMove(e: PointerEvent) {
557566
// TODO(#7926): Move this into a utils file.
558-
const delta = this.workspace.moveDrag(e);
559-
this.setSize(new Size(this.workspace.RTL ? -delta.x : delta.x, delta.y));
567+
const size = this.workspace.moveDrag(e);
568+
this.setSizeWithoutFiringEvents(
569+
new Size(this.workspace.RTL ? -size.x : size.x, size.y),
570+
);
560571
}
561572

562573
/** Returns true if the comment is currently collapsed. */
@@ -573,7 +584,7 @@ export class CommentView implements IRenderedElement {
573584
dom.removeClass(this.svgRoot, 'blocklyCollapsed');
574585
}
575586
// Repositions resize handle and such.
576-
this.setSize(this.size);
587+
this.setSizeWithoutFiringEvents(this.size);
577588
this.onCollapse();
578589
}
579590

@@ -682,7 +693,7 @@ export class CommentView implements IRenderedElement {
682693

683694
/**
684695
* Triggers listeners when the text of the comment changes, either
685-
* progrmatically or manually by the user.
696+
* programmatically or manually by the user.
686697
*/
687698
private onTextChange() {
688699
const oldText = this.text;

core/comments/workspace_comment.ts

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ import {Coordinate} from '../utils/coordinate.js';
1010
import * as idGenerator from '../utils/idgenerator.js';
1111
import * as eventUtils from '../events/utils.js';
1212
import {CommentMove} from '../events/events_comment_move.js';
13+
import {CommentResize} from '../events/events_comment_resize.js';
1314

1415
export class WorkspaceComment {
1516
/** The unique identifier for this comment. */
@@ -104,7 +105,14 @@ export class WorkspaceComment {
104105

105106
/** Sets the comment's size in workspace units. */
106107
setSize(size: Size) {
108+
const event = new (eventUtils.get(eventUtils.COMMENT_RESIZE))(
109+
this,
110+
) as CommentResize;
111+
107112
this.size = size;
113+
114+
event.recordCurrentSizeAsNewSize();
115+
eventUtils.fire(event);
108116
}
109117

110118
/** Returns the comment's size in workspace units. */
@@ -196,7 +204,7 @@ export class WorkspaceComment {
196204
this.location = location;
197205

198206
event.recordNew();
199-
if (eventUtils.isEnabled()) eventUtils.fire(event);
207+
eventUtils.fire(event);
200208
}
201209

202210
/** Returns the position of the comment in workspace coordinates. */

core/dragging/comment_drag_strategy.ts

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ export class CommentDragStrategy implements IDragStrategy {
2929
if (!eventUtils.getGroup()) {
3030
eventUtils.setGroup(true);
3131
}
32+
this.fireDragStartEvent();
3233
this.startLoc = this.comment.getRelativeToSurfaceXY();
3334
this.workspace.setResizesEnabled(false);
3435
this.workspace.getLayerManager()?.moveToDragLayer(this.comment);
@@ -40,6 +41,7 @@ export class CommentDragStrategy implements IDragStrategy {
4041
}
4142

4243
endDrag(): void {
44+
this.fireDragEndEvent();
4345
this.fireMoveEvent();
4446

4547
this.workspace
@@ -53,6 +55,25 @@ export class CommentDragStrategy implements IDragStrategy {
5355
eventUtils.setGroup(false);
5456
}
5557

58+
/** Fire a UI event at the start of a comment drag. */
59+
private fireDragStartEvent() {
60+
const event = new (eventUtils.get(eventUtils.COMMENT_DRAG))(
61+
this.comment,
62+
true,
63+
);
64+
eventUtils.fire(event);
65+
}
66+
67+
/** Fire a UI event at the end of a comment drag. */
68+
private fireDragEndEvent() {
69+
const event = new (eventUtils.get(eventUtils.COMMENT_DRAG))(
70+
this.comment,
71+
false,
72+
);
73+
eventUtils.fire(event);
74+
}
75+
76+
/** Fire a move event at the end of a comment drag. */
5677
private fireMoveEvent() {
5778
if (this.comment.isDeadOrDying()) return;
5879
const event = new (eventUtils.get(eventUtils.COMMENT_MOVE))(

core/events/events.ts

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,8 @@ import {CommentChange, CommentChangeJson} from './events_comment_change.js';
2424
import {CommentCreate, CommentCreateJson} from './events_comment_create.js';
2525
import {CommentDelete} from './events_comment_delete.js';
2626
import {CommentMove, CommentMoveJson} from './events_comment_move.js';
27+
import {CommentResize, CommentResizeJson} from './events_comment_resize.js';
28+
import {CommentDrag, CommentDragJson} from './events_comment_drag.js';
2729
import {
2830
CommentCollapse,
2931
CommentCollapseJson,
@@ -77,6 +79,10 @@ export {CommentCreateJson};
7779
export {CommentDelete};
7880
export {CommentMove};
7981
export {CommentMoveJson};
82+
export {CommentResize};
83+
export {CommentResizeJson};
84+
export {CommentDrag};
85+
export {CommentDragJson};
8086
export {CommentCollapse};
8187
export {CommentCollapseJson};
8288
export {FinishedLoading};
@@ -119,6 +125,8 @@ export const COMMENT_CHANGE = eventUtils.COMMENT_CHANGE;
119125
export const COMMENT_CREATE = eventUtils.COMMENT_CREATE;
120126
export const COMMENT_DELETE = eventUtils.COMMENT_DELETE;
121127
export const COMMENT_MOVE = eventUtils.COMMENT_MOVE;
128+
export const COMMENT_RESIZE = eventUtils.COMMENT_RESIZE;
129+
export const COMMENT_DRAG = eventUtils.COMMENT_DRAG;
122130
export const CREATE = eventUtils.CREATE;
123131
export const DELETE = eventUtils.DELETE;
124132
export const FINISHED_LOADING = eventUtils.FINISHED_LOADING;

core/events/events_comment_drag.ts

Lines changed: 99 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,99 @@
1+
/**
2+
* @license
3+
* Copyright 2024 Google LLC
4+
* SPDX-License-Identifier: Apache-2.0
5+
*/
6+
7+
/**
8+
* Events fired when a workspace comment is dragged.
9+
*/
10+
11+
import type {WorkspaceComment} from '../comments/workspace_comment.js';
12+
import * as registry from '../registry.js';
13+
import {AbstractEventJson} from './events_abstract.js';
14+
import {UiBase} from './events_ui_base.js';
15+
import * as eventUtils from './utils.js';
16+
import {Workspace} from '../workspace.js';
17+
18+
/**
19+
* Notifies listeners when a comment is being manually dragged/dropped.
20+
*/
21+
export class CommentDrag extends UiBase {
22+
/** The ID of the top-level comment being dragged. */
23+
commentId?: string;
24+
25+
/** True if this is the start of a drag, false if this is the end of one. */
26+
isStart?: boolean;
27+
28+
override type = eventUtils.COMMENT_DRAG;
29+
30+
/**
31+
* @param opt_comment The comment that is being dragged.
32+
* Undefined for a blank event.
33+
* @param opt_isStart Whether this is the start of a comment drag.
34+
* Undefined for a blank event.
35+
*/
36+
constructor(opt_comment?: WorkspaceComment, opt_isStart?: boolean) {
37+
const workspaceId = opt_comment ? opt_comment.workspace.id : undefined;
38+
super(workspaceId);
39+
if (!opt_comment) return;
40+
41+
this.commentId = opt_comment.id;
42+
this.isStart = opt_isStart;
43+
}
44+
45+
/**
46+
* Encode the event as JSON.
47+
*
48+
* @returns JSON representation.
49+
*/
50+
override toJson(): CommentDragJson {
51+
const json = super.toJson() as CommentDragJson;
52+
if (this.isStart === undefined) {
53+
throw new Error(
54+
'Whether this event is the start of a drag is undefined. ' +
55+
'Either pass the value to the constructor, or call fromJson',
56+
);
57+
}
58+
if (this.commentId === undefined) {
59+
throw new Error(
60+
'The comment ID is undefined. Either pass a comment to ' +
61+
'the constructor, or call fromJson',
62+
);
63+
}
64+
json['isStart'] = this.isStart;
65+
json['commentId'] = this.commentId;
66+
return json;
67+
}
68+
69+
/**
70+
* Deserializes the JSON event.
71+
*
72+
* @param event The event to append new properties to. Should be a subclass
73+
* of CommentDrag, but we can't specify that due to the fact that parameters
74+
* to static methods in subclasses must be supertypes of parameters to
75+
* static methods in superclasses.
76+
* @internal
77+
*/
78+
static fromJson(
79+
json: CommentDragJson,
80+
workspace: Workspace,
81+
event?: any,
82+
): CommentDrag {
83+
const newEvent = super.fromJson(
84+
json,
85+
workspace,
86+
event ?? new CommentDrag(),
87+
) as CommentDrag;
88+
newEvent.isStart = json['isStart'];
89+
newEvent.commentId = json['commentId'];
90+
return newEvent;
91+
}
92+
}
93+
94+
export interface CommentDragJson extends AbstractEventJson {
95+
isStart: boolean;
96+
commentId: string;
97+
}
98+
99+
registry.register(registry.Type.EVENT, eventUtils.COMMENT_DRAG, CommentDrag);

0 commit comments

Comments
 (0)