Skip to content

Commit

Permalink
fix: add support for Scratch-style block comments (#83)
Browse files Browse the repository at this point in the history
* fix: add support for Scratch-style block comments

* chore: add license header.

* refactor: remove redundant property initialization.

This is handled in the superclass.

* chore: add comments to clarify disabling undo in block comment events.

* chore: add @implements annotations to bubble/icon classes.

* refactor: remove redundant listener cleanup.

* refactor: use an early return when serializing comment icons.

* chore: format comment icon.

* refactor: set initial comment position in onLocationChange instead of constructor.

* refactor: make comment bubbles preserve their offset automatically when their anchor point is set.

* refactor: correctly calculate the block comment anchor point.

* refactor: use the bubble layer constant.

* chore: format block events.

* refactor: initialize block comment anchors at the correct location

* refactor: don't decompose objects when serializing
  • Loading branch information
gonfunko authored Jul 11, 2024
1 parent 98ccb62 commit 8902091
Show file tree
Hide file tree
Showing 11 changed files with 681 additions and 1 deletion.
6 changes: 5 additions & 1 deletion core/css.js
Original file line number Diff line number Diff line change
Expand Up @@ -1288,6 +1288,10 @@ const styles = `
height: 1.25rem;
}
.blocklyComment {
--colour-commentBorder: #bcA903;
}
.blocklyCommentTopbar {
height: 32px;
--commentBorderColour: #e2db96;
Expand All @@ -1307,7 +1311,7 @@ const styles = `
.blocklySelected .blocklyCommentHighlight,
.blocklyCollapsed .blocklyCommentTopbarBackground,
.blocklyCollapsed.blocklySelected .blocklyCommentTopbarBackground {
stroke: #bcA903;
stroke: var(--colour-commentBorder);
stroke-width: 1px;
}
Expand Down
35 changes: 35 additions & 0 deletions src/events_block_comment_base.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
/**
* @license
* Copyright 2024 Google LLC
* SPDX-License-Identifier: Apache-2.0
*/

import * as Blockly from "blockly/core";

export class BlockCommentBase extends Blockly.Events.Abstract {
constructor(opt_blockComment) {
super();
this.isBlank = !opt_blockComment;

if (!opt_blockComment) return;

this.commentId = opt_blockComment.getId();
this.blockId = opt_blockComment.getSourceBlock()?.id;
this.workspaceId = opt_blockComment.getSourceBlock()?.workspace.id;
}

toJson() {
return {
...super.toJson(),
commentId: this.commentId,
blockId: this.blockId,
};
}

static fromJson(json, workspace, event) {
const newEvent = super.fromJson(json, workspace, event);
newEvent.commentId = json["commentId"];
newEvent.blockId = json["blockId"];
return newEvent;
}
}
43 changes: 43 additions & 0 deletions src/events_block_comment_change.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
/**
* @license
* Copyright 2024 Google LLC
* SPDX-License-Identifier: Apache-2.0
*/

import * as Blockly from "blockly/core";
import { BlockCommentBase } from "./events_block_comment_base.js";

class BlockCommentChange extends BlockCommentBase {
constructor(opt_blockComment, oldContents, newContents) {
super(opt_blockComment);
this.type = "block_comment_change";
this.oldContents_ = oldContents;
this.newContents_ = newContents;
// Disable undo because Blockly already tracks changes to comment text for
// undo purposes; this event exists solely to keep the Scratch VM apprised
// of the state of things.
this.recordUndo = false;
}

toJson() {
return {
...super.toJson(),
newContents: this.newContents_,
oldContents: this.oldContents_,
};
}

static fromJson(json, workspace, event) {
const newEvent = super.fromJson(json, workspace, event);
newEvent.newContents_ = json["newContents"];
newEvent.oldContents_ = json["oldContents"];

return newEvent;
}
}

Blockly.registry.register(
Blockly.registry.Type.EVENT,
"block_comment_change",
BlockCommentChange
);
43 changes: 43 additions & 0 deletions src/events_block_comment_collapse.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
/**
* @license
* Copyright 2024 Google LLC
* SPDX-License-Identifier: Apache-2.0
*/

import * as Blockly from "blockly/core";
import { BlockCommentBase } from "./events_block_comment_base.js";

class BlockCommentCollapse extends BlockCommentBase {
constructor(opt_blockComment, collapsed) {
super(opt_blockComment);
this.type = "block_comment_collapse";
this.newCollapsed = collapsed;
}

toJson() {
return {
...super.toJson(),
collapsed: this.newCollapsed,
};
}

static fromJson(json, workspace, event) {
const newEvent = super.fromJson(json, workspace, event);
newEvent.newCollapsed = json["collapsed"];

return newEvent;
}

run(forward) {
const workspace = this.getEventWorkspace_();
const block = workspace.getBlockById(this.blockId);
const comment = block.getIcon(Blockly.icons.IconType.COMMENT);
comment.setBubbleVisible(forward ? !this.newCollapsed : this.newCollapsed);
}
}

Blockly.registry.register(
Blockly.registry.Type.EVENT,
"block_comment_collapse",
BlockCommentCollapse
);
52 changes: 52 additions & 0 deletions src/events_block_comment_create.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
/**
* @license
* Copyright 2024 Google LLC
* SPDX-License-Identifier: Apache-2.0
*/

import * as Blockly from "blockly/core";
import { BlockCommentBase } from "./events_block_comment_base.js";

class BlockCommentCreate extends BlockCommentBase {
constructor(opt_blockComment) {
super(opt_blockComment);
this.type = "block_comment_create";
const size = opt_blockComment.getSize();
const location = opt_blockComment.getRelativeToSurfaceXY();
this.json = {
x: location.x,
y: location.y,
width: size.width,
height: size.height,
};
// Disable undo because Blockly already tracks comment creation for
// undo purposes; this event exists solely to keep the Scratch VM apprised
// of the state of things.
this.recordUndo = false;
}

toJson() {
return {
...super.toJson(),
json: this.json,
};
}

static fromJson(json, workspace, event) {
const newEvent = super.fromJson(json, workspace, event);
newEvent.json = {
x: json["json"]["x"],
y: json["json"]["y"],
width: json["json"]["width"],
height: json["json"]["height"],
};

return newEvent;
}
}

Blockly.registry.register(
Blockly.registry.Type.EVENT,
"block_comment_create",
BlockCommentCreate
);
27 changes: 27 additions & 0 deletions src/events_block_comment_delete.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
/**
* @license
* Copyright 2024 Google LLC
* SPDX-License-Identifier: Apache-2.0
*/

import * as Blockly from "blockly/core";
import { BlockCommentBase } from "./events_block_comment_base.js";

class BlockCommentDelete extends BlockCommentBase {
constructor(opt_blockComment, sourceBlock) {
super(opt_blockComment);
this.type = "block_comment_delete";
this.blockId = sourceBlock.id;
this.workspaceId = sourceBlock.workspace.id;
// Disable undo because Blockly already tracks comment deletion for
// undo purposes; this event exists solely to keep the Scratch VM apprised
// of the state of things.
this.recordUndo = false;
}
}

Blockly.registry.register(
Blockly.registry.Type.EVENT,
"block_comment_delete",
BlockCommentDelete
);
54 changes: 54 additions & 0 deletions src/events_block_comment_move.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
/**
* @license
* Copyright 2024 Google LLC
* SPDX-License-Identifier: Apache-2.0
*/

import * as Blockly from "blockly/core";
import { BlockCommentBase } from "./events_block_comment_base.js";

class BlockCommentMove extends BlockCommentBase {
constructor(opt_blockComment, oldCoordinate, newCoordinate) {
super(opt_blockComment);
this.type = "block_comment_move";
this.oldCoordinate_ = oldCoordinate;
this.newCoordinate_ = newCoordinate;
}

toJson() {
return {
...super.toJson(),
newCoordinate: this.newCoordinate_,
oldCoordinate: this.oldCoordinate_,
};
}

static fromJson(json, workspace, event) {
const newEvent = super.fromJson(json, workspace, event);
newEvent.newCoordinate_ = new Blockly.utils.Coordinate(
json["newCoordinate"]["x"],
json["newCoordinate"]["y"]
);
newEvent.oldCoordinate_ = new Blockly.utils.Coordinate(
json["oldCoordinate"]["x"],
json["oldCoordinate"]["y"]
);

return newEvent;
}

run(forward) {
const workspace = this.getEventWorkspace_();
const block = workspace?.getBlockById(this.blockId);
const comment = block?.getIcon(Blockly.icons.IconType.COMMENT);
comment?.setBubbleLocation(
forward ? this.newCoordinate_ : this.oldCoordinate_
);
}
}

Blockly.registry.register(
Blockly.registry.Type.EVENT,
"block_comment_move",
BlockCommentMove
);
52 changes: 52 additions & 0 deletions src/events_block_comment_resize.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
/**
* @license
* Copyright 2024 Google LLC
* SPDX-License-Identifier: Apache-2.0
*/

import * as Blockly from "blockly/core";
import { BlockCommentBase } from "./events_block_comment_base.js";

class BlockCommentResize extends BlockCommentBase {
constructor(opt_blockComment, oldSize, newSize) {
super(opt_blockComment);
this.type = "block_comment_resize";
this.oldSize = oldSize;
this.newSize = newSize;
}

toJson() {
return {
...super.toJson(),
newSize: this.newSize,
oldSize: this.oldSize,
};
}

static fromJson(json, workspace, event) {
const newEvent = super.fromJson(json, workspace, event);
newEvent.newSize = new Blockly.utils.Size(
json["newSize"]["width"],
json["newSize"]["height"]
);
newEvent.oldSize = new Blockly.utils.Size(
json["oldSize"]["width"],
json["oldSize"]["height"]
);

return newEvent;
}

run(forward) {
const workspace = this.getEventWorkspace_();
const block = workspace?.getBlockById(this.blockId);
const comment = block?.getIcon(Blockly.icons.IconType.COMMENT);
comment?.setBubbleSize(forward ? this.newSize : this.oldSize);
}
}

Blockly.registry.register(
Blockly.registry.Type.EVENT,
"block_comment_resize",
BlockCommentResize
);
7 changes: 7 additions & 0 deletions src/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,13 @@ import {CheckableContinuousFlyout} from './checkable_continuous_flyout.js';
import {buildGlowFilter, glowStack} from './glows.js';
import {ScratchContinuousToolbox} from './scratch_continuous_toolbox.js';
import './scratch_continuous_category.js';
import './scratch_comment_icon.js';
import './events_block_comment_change.js';
import './events_block_comment_collapse.js';
import './events_block_comment_create.js';
import './events_block_comment_delete.js';
import './events_block_comment_move.js';
import './events_block_comment_resize.js';
import {buildShadowFilter} from './shadows.js';

export * from 'blockly';
Expand Down
Loading

0 comments on commit 8902091

Please # to comment.