Skip to content

Commit

Permalink
fix: Drag and Resize events for workspace comments (#8217)
Browse files Browse the repository at this point in the history
* 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.
  • Loading branch information
johnnesky authored Jun 26, 2024
1 parent be268e3 commit 9a0619a
Show file tree
Hide file tree
Showing 14 changed files with 469 additions and 14 deletions.
4 changes: 3 additions & 1 deletion core/bump_objects.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import type {BlockCreate} from './events/events_block_create.js';
import type {BlockMove} from './events/events_block_move.js';
import type {CommentCreate} from './events/events_comment_create.js';
import type {CommentMove} from './events/events_comment_move.js';
import type {CommentResize} from './events/events_comment_resize.js';
import type {ViewportChange} from './events/events_viewport.js';
import * as eventUtils from './events/utils.js';
import type {IBoundedElement} from './interfaces/i_bounded_element.js';
Expand Down Expand Up @@ -163,8 +164,9 @@ function extractObjectFromEvent(
break;
case eventUtils.COMMENT_CREATE:
case eventUtils.COMMENT_MOVE:
case eventUtils.COMMENT_RESIZE:
object = workspace.getCommentById(
(e as CommentCreate | CommentMove).commentId!,
(e as CommentCreate | CommentMove | CommentResize).commentId!,
) as RenderedWorkspaceComment;
break;
}
Expand Down
27 changes: 19 additions & 8 deletions core/comments/comment_view.ts
Original file line number Diff line number Diff line change
Expand Up @@ -125,7 +125,7 @@ export class CommentView implements IRenderedElement {
workspace.getLayerManager()?.append(this, layers.BLOCK);

// Set size to the default size.
this.setSize(this.size);
this.setSizeWithoutFiringEvents(this.size);

// Set default transform (including inverted scale for RTL).
this.moveTo(new Coordinate(0, 0));
Expand Down Expand Up @@ -298,7 +298,7 @@ export class CommentView implements IRenderedElement {
* Sets the size of the comment in workspace units, and updates the view
* elements to reflect the new size.
*/
setSize(size: Size) {
setSizeWithoutFiringEvents(size: Size) {
const topBarSize = this.topBarBackground.getBBox();
const deleteSize = this.deleteIcon.getBBox();
const foldoutSize = this.foldoutIcon.getBBox();
Expand All @@ -309,7 +309,6 @@ export class CommentView implements IRenderedElement {
size,
this.calcMinSize(topBarSize, foldoutSize, deleteSize),
);
const oldSize = this.size;
this.size = size;

this.svgRoot.setAttribute('height', `${size.height}`);
Expand All @@ -328,7 +327,15 @@ export class CommentView implements IRenderedElement {
resizeSize,
);
this.updateResizeHandlePosition(size, resizeSize);
}

/**
* Sets the size of the comment in workspace units, updates the view
* elements to reflect the new size, and triggers size change listeners.
*/
setSize(size: Size) {
const oldSize = this.size;
this.setSizeWithoutFiringEvents(size);
this.onSizeChange(oldSize, this.size);
}

Expand Down Expand Up @@ -472,7 +479,7 @@ export class CommentView implements IRenderedElement {

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

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

/** Returns true if the comment is currently collapsed. */
Expand All @@ -573,7 +584,7 @@ export class CommentView implements IRenderedElement {
dom.removeClass(this.svgRoot, 'blocklyCollapsed');
}
// Repositions resize handle and such.
this.setSize(this.size);
this.setSizeWithoutFiringEvents(this.size);
this.onCollapse();
}

Expand Down Expand Up @@ -682,7 +693,7 @@ export class CommentView implements IRenderedElement {

/**
* Triggers listeners when the text of the comment changes, either
* progrmatically or manually by the user.
* programmatically or manually by the user.
*/
private onTextChange() {
const oldText = this.text;
Expand Down
10 changes: 9 additions & 1 deletion core/comments/workspace_comment.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import {Coordinate} from '../utils/coordinate.js';
import * as idGenerator from '../utils/idgenerator.js';
import * as eventUtils from '../events/utils.js';
import {CommentMove} from '../events/events_comment_move.js';
import {CommentResize} from '../events/events_comment_resize.js';

export class WorkspaceComment {
/** The unique identifier for this comment. */
Expand Down Expand Up @@ -104,7 +105,14 @@ export class WorkspaceComment {

/** Sets the comment's size in workspace units. */
setSize(size: Size) {
const event = new (eventUtils.get(eventUtils.COMMENT_RESIZE))(
this,
) as CommentResize;

this.size = size;

event.recordCurrentSizeAsNewSize();
eventUtils.fire(event);
}

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

event.recordNew();
if (eventUtils.isEnabled()) eventUtils.fire(event);
eventUtils.fire(event);
}

/** Returns the position of the comment in workspace coordinates. */
Expand Down
21 changes: 21 additions & 0 deletions core/dragging/comment_drag_strategy.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ export class CommentDragStrategy implements IDragStrategy {
if (!eventUtils.getGroup()) {
eventUtils.setGroup(true);
}
this.fireDragStartEvent();
this.startLoc = this.comment.getRelativeToSurfaceXY();
this.workspace.setResizesEnabled(false);
this.workspace.getLayerManager()?.moveToDragLayer(this.comment);
Expand All @@ -40,6 +41,7 @@ export class CommentDragStrategy implements IDragStrategy {
}

endDrag(): void {
this.fireDragEndEvent();
this.fireMoveEvent();

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

/** Fire a UI event at the start of a comment drag. */
private fireDragStartEvent() {
const event = new (eventUtils.get(eventUtils.COMMENT_DRAG))(
this.comment,
true,
);
eventUtils.fire(event);
}

/** Fire a UI event at the end of a comment drag. */
private fireDragEndEvent() {
const event = new (eventUtils.get(eventUtils.COMMENT_DRAG))(
this.comment,
false,
);
eventUtils.fire(event);
}

/** Fire a move event at the end of a comment drag. */
private fireMoveEvent() {
if (this.comment.isDeadOrDying()) return;
const event = new (eventUtils.get(eventUtils.COMMENT_MOVE))(
Expand Down
8 changes: 8 additions & 0 deletions core/events/events.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,8 @@ import {CommentChange, CommentChangeJson} from './events_comment_change.js';
import {CommentCreate, CommentCreateJson} from './events_comment_create.js';
import {CommentDelete} from './events_comment_delete.js';
import {CommentMove, CommentMoveJson} from './events_comment_move.js';
import {CommentResize, CommentResizeJson} from './events_comment_resize.js';
import {CommentDrag, CommentDragJson} from './events_comment_drag.js';
import {
CommentCollapse,
CommentCollapseJson,
Expand Down Expand Up @@ -77,6 +79,10 @@ export {CommentCreateJson};
export {CommentDelete};
export {CommentMove};
export {CommentMoveJson};
export {CommentResize};
export {CommentResizeJson};
export {CommentDrag};
export {CommentDragJson};
export {CommentCollapse};
export {CommentCollapseJson};
export {FinishedLoading};
Expand Down Expand Up @@ -119,6 +125,8 @@ export const COMMENT_CHANGE = eventUtils.COMMENT_CHANGE;
export const COMMENT_CREATE = eventUtils.COMMENT_CREATE;
export const COMMENT_DELETE = eventUtils.COMMENT_DELETE;
export const COMMENT_MOVE = eventUtils.COMMENT_MOVE;
export const COMMENT_RESIZE = eventUtils.COMMENT_RESIZE;
export const COMMENT_DRAG = eventUtils.COMMENT_DRAG;
export const CREATE = eventUtils.CREATE;
export const DELETE = eventUtils.DELETE;
export const FINISHED_LOADING = eventUtils.FINISHED_LOADING;
Expand Down
99 changes: 99 additions & 0 deletions core/events/events_comment_drag.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
/**
* @license
* Copyright 2024 Google LLC
* SPDX-License-Identifier: Apache-2.0
*/

/**
* Events fired when a workspace comment is dragged.
*/

import type {WorkspaceComment} from '../comments/workspace_comment.js';
import * as registry from '../registry.js';
import {AbstractEventJson} from './events_abstract.js';
import {UiBase} from './events_ui_base.js';
import * as eventUtils from './utils.js';
import {Workspace} from '../workspace.js';

/**
* Notifies listeners when a comment is being manually dragged/dropped.
*/
export class CommentDrag extends UiBase {
/** The ID of the top-level comment being dragged. */
commentId?: string;

/** True if this is the start of a drag, false if this is the end of one. */
isStart?: boolean;

override type = eventUtils.COMMENT_DRAG;

/**
* @param opt_comment The comment that is being dragged.
* Undefined for a blank event.
* @param opt_isStart Whether this is the start of a comment drag.
* Undefined for a blank event.
*/
constructor(opt_comment?: WorkspaceComment, opt_isStart?: boolean) {
const workspaceId = opt_comment ? opt_comment.workspace.id : undefined;
super(workspaceId);
if (!opt_comment) return;

this.commentId = opt_comment.id;
this.isStart = opt_isStart;
}

/**
* Encode the event as JSON.
*
* @returns JSON representation.
*/
override toJson(): CommentDragJson {
const json = super.toJson() as CommentDragJson;
if (this.isStart === undefined) {
throw new Error(
'Whether this event is the start of a drag is undefined. ' +
'Either pass the value to the constructor, or call fromJson',
);
}
if (this.commentId === undefined) {
throw new Error(
'The comment ID is undefined. Either pass a comment to ' +
'the constructor, or call fromJson',
);
}
json['isStart'] = this.isStart;
json['commentId'] = this.commentId;
return json;
}

/**
* Deserializes the JSON event.
*
* @param event The event to append new properties to. Should be a subclass
* of CommentDrag, but we can't specify that due to the fact that parameters
* to static methods in subclasses must be supertypes of parameters to
* static methods in superclasses.
* @internal
*/
static fromJson(
json: CommentDragJson,
workspace: Workspace,
event?: any,
): CommentDrag {
const newEvent = super.fromJson(
json,
workspace,
event ?? new CommentDrag(),
) as CommentDrag;
newEvent.isStart = json['isStart'];
newEvent.commentId = json['commentId'];
return newEvent;
}
}

export interface CommentDragJson extends AbstractEventJson {
isStart: boolean;
commentId: string;
}

registry.register(registry.Type.EVENT, eventUtils.COMMENT_DRAG, CommentDrag);
Loading

0 comments on commit 9a0619a

Please sign in to comment.