Skip to content

Commit 81f19c1

Browse files
authored
refactor: update codebase for new version of Blockly and continuous toolbox (#226)
* refactor: update codebase for new version of Blockly and continuous toolbox * chore: update deps to reference new versions of Blockly and continuous toolbox * chore: rename checkable_continuous_flyout.js to checkable_continuous_flyout.ts * refactor: convert CheckableContinuousFlyout to typescript * chore: remove debugging * fix: fix support for status indicator labels
1 parent 9a03eea commit 81f19c1

13 files changed

+310
-506
lines changed

package-lock.json

Lines changed: 135 additions & 159 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -29,8 +29,8 @@
2929
"webpack-dev-server": "^4.11.1"
3030
},
3131
"dependencies": {
32-
"@blockly/continuous-toolbox": "^5.0.15",
32+
"@blockly/continuous-toolbox": "^7.0.0-beta.1",
3333
"@blockly/field-colour": "^4.0.2",
34-
"blockly": "^11.0.0"
34+
"blockly": "^12.0.0-beta.1"
3535
}
3636
}

src/checkable_continuous_flyout.js

Lines changed: 0 additions & 138 deletions
This file was deleted.

src/checkable_continuous_flyout.ts

Lines changed: 112 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,112 @@
1+
/**
2+
* @license
3+
* Copyright 2024 Google LLC
4+
* SPDX-License-Identifier: Apache-2.0
5+
*/
6+
7+
import * as Blockly from "blockly/core";
8+
import { ContinuousFlyout } from "@blockly/continuous-toolbox";
9+
import { CheckboxBubble } from "./checkbox_bubble";
10+
import { StatusIndicatorLabel } from "./status_indicator_label";
11+
import { STATUS_INDICATOR_LABEL_TYPE } from "./status_indicator_label_flyout_inflater";
12+
13+
export class CheckableContinuousFlyout extends ContinuousFlyout {
14+
/**
15+
* Creates a new CheckableContinuousFlyout.
16+
*
17+
* @param workspaceOptions Configuration options for the flyout workspace.
18+
*/
19+
constructor(workspaceOptions: Blockly.Options) {
20+
workspaceOptions.modalInputs = false;
21+
super(workspaceOptions);
22+
this.tabWidth_ = 0;
23+
this.MARGIN = 12;
24+
this.GAP_Y = 12;
25+
}
26+
27+
/**
28+
* Serializes a block to JSON in order to copy it to the main workspace.
29+
*
30+
* @param block The block to serialize.
31+
* @returns A JSON representation of the block.
32+
*/
33+
protected serializeBlock(block: Blockly.BlockSvg) {
34+
const json = super.serializeBlock(block);
35+
// Delete the serialized block's ID so that a new one is generated when it is
36+
// placed on the workspace. Otherwise, the block on the workspace may be
37+
// indistinguishable from the one in the flyout, which can cause reporter blocks
38+
// to have their value dropdown shown in the wrong place.
39+
delete json.id;
40+
return json;
41+
}
42+
43+
/**
44+
* Set the state of a checkbox by block ID.
45+
*
46+
* @param blockId ID of the block whose checkbox should be set
47+
* @param value Value to set the checkbox to.
48+
*/
49+
setCheckboxState(blockId: string, value: boolean) {
50+
this.getWorkspace()
51+
.getBlockById(blockId)
52+
?.getIcon("checkbox")
53+
?.setChecked(value);
54+
}
55+
56+
getFlyoutScale() {
57+
return 0.675;
58+
}
59+
60+
getWidth() {
61+
return 250;
62+
}
63+
64+
protected reflowInternal_() {
65+
super.reflowInternal_();
66+
67+
if (this.RTL) {
68+
// The parent implementation assumes that the flyout grows to fit its
69+
// contents, and adjusts blocks in RTL mode accordingly. In Scratch, the
70+
// flyout width is fixed (and blocks may exceed it), so re-adjust blocks
71+
// accordingly based on the actual fixed width.
72+
for (const item of this.getContents()) {
73+
const oldX = item.getElement().getBoundingRectangle().left;
74+
let newX =
75+
this.getWidth() / this.workspace_.scale -
76+
item.getElement().getBoundingRectangle().getWidth() -
77+
this.MARGIN;
78+
if (
79+
"checkboxInFlyout" in item.getElement() &&
80+
item.getElement().checkboxInFlyout
81+
) {
82+
newX -= CheckboxBubble.CHECKBOX_SIZE + CheckboxBubble.CHECKBOX_MARGIN;
83+
}
84+
item.getElement().moveBy(newX - oldX, 0);
85+
}
86+
}
87+
}
88+
89+
/**
90+
* Validates that the given toolbox item represents a label.
91+
*
92+
* @param item The toolbox item to check.
93+
* @returns True if the item represents a label in the flyout.
94+
*/
95+
protected toolboxItemIsLabel(item: Blockly.FlyoutItem) {
96+
return (
97+
item.getType() === STATUS_INDICATOR_LABEL_TYPE ||
98+
super.toolboxItemIsLabel(item)
99+
);
100+
}
101+
102+
/**
103+
* Updates the state of status indicators for hardware-based extensions.
104+
*/
105+
refreshStatusButtons() {
106+
for (const item of this.contents) {
107+
if (item.element instanceof StatusIndicatorLabel) {
108+
item.element.refreshStatus();
109+
}
110+
}
111+
}
112+
}

src/checkbox_bubble.ts

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -203,15 +203,14 @@ export class CheckboxBubble
203203
* Recalculates this bubble's location, keeping it adjacent to its block.
204204
*/
205205
updateLocation() {
206-
const blockLocation = this.sourceBlock.getRelativeToSurfaceXY();
207-
const blockBounds = this.sourceBlock.getHeightWidth();
206+
const bounds = this.sourceBlock.getBoundingRectangle();
208207
const x = this.sourceBlock.workspace.RTL
209-
? blockLocation.x + blockBounds.width + CheckboxBubble.CHECKBOX_MARGIN
210-
: blockLocation.x -
208+
? bounds.right + CheckboxBubble.CHECKBOX_MARGIN
209+
: bounds.left -
211210
CheckboxBubble.CHECKBOX_MARGIN -
212211
CheckboxBubble.CHECKBOX_SIZE;
213212
const y =
214-
blockLocation.y + (blockBounds.height - CheckboxBubble.CHECKBOX_SIZE) / 2;
213+
bounds.top + (bounds.getHeight() - CheckboxBubble.CHECKBOX_SIZE) / 2;
215214
this.moveTo(x, y);
216215
}
217216

src/css.ts

Lines changed: 13 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -751,8 +751,9 @@ const styles = `
751751
}
752752
753753
/* Category tree in Toolbox. */
754-
.blocklyToolboxDiv {
754+
.blocklyToolbox {
755755
background-color: var(--colour-toolbox);
756+
border-right: 1px solid #ddd;
756757
color: var(--colour-toolboxText);
757758
overflow-x: visible;
758759
overflow-y: auto;
@@ -763,6 +764,11 @@ const styles = `
763764
padding: 0;
764765
}
765766
767+
.blocklyToolbox[dir="RTL"] {
768+
border-right: none;
769+
border-left: 1px solid #ddd;
770+
}
771+
766772
.blocklyTreeRoot {
767773
padding: 4px 0;
768774
}
@@ -771,7 +777,7 @@ const styles = `
771777
outline: none;
772778
}
773779
774-
.blocklyToolboxDiv .blocklyTreeRow {
780+
.blocklyToolbox .blocklyToolboxCategory {
775781
line-height: 22px;
776782
margin: 0;
777783
padding: 0.375rem 0px;
@@ -789,11 +795,11 @@ const styles = `
789795
margin: 1px 0 8px 5px;
790796
}
791797
792-
.blocklyToolboxDiv[dir="RTL"] .blocklyTreeRow {
793-
margin-left: 8px;
798+
.blocklyToolbox[dir="RTL"] .blocklyToolboxCategory {
799+
margin-left: 0px;
794800
}
795801
796-
.blocklyTreeRow:hover {
802+
.blocklyToolboxCategory:hover {
797803
color: var(--colour-toolboxHover);
798804
}
799805
@@ -844,7 +850,7 @@ const styles = `
844850
background-position: -48px -1px;
845851
}
846852
847-
.blocklyTreeLabel {
853+
.blocklyToolboxCategoryLabel {
848854
cursor: default;
849855
font-family: "Helvetica Neue", Helvetica, sans-serif;
850856
font-size: .65rem;
@@ -855,7 +861,7 @@ const styles = `
855861
text-wrap: wrap;
856862
}
857863
858-
.blocklyTreeSelected .blocklyTreeLabel {
864+
.blocklyToolboxSelected .blocklyToolboxCategoryLabel {
859865
color: inherit;
860866
}
861867

src/fields/field_matrix.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -70,7 +70,7 @@ class FieldMatrix extends Blockly.Field<string> {
7070
* Touch event wrapper.
7171
* Runs when the field is selected.
7272
*/
73-
private mouseDownWrapper: Blockly.browserEvents.Data | null = null;
73+
private mouseDownWrapper_: Blockly.browserEvents.Data | null = null;
7474

7575
/**
7676
* Touch event wrapper.
@@ -558,8 +558,8 @@ class FieldMatrix extends Blockly.Field<string> {
558558
dispose() {
559559
super.dispose();
560560
this.matrixStage_ = null;
561-
if (this.mouseDownWrapper) {
562-
Blockly.browserEvents.unbind(this.mouseDownWrapper);
561+
if (this.mouseDownWrapper_) {
562+
Blockly.browserEvents.unbind(this.mouseDownWrapper_);
563563
}
564564
if (this.matrixTouchWrapper_) {
565565
Blockly.browserEvents.unbind(this.matrixTouchWrapper_);

src/fields/scratch_field_angle.ts

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,7 @@ class ScratchFieldAngle extends Blockly.FieldNumber {
5151
/**
5252
* Opaque identifier used to unbind event listener in dispose().
5353
*/
54-
private mouseDownWrapper: Blockly.browserEvents.Data;
54+
private mouseDownWrapper_: Blockly.browserEvents.Data;
5555

5656
/**
5757
* Opaque identifier used to unbind event listener in dispose().
@@ -142,8 +142,8 @@ class ScratchFieldAngle extends Blockly.FieldNumber {
142142
dispose() {
143143
super.dispose();
144144
this.gauge = null;
145-
if (this.mouseDownWrapper) {
146-
Blockly.browserEvents.unbind(this.mouseDownWrapper);
145+
if (this.mouseDownWrapper_) {
146+
Blockly.browserEvents.unbind(this.mouseDownWrapper_);
147147
}
148148
if (this.mouseUpWrapper) {
149149
Blockly.browserEvents.unbind(this.mouseUpWrapper);
@@ -286,7 +286,7 @@ class ScratchFieldAngle extends Blockly.FieldNumber {
286286
this.getSourceBlock() as Blockly.BlockSvg
287287
);
288288

289-
this.mouseDownWrapper = Blockly.browserEvents.bind(
289+
this.mouseDownWrapper_ = Blockly.browserEvents.bind(
290290
this.handle,
291291
"mousedown",
292292
this,

0 commit comments

Comments
 (0)