scratch-blocks 2.0.0-spork.1 → 2.0.0-spork.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (81) hide show
  1. package/CHANGELOG.md +14 -0
  2. package/dist/main.js +1 -1
  3. package/package.json +2 -3
  4. package/src/{block_reporting.js → block_reporting.ts} +7 -5
  5. package/src/blocks/{colour.js → colour.ts} +6 -6
  6. package/src/blocks/{control.js → control.ts} +21 -54
  7. package/src/blocks/{data.js → data.ts} +134 -142
  8. package/src/blocks/{event.js → event.ts} +12 -33
  9. package/src/blocks/{looks.js → looks.ts} +24 -73
  10. package/src/blocks/{math.js → math.ts} +6 -11
  11. package/src/blocks/{matrix.js → matrix.ts} +2 -3
  12. package/src/blocks/{motion.js → motion.ts} +23 -70
  13. package/src/blocks/{note.js → note.ts} +2 -3
  14. package/src/blocks/{operators.js → operators.ts} +18 -55
  15. package/src/blocks/{procedures.js → procedures.ts} +418 -269
  16. package/src/blocks/{sensing.js → sensing.ts} +21 -61
  17. package/src/blocks/{sound.js → sound.ts} +9 -28
  18. package/src/blocks/{text.js → text.ts} +1 -2
  19. package/src/blocks/{vertical_extensions.js → vertical_extensions.ts} +63 -100
  20. package/src/checkable_continuous_flyout.js +2 -2
  21. package/src/{checkbox_bubble.js → checkbox_bubble.ts} +36 -53
  22. package/src/{colours.js → colours.ts} +11 -4
  23. package/src/{constants.js → constants.ts} +13 -0
  24. package/src/{context_menu_items.js → context_menu_items.ts} +18 -12
  25. package/src/{data_category.js → data_category.ts} +216 -150
  26. package/src/events/{events_block_comment_base.js → events_block_comment_base.ts} +23 -4
  27. package/src/events/{events_block_comment_change.js → events_block_comment_change.ts} +29 -5
  28. package/src/events/{events_block_comment_collapse.js → events_block_comment_collapse.ts} +24 -6
  29. package/src/events/{events_block_comment_create.js → events_block_comment_create.ts} +36 -10
  30. package/src/events/{events_block_comment_delete.js → events_block_comment_delete.ts} +6 -2
  31. package/src/events/{events_block_comment_move.js → events_block_comment_move.ts} +36 -6
  32. package/src/events/events_block_comment_resize.ts +88 -0
  33. package/src/events/events_block_drag_end.ts +49 -0
  34. package/src/events/events_block_drag_outside.ts +44 -0
  35. package/src/events/{events_scratch_variable_create.js → events_scratch_variable_create.ts} +28 -15
  36. package/src/fields/{field_colour_slider.js → field_colour_slider.ts} +117 -106
  37. package/src/fields/{field_matrix.js → field_matrix.ts} +189 -215
  38. package/src/fields/{field_note.js → field_note.ts} +227 -286
  39. package/src/fields/{field_textinput_removable.js → field_textinput_removable.ts} +17 -20
  40. package/src/fields/{field_variable_getter.js → field_variable_getter.ts} +28 -17
  41. package/src/fields/{field_vertical_separator.js → field_vertical_separator.ts} +14 -30
  42. package/src/fields/{field_angle.js → scratch_field_angle.ts} +124 -80
  43. package/src/fields/{field_dropdown.js → scratch_field_dropdown.ts} +9 -7
  44. package/src/fields/{field_number.js → scratch_field_number.ts} +60 -55
  45. package/src/fields/{field_variable.js → scratch_field_variable.ts} +46 -27
  46. package/src/{flyout_checkbox_icon.js → flyout_checkbox_icon.ts} +15 -19
  47. package/src/{glows.js → glows.ts} +29 -18
  48. package/src/index.ts +59 -60
  49. package/src/procedures.ts +462 -0
  50. package/src/{recyclable_block_flyout_inflater.js → recyclable_block_flyout_inflater.ts} +35 -35
  51. package/src/renderer/{bowler_hat.js → bowler_hat.ts} +1 -1
  52. package/src/renderer/{constants.js → constants.ts} +26 -12
  53. package/src/renderer/{drawer.js → drawer.ts} +8 -3
  54. package/src/renderer/{path_object.js → path_object.ts} +2 -2
  55. package/src/renderer/{render_info.js → render_info.ts} +19 -7
  56. package/src/renderer/renderer.ts +76 -0
  57. package/src/{scratch_block_paster.js → scratch_block_paster.ts} +9 -7
  58. package/src/scratch_blocks_utils.ts +39 -0
  59. package/src/{scratch_comment_icon.js → scratch_comment_icon.ts} +43 -26
  60. package/src/scratch_connection_checker.ts +44 -0
  61. package/src/{scratch_continuous_category.js → scratch_continuous_category.ts} +20 -13
  62. package/src/{scratch_continuous_toolbox.js → scratch_continuous_toolbox.ts} +20 -18
  63. package/src/{scratch_dragger.js → scratch_dragger.ts} +97 -28
  64. package/src/{scratch_variable_map.js → scratch_variable_map.ts} +4 -1
  65. package/src/scratch_variable_model.ts +30 -0
  66. package/src/{shadows.js → shadows.ts} +8 -4
  67. package/src/{status_indicator_label.js → status_indicator_label.ts} +24 -36
  68. package/src/{status_indicator_label_flyout_inflater.js → status_indicator_label_flyout_inflater.ts} +9 -7
  69. package/src/{variables.js → variables.ts} +153 -123
  70. package/tsconfig.json +4 -2
  71. package/src/categories.js +0 -15
  72. package/src/events/events_block_comment_resize.js +0 -52
  73. package/src/events/events_block_drag_end.js +0 -33
  74. package/src/events/events_block_drag_outside.js +0 -30
  75. package/src/procedures.js +0 -425
  76. package/src/renderer/renderer.js +0 -74
  77. package/src/scratch_blocks_utils.js +0 -148
  78. package/src/scratch_connection_checker.js +0 -29
  79. package/src/scratch_variable_model.js +0 -24
  80. /package/src/{css.js → css.ts} +0 -0
  81. /package/{continuous-toolbox.d.ts → types/continuous-toolbox.d.ts} +0 -0
@@ -23,21 +23,14 @@
23
23
  * @author pkaplan@media.mit.edu (Paul Kaplan)
24
24
  */
25
25
  import * as Blockly from "blockly/core";
26
+ import type { ProcedureDeclarationBlock } from "../blocks/procedures";
26
27
 
27
28
  /**
28
29
  * Class for an editable text field displaying a deletion icon when selected.
29
- * @param {string} text The initial content of the field.
30
- * @param {Function=} opt_validator An optional function that is called
31
- * to validate any constraints on what the user entered. Takes the new
32
- * text as an argument and returns either the accepted text, a replacement
33
- * text, or null to abort the change.
34
- * @param {RegExp=} opt_restrictor An optional regular expression to restrict
35
- * typed text to. Text that doesn't match the restrictor will never show
36
- * in the text field.
37
- * @extends {Blockly.FieldTextInput}
38
- * @constructor
39
30
  */
40
31
  export class FieldTextInputRemovable extends Blockly.FieldTextInput {
32
+ private removeButtonMouseWrapper_?: Blockly.browserEvents.Data;
33
+
41
34
  /**
42
35
  * Show the inline free-text editor on top of the text with the remove button.
43
36
  */
@@ -68,11 +61,12 @@ export class FieldTextInputRemovable extends Blockly.FieldTextInput {
68
61
  /**
69
62
  * Function to call when remove button is called. Checks for removeFieldCallback
70
63
  * on sourceBlock and calls it if possible.
71
- * @private
72
64
  */
73
- removeCallback_() {
74
- if (this.sourceBlock_ && this.sourceBlock_.removeFieldCallback) {
75
- this.sourceBlock_.removeFieldCallback(this);
65
+ private removeCallback_() {
66
+ if (this.sourceBlock_ && "removeFieldCallback" in this.sourceBlock_) {
67
+ (this.sourceBlock_ as ProcedureDeclarationBlock).removeFieldCallback(
68
+ this
69
+ );
76
70
  } else {
77
71
  console.warn("Expected a source block with removeFieldCallback");
78
72
  }
@@ -81,13 +75,16 @@ export class FieldTextInputRemovable extends Blockly.FieldTextInput {
81
75
  /**
82
76
  * Helper function to construct a FieldTextInputRemovable from a JSON arg object,
83
77
  * dereferencing any string table references.
84
- * @param {!Object} options A JSON object with options (text, class, and
85
- * spellcheck).
86
- * @returns {!Blockly.FieldTextInputRemovable} The new text input.
87
- * @public
78
+ *
79
+ * @param options A JSON object with options (text, class, and spellcheck).
80
+ * @returns The new text input.
88
81
  */
89
- fromJson(options) {
90
- const text = Blockly.utils.replaceMessageReferences(options["text"]);
82
+ fromJson(
83
+ options: Blockly.FieldTextInputFromJsonConfig
84
+ ): FieldTextInputRemovable {
85
+ const text = Blockly.utils.parsing.replaceMessageReferences(
86
+ options["text"]
87
+ );
91
88
  const field = new FieldTextInputRemovable(text, null, options);
92
89
  if (typeof options["spellcheck"] == "boolean") {
93
90
  field.setSpellcheck(options["spellcheck"]);
@@ -27,29 +27,36 @@ import * as Blockly from "blockly/core";
27
27
 
28
28
  /**
29
29
  * Class for a variable getter field.
30
- * @param {string} allowedVariableType The type of variables this field can display.
31
30
  */
32
31
  class FieldVariableGetter extends Blockly.FieldLabel {
33
- constructor(allowedVariableType = "") {
32
+ private variable: Blockly.IVariableModel<Blockly.IVariableState> | null =
33
+ null;
34
+
35
+ /**
36
+ * Creates a new FieldVariableGetter.
37
+ *
38
+ * @param allowedVariableType The type of variables this field can display.
39
+ */
40
+ constructor(private allowedVariableType = "") {
34
41
  super(Blockly.Field.SKIP_SETUP);
35
42
  this.SERIALIZABLE = true;
36
- this.allowedVariableType = allowedVariableType;
37
- this.variable = null;
38
43
  }
39
44
 
40
45
  /**
41
46
  * Returns the ID of this field's variable.
42
- * @return {string} The ID of this field's variable.
47
+ *
48
+ * @returns The ID of this field's variable.
43
49
  */
44
- getValue() {
50
+ getValue(): string {
45
51
  return this.variable?.getId() ?? "";
46
52
  }
47
53
 
48
54
  /**
49
55
  * Returns the name of this field's variable.
50
- * @return {string} The name of this field's variable.
56
+ *
57
+ * @returns The name of this field's variable.
51
58
  */
52
- getText() {
59
+ getText(): string {
53
60
  return this.variable?.getName() ?? "";
54
61
  }
55
62
 
@@ -57,19 +64,19 @@ class FieldVariableGetter extends Blockly.FieldLabel {
57
64
  * Get the variable model for the variable associated with this field.
58
65
  * Not guaranteed to be in the variable map on the workspace (e.g. if accessed
59
66
  * after the variable has been deleted).
60
- * @return {?Blockly.VariableModel} the selected variable, or null if none was
61
- * selected.
62
- * @package
67
+ *
68
+ * @returns the selected variable, or null if none was selected.
63
69
  */
64
- getVariable() {
70
+ getVariable(): Blockly.IVariableModel<Blockly.IVariableState> | null {
65
71
  return this.variable;
66
72
  }
67
73
 
68
74
  /**
69
75
  * Updates this field's variable to one with the given ID.
70
- * @param {string} newVariableId ID of a variable this field should represent.
76
+ *
77
+ * @param newVariableId ID of a variable this field should represent.
71
78
  */
72
- doValueUpdate_(newVariableId) {
79
+ doValueUpdate_(newVariableId: string) {
73
80
  super.doValueUpdate_(newVariableId);
74
81
  const workspace = this.getSourceBlock().workspace;
75
82
  this.variable = Blockly.Variables.getVariable(workspace, newVariableId);
@@ -85,15 +92,15 @@ class FieldVariableGetter extends Blockly.FieldLabel {
85
92
  this.forceRerender();
86
93
  }
87
94
 
88
- static fromJson(options) {
95
+ static fromJson(options: FieldVariableGetterConfig) {
89
96
  return new FieldVariableGetter(options["allowedVariableType"]);
90
97
  }
91
98
 
92
- fromXml(element) {
99
+ fromXml(element: Element) {
93
100
  this.setValue(element.getAttribute("id"));
94
101
  }
95
102
 
96
- toXml(element) {
103
+ toXml(element: Element): Element {
97
104
  element.setAttribute("id", this.variable.getId());
98
105
  element.setAttribute("variabletype", this.variable.getType());
99
106
  element.textContent = this.variable.getName();
@@ -101,6 +108,10 @@ class FieldVariableGetter extends Blockly.FieldLabel {
101
108
  }
102
109
  }
103
110
 
111
+ interface FieldVariableGetterConfig extends Blockly.FieldLabelConfig {
112
+ allowedVariableType?: string;
113
+ }
114
+
104
115
  /**
105
116
  * Register the field and any dependencies.
106
117
  */
@@ -26,10 +26,10 @@ import * as Blockly from "blockly/core";
26
26
 
27
27
  /**
28
28
  * Class for a vertical separator line.
29
- * @extends {Blockly.Field}
30
- * @constructor
31
29
  */
32
30
  class FieldVerticalSeparator extends Blockly.Field {
31
+ private lineElement?: SVGLineElement;
32
+
33
33
  constructor() {
34
34
  super(Blockly.Field.SKIP_SETUP);
35
35
  /**
@@ -39,17 +39,10 @@ class FieldVerticalSeparator extends Blockly.Field {
39
39
  }
40
40
 
41
41
  /**
42
- * Construct a FieldVerticalSeparator from a JSON arg object.
43
- * @param {!Object} _element A JSON object with options (unused, but passed in
44
- * by Field.fromJson).
45
- * @returns {!Blockly.FieldVerticalSeparator} The new field instance.
46
- * @package
47
- * @nocollapse
42
+ * Construct a FieldVerticalSeparator.
43
+ * @returns The new field instance.
48
44
  */
49
- static fromJson = function (
50
- /* eslint-disable no-unused-vars */ _element
51
- /* eslint-enable no-unused-vars */
52
- ) {
45
+ static fromJson = function () {
53
46
  return new FieldVerticalSeparator();
54
47
  };
55
48
 
@@ -57,14 +50,14 @@ class FieldVerticalSeparator extends Blockly.Field {
57
50
  * Install this field on a block.
58
51
  */
59
52
  initView() {
60
- const height = 10 * this.getConstants().GRID_UNIT;
53
+ const height =
54
+ 10 * (this.getConstants() as Blockly.zelos.ConstantProvider).GRID_UNIT;
61
55
  this.size_ = new Blockly.utils.Size(1, height);
62
56
 
63
- /** @type {SVGElement} */
64
- this.lineElement_ = Blockly.utils.dom.createSvgElement(
57
+ this.lineElement = Blockly.utils.dom.createSvgElement(
65
58
  "line",
66
59
  {
67
- stroke: this.sourceBlock_.getColourSecondary(),
60
+ stroke: (this.sourceBlock_ as Blockly.BlockSvg).getColourSecondary(),
68
61
  "stroke-linecap": "round",
69
62
  x1: 0,
70
63
  y1: 0,
@@ -79,19 +72,17 @@ class FieldVerticalSeparator extends Blockly.Field {
79
72
  * Set the height of the line element, without adjusting the field's height.
80
73
  * This allows the line's height to be changed without causing it to be
81
74
  * centered with the new height (needed for correct rendering of hat blocks).
82
- * @param {number} newHeight the new height for the line.
75
+ * @param newHeight the new height for the line.
83
76
  * @package
84
77
  */
85
- setLineHeight(newHeight) {
86
- this.lineElement_.setAttribute("y2", newHeight);
78
+ setLineHeight(newHeight: number) {
79
+ this.lineElement.setAttribute("y2", `${newHeight}`);
87
80
  }
88
81
 
89
82
  /**
90
83
  * Get the value of this field. A no-op in this case.
91
- * @return {string} null.
92
- * @override
93
84
  */
94
- getValue() {
85
+ getValue(): string | null {
95
86
  return null;
96
87
  }
97
88
 
@@ -101,19 +92,13 @@ class FieldVerticalSeparator extends Blockly.Field {
101
92
 
102
93
  /**
103
94
  * Set the value of this field. A no-op in this case.
104
- * @param {?string} src New value.
105
- * @override
106
95
  */
107
- setValue(
108
- /* eslint-disable no-unused-vars */ src
109
- /* eslint-enable no-unused-vars */
110
- ) {
96
+ setValue() {
111
97
  return;
112
98
  }
113
99
 
114
100
  /**
115
101
  * Separator lines are fixed width, no need to render.
116
- * @private
117
102
  */
118
103
  render_() {
119
104
  // NOP
@@ -121,7 +106,6 @@ class FieldVerticalSeparator extends Blockly.Field {
121
106
 
122
107
  /**
123
108
  * Separator lines are fixed width, no need to update.
124
- * @private
125
109
  */
126
110
  updateWidth() {
127
111
  // NOP
@@ -26,17 +26,42 @@
26
26
 
27
27
  import * as Blockly from "blockly/core";
28
28
 
29
- class FieldAngle extends Blockly.FieldNumber {
29
+ class ScratchFieldAngle extends Blockly.FieldNumber {
30
30
  /**
31
- * Construct a FieldAngle from a JSON arg object.
32
- * @param {!Object} options A JSON object with options (angle).
33
- * @returns {!Blockly.FieldAngle} The new field instance.
34
- * @package
35
- * @nocollapse
31
+ * The highlighted portion of the angle picker circle, between 0º and the
32
+ * selected angle.
36
33
  */
37
- fromJson(options) {
38
- return new FieldAngle(options["angle"]);
39
- }
34
+ private gauge?: SVGPathElement;
35
+
36
+ /**
37
+ * The line to the angle picker handle.
38
+ */
39
+ private line?: SVGLineElement;
40
+
41
+ /**
42
+ * The grabbable handle used to choose an angle.
43
+ */
44
+ private handle?: SVGGElement;
45
+
46
+ /**
47
+ * The arrow graphic shown on the grab handle.
48
+ */
49
+ private arrow?: SVGImageElement;
50
+
51
+ /**
52
+ * Opaque identifier used to unbind event listener in dispose().
53
+ */
54
+ private mouseDownWrapper_: Blockly.browserEvents.Data;
55
+
56
+ /**
57
+ * Opaque identifier used to unbind event listener in dispose().
58
+ */
59
+ private mouseMoveWrapper: Blockly.browserEvents.Data;
60
+
61
+ /**
62
+ * Opaque identifier used to unbind event listener in dispose().
63
+ */
64
+ private mouseUpWrapper: Blockly.browserEvents.Data;
40
65
 
41
66
  /**
42
67
  * Round angles to the nearest 15 degrees when using mouse.
@@ -89,7 +114,8 @@ class FieldAngle extends Blockly.FieldNumber {
89
114
  ARROW_WIDTH = this.HANDLE_RADIUS;
90
115
 
91
116
  /**
92
- * Half the stroke-width used for the "glow" around the drag handle, rounded up to nearest whole pixel
117
+ * Half the stroke-width used for the "glow" around the drag handle, rounded
118
+ * up to nearest whole pixel.
93
119
  */
94
120
 
95
121
  HANDLE_GLOW_WIDTH = 3;
@@ -111,36 +137,33 @@ class FieldAngle extends Blockly.FieldNumber {
111
137
  ARROW_SVG_PATH = "icons/arrow.svg";
112
138
 
113
139
  /**
114
- * Clean up this FieldAngle, as well as the inherited FieldTextInput.
115
- * @return {!Function} Closure to call on destruction of the WidgetDiv.
116
- * @private
140
+ * Clean up this FieldAngle, as well as the inherited FieldNumber.
117
141
  */
118
142
  dispose() {
119
143
  super.dispose();
120
- this.gauge_ = null;
144
+ this.gauge = null;
121
145
  if (this.mouseDownWrapper_) {
122
146
  Blockly.browserEvents.unbind(this.mouseDownWrapper_);
123
147
  }
124
- if (this.mouseUpWrapper_) {
125
- Blockly.browserEvents.unbind(this.mouseUpWrapper_);
148
+ if (this.mouseUpWrapper) {
149
+ Blockly.browserEvents.unbind(this.mouseUpWrapper);
126
150
  }
127
- if (this.mouseMoveWrapper_) {
128
- Blockly.browserEvents.unbind(this.mouseMoveWrapper_);
151
+ if (this.mouseMoveWrapper) {
152
+ Blockly.browserEvents.unbind(this.mouseMoveWrapper);
129
153
  }
130
154
  }
131
155
 
132
156
  /**
133
157
  * Show the inline free-text editor on top of the text.
134
- * @private
135
158
  */
136
- showEditor_(event) {
159
+ showEditor_(event: PointerEvent) {
137
160
  super.showEditor_(event);
138
161
  // If there is an existing drop-down someone else owns, hide it immediately and clear it.
139
162
  Blockly.DropDownDiv.hideWithoutAnimation();
140
163
  Blockly.DropDownDiv.clearContent();
141
- var div = Blockly.DropDownDiv.getContentDiv();
164
+ const div = Blockly.DropDownDiv.getContentDiv();
142
165
  // Build the SVG DOM.
143
- var svg = Blockly.utils.dom.createSvgElement(
166
+ const svg = Blockly.utils.dom.createSvgElement(
144
167
  "svg",
145
168
  {
146
169
  xmlns: "http://www.w3.org/2000/svg",
@@ -158,19 +181,23 @@ class FieldAngle extends Blockly.FieldNumber {
158
181
  cx: this.HALF,
159
182
  cy: this.HALF,
160
183
  r: this.RADIUS,
161
- fill: this.getSourceBlock().getParent().getColourSecondary(),
162
- stroke: this.getSourceBlock().getParent().getColourTertiary(),
184
+ fill: (
185
+ this.getSourceBlock().getParent() as Blockly.BlockSvg
186
+ ).getColourSecondary(),
187
+ stroke: (
188
+ this.getSourceBlock().getParent() as Blockly.BlockSvg
189
+ ).getColourTertiary(),
163
190
  class: "blocklyAngleCircle",
164
191
  },
165
192
  svg
166
193
  );
167
- this.gauge_ = Blockly.utils.dom.createSvgElement(
194
+ this.gauge = Blockly.utils.dom.createSvgElement(
168
195
  "path",
169
196
  { class: "blocklyAngleGauge" },
170
197
  svg
171
198
  );
172
- // The moving line, x2 and y2 are set in updateGraph_
173
- this.line_ = Blockly.utils.dom.createSvgElement(
199
+ // The moving line, x2 and y2 are set in updateGraph
200
+ this.line = Blockly.utils.dom.createSvgElement(
174
201
  "line",
175
202
  {
176
203
  x1: this.HALF,
@@ -180,7 +207,7 @@ class FieldAngle extends Blockly.FieldNumber {
180
207
  svg
181
208
  );
182
209
  // The fixed vertical line at the offset
183
- var offsetRadians = (Math.PI * this.OFFSET) / 180;
210
+ const offsetRadians = (Math.PI * this.OFFSET) / 180;
184
211
  Blockly.utils.dom.createSvgElement(
185
212
  "line",
186
213
  {
@@ -193,7 +220,7 @@ class FieldAngle extends Blockly.FieldNumber {
193
220
  svg
194
221
  );
195
222
  // Draw markers around the edge.
196
- for (var angle = 0; angle < 360; angle += 15) {
223
+ for (let angle = 0; angle < 360; angle += 15) {
197
224
  Blockly.utils.dom.createSvgElement(
198
225
  "line",
199
226
  {
@@ -220,7 +247,7 @@ class FieldAngle extends Blockly.FieldNumber {
220
247
  svg
221
248
  );
222
249
  // Handle group: a circle and the arrow image
223
- this.handle_ = Blockly.utils.dom.createSvgElement("g", {}, svg);
250
+ this.handle = Blockly.utils.dom.createSvgElement("g", {}, svg);
224
251
  Blockly.utils.dom.createSvgElement(
225
252
  "circle",
226
253
  {
@@ -229,9 +256,9 @@ class FieldAngle extends Blockly.FieldNumber {
229
256
  r: this.HANDLE_RADIUS,
230
257
  class: "blocklyAngleDragHandle",
231
258
  },
232
- this.handle_
259
+ this.handle
233
260
  );
234
- this.arrowSvg_ = Blockly.utils.dom.createSvgElement(
261
+ this.arrow = Blockly.utils.dom.createSvgElement(
235
262
  "image",
236
263
  {
237
264
  width: this.ARROW_WIDTH,
@@ -240,9 +267,9 @@ class FieldAngle extends Blockly.FieldNumber {
240
267
  y: -this.ARROW_WIDTH / 2,
241
268
  class: "blocklyAngleDragArrow",
242
269
  },
243
- this.handle_
270
+ this.handle
244
271
  );
245
- this.arrowSvg_.setAttributeNS(
272
+ this.arrow.setAttributeNS(
246
273
  "http://www.w3.org/1999/xlink",
247
274
  "xlink:href",
248
275
  Blockly.getMainWorkspace().options.pathToMedia + this.ARROW_SVG_PATH
@@ -250,32 +277,36 @@ class FieldAngle extends Blockly.FieldNumber {
250
277
 
251
278
  Blockly.DropDownDiv.setColour(
252
279
  this.getSourceBlock().getParent().getColour(),
253
- this.getSourceBlock().getParent().getColourTertiary()
280
+ (
281
+ this.getSourceBlock().getParent() as Blockly.BlockSvg
282
+ ).getColourTertiary()
283
+ );
284
+ Blockly.DropDownDiv.showPositionedByBlock(
285
+ this,
286
+ this.getSourceBlock() as Blockly.BlockSvg
254
287
  );
255
- Blockly.DropDownDiv.showPositionedByBlock(this, this.getSourceBlock());
256
288
 
257
289
  this.mouseDownWrapper_ = Blockly.browserEvents.bind(
258
- this.handle_,
290
+ this.handle,
259
291
  "mousedown",
260
292
  this,
261
293
  this.onMouseDown
262
294
  );
263
295
 
264
- this.updateGraph_();
296
+ this.updateGraph();
265
297
  }
266
298
 
267
299
  /**
268
300
  * Set the angle to match the mouse's position.
269
- * @param {!Event} e Mouse move event.
270
301
  */
271
302
  onMouseDown() {
272
- this.mouseMoveWrapper_ = Blockly.browserEvents.bind(
303
+ this.mouseMoveWrapper = Blockly.browserEvents.bind(
273
304
  document.body,
274
305
  "mousemove",
275
306
  this,
276
307
  this.onMouseMove
277
308
  );
278
- this.mouseUpWrapper_ = Blockly.browserEvents.bind(
309
+ this.mouseUpWrapper = Blockly.browserEvents.bind(
279
310
  document.body,
280
311
  "mouseup",
281
312
  this,
@@ -285,23 +316,22 @@ class FieldAngle extends Blockly.FieldNumber {
285
316
 
286
317
  /**
287
318
  * Set the angle to match the mouse's position.
288
- * @param {!Event} e Mouse move event.
289
319
  */
290
320
  onMouseUp() {
291
- Blockly.browserEvents.unbind(this.mouseMoveWrapper_);
292
- Blockly.browserEvents.unbind(this.mouseUpWrapper_);
321
+ Blockly.browserEvents.unbind(this.mouseMoveWrapper);
322
+ Blockly.browserEvents.unbind(this.mouseUpWrapper);
293
323
  }
294
324
 
295
325
  /**
296
326
  * Set the angle to match the mouse's position.
297
- * @param {!Event} e Mouse move event.
327
+ * @param e Mouse move event.
298
328
  */
299
- onMouseMove(e) {
329
+ onMouseMove(e: PointerEvent) {
300
330
  e.preventDefault();
301
- var bBox = this.gauge_.ownerSVGElement.getBoundingClientRect();
302
- var dx = e.clientX - bBox.left - this.HALF;
303
- var dy = e.clientY - bBox.top - this.HALF;
304
- var angle = Math.atan(-dy / dx);
331
+ const bBox = this.gauge.ownerSVGElement.getBoundingClientRect();
332
+ const dx = e.clientX - bBox.left - this.HALF;
333
+ const dy = e.clientY - bBox.top - this.HALF;
334
+ let angle = Math.atan(-dy / dx);
305
335
  if (isNaN(angle)) {
306
336
  // This shouldn't happen, but let's not let this error propagate further.
307
337
  return;
@@ -328,29 +358,28 @@ class FieldAngle extends Blockly.FieldNumber {
328
358
 
329
359
  /**
330
360
  * Redraw the graph with the current angle.
331
- * @private
332
361
  */
333
- updateGraph_() {
334
- if (!this.gauge_) {
362
+ private updateGraph() {
363
+ if (!this.gauge) {
335
364
  return;
336
365
  }
337
- var angleDegrees = (this.getValue() % 360) + this.OFFSET;
338
- var angleRadians = this.toRadians(angleDegrees);
339
- var path = ["M ", this.HALF, ",", this.HALF];
340
- var x2 = this.HALF;
341
- var y2 = this.HALF;
366
+ const angleDegrees = (Number(this.getValue()) % 360) + this.OFFSET;
367
+ let angleRadians = this.toRadians(angleDegrees);
368
+ const path = ["M ", this.HALF, ",", this.HALF];
369
+ let x2 = this.HALF;
370
+ let y2 = this.HALF;
342
371
  if (!isNaN(angleRadians)) {
343
- var angle1 = this.toRadians(this.OFFSET);
344
- var x1 = Math.cos(angle1) * this.RADIUS;
345
- var y1 = Math.sin(angle1) * -this.RADIUS;
372
+ const angle1 = this.toRadians(this.OFFSET);
373
+ const x1 = Math.cos(angle1) * this.RADIUS;
374
+ const y1 = Math.sin(angle1) * -this.RADIUS;
346
375
  if (this.CLOCKWISE) {
347
376
  angleRadians = 2 * angle1 - angleRadians;
348
377
  }
349
378
  x2 += Math.cos(angleRadians) * this.RADIUS;
350
379
  y2 -= Math.sin(angleRadians) * this.RADIUS;
351
380
  // Use large arc only if input value is greater than wrap
352
- var largeFlag = Math.abs(angleDegrees - this.OFFSET) > 180 ? 1 : 0;
353
- var sweepFlag = Number(this.CLOCKWISE);
381
+ const largeFlag = Math.abs(angleDegrees - this.OFFSET) > 180 ? 1 : 0;
382
+ let sweepFlag = Number(this.CLOCKWISE);
354
383
  if (angleDegrees < this.OFFSET) {
355
384
  sweepFlag = 1 - sweepFlag; // Sweep opposite direction if less than the offset
356
385
  }
@@ -375,29 +404,30 @@ class FieldAngle extends Blockly.FieldNumber {
375
404
  );
376
405
 
377
406
  // Image rotation needs to be set in degrees
407
+ let imageRotation: number;
378
408
  if (this.CLOCKWISE) {
379
- var imageRotation = angleDegrees + 2 * this.OFFSET;
409
+ imageRotation = angleDegrees + 2 * this.OFFSET;
380
410
  } else {
381
- var imageRotation = -angleDegrees;
411
+ imageRotation = -angleDegrees;
382
412
  }
383
- this.arrowSvg_.setAttribute("transform", "rotate(" + imageRotation + ")");
413
+ this.arrow.setAttribute("transform", "rotate(" + imageRotation + ")");
384
414
  }
385
- this.gauge_.setAttribute("d", path.join(""));
386
- this.line_.setAttribute("x2", x2);
387
- this.line_.setAttribute("y2", y2);
388
- this.handle_.setAttribute("transform", "translate(" + x2 + "," + y2 + ")");
415
+ this.gauge.setAttribute("d", path.join(""));
416
+ this.line.setAttribute("x2", `${x2}`);
417
+ this.line.setAttribute("y2", `${y2}`);
418
+ this.handle.setAttribute("transform", "translate(" + x2 + "," + y2 + ")");
389
419
  }
390
420
 
391
421
  /**
392
422
  * Ensure that only an angle may be entered.
393
- * @param {string} text The user's text.
394
- * @return {?string} A string representing a valid angle, or null if invalid.
423
+ * @param text The user's text.
424
+ * @returns A string representing a valid angle, or null if invalid.
395
425
  */
396
- doClassValidation_(text) {
426
+ doClassValidation_(text: string): number | null {
397
427
  if (text === null) {
398
428
  return null;
399
429
  }
400
- var n = parseFloat(text || 0);
430
+ let n = parseFloat(text || "0");
401
431
  if (isNaN(n)) {
402
432
  return null;
403
433
  }
@@ -411,23 +441,37 @@ class FieldAngle extends Blockly.FieldNumber {
411
441
  return Number(n);
412
442
  }
413
443
 
414
- doValueUpdate_(newValue) {
444
+ doValueUpdate_(newValue: number) {
415
445
  super.doValueUpdate_(newValue);
416
- this.updateGraph_();
446
+ this.updateGraph();
417
447
  }
418
448
 
419
- toDegrees(radians) {
449
+ toDegrees(radians: number) {
420
450
  return (radians * 180) / Math.PI;
421
451
  }
422
452
 
423
- toRadians(degrees) {
453
+ toRadians(degrees: number) {
424
454
  return (degrees * Math.PI) / 180;
425
455
  }
456
+
457
+ /**
458
+ * Construct a FieldAngle from a JSON arg object.
459
+ *
460
+ * @param options A JSON object with options (angle).
461
+ * @returns The new field instance.
462
+ */
463
+ fromJson(options: ScratchFieldAngleJsonConfig): ScratchFieldAngle {
464
+ return new ScratchFieldAngle(options["angle"]);
465
+ }
466
+ }
467
+
468
+ export interface ScratchFieldAngleJsonConfig {
469
+ angle?: number;
426
470
  }
427
471
 
428
472
  /**
429
473
  * Register the field and any dependencies.
430
474
  */
431
- export function registerFieldAngle() {
432
- Blockly.fieldRegistry.register("field_angle", FieldAngle);
475
+ export function registerScratchFieldAngle() {
476
+ Blockly.fieldRegistry.register("field_angle", ScratchFieldAngle);
433
477
  }