scratch-blocks 2.0.2 → 2.0.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 (274) hide show
  1. package/commitlint.config.js +2 -2
  2. package/dist/main.mjs +1 -2
  3. package/dist/types/msg/scratch_msgs.d.ts.map +1 -1
  4. package/dist/types/src/block_reporting.d.ts.map +1 -1
  5. package/dist/types/src/blocks/colour.d.ts +0 -19
  6. package/dist/types/src/blocks/colour.d.ts.map +1 -1
  7. package/dist/types/src/blocks/control.d.ts +0 -19
  8. package/dist/types/src/blocks/control.d.ts.map +1 -1
  9. package/dist/types/src/blocks/data.d.ts +0 -19
  10. package/dist/types/src/blocks/data.d.ts.map +1 -1
  11. package/dist/types/src/blocks/event.d.ts +0 -19
  12. package/dist/types/src/blocks/event.d.ts.map +1 -1
  13. package/dist/types/src/blocks/looks.d.ts +0 -19
  14. package/dist/types/src/blocks/looks.d.ts.map +1 -1
  15. package/dist/types/src/blocks/math.d.ts +0 -19
  16. package/dist/types/src/blocks/math.d.ts.map +1 -1
  17. package/dist/types/src/blocks/matrix.d.ts +0 -19
  18. package/dist/types/src/blocks/matrix.d.ts.map +1 -1
  19. package/dist/types/src/blocks/motion.d.ts +0 -19
  20. package/dist/types/src/blocks/motion.d.ts.map +1 -1
  21. package/dist/types/src/blocks/note.d.ts +0 -19
  22. package/dist/types/src/blocks/note.d.ts.map +1 -1
  23. package/dist/types/src/blocks/operators.d.ts +0 -19
  24. package/dist/types/src/blocks/operators.d.ts.map +1 -1
  25. package/dist/types/src/blocks/procedures.d.ts +6 -9
  26. package/dist/types/src/blocks/procedures.d.ts.map +1 -1
  27. package/dist/types/src/blocks/sensing.d.ts +0 -19
  28. package/dist/types/src/blocks/sensing.d.ts.map +1 -1
  29. package/dist/types/src/blocks/sound.d.ts +0 -19
  30. package/dist/types/src/blocks/sound.d.ts.map +1 -1
  31. package/dist/types/src/blocks/text.d.ts +0 -19
  32. package/dist/types/src/blocks/text.d.ts.map +1 -1
  33. package/dist/types/src/blocks/vertical_extensions.d.ts +0 -19
  34. package/dist/types/src/blocks/vertical_extensions.d.ts.map +1 -1
  35. package/dist/types/src/checkable_continuous_flyout.d.ts +2 -7
  36. package/dist/types/src/checkable_continuous_flyout.d.ts.map +1 -1
  37. package/dist/types/src/checkbox_bubble.d.ts +13 -12
  38. package/dist/types/src/checkbox_bubble.d.ts.map +1 -1
  39. package/dist/types/src/colours.d.ts.map +1 -1
  40. package/dist/types/src/constants.d.ts +0 -7
  41. package/dist/types/src/constants.d.ts.map +1 -1
  42. package/dist/types/src/context_menu_items.d.ts +0 -5
  43. package/dist/types/src/context_menu_items.d.ts.map +1 -1
  44. package/dist/types/src/data_category.d.ts +2 -4
  45. package/dist/types/src/data_category.d.ts.map +1 -1
  46. package/dist/types/src/events/events_block_comment_base.d.ts +2 -3
  47. package/dist/types/src/events/events_block_comment_base.d.ts.map +1 -1
  48. package/dist/types/src/events/events_block_comment_change.d.ts +0 -5
  49. package/dist/types/src/events/events_block_comment_change.d.ts.map +1 -1
  50. package/dist/types/src/events/events_block_comment_collapse.d.ts +0 -5
  51. package/dist/types/src/events/events_block_comment_collapse.d.ts.map +1 -1
  52. package/dist/types/src/events/events_block_comment_create.d.ts +0 -5
  53. package/dist/types/src/events/events_block_comment_create.d.ts.map +1 -1
  54. package/dist/types/src/events/events_block_comment_delete.d.ts +0 -5
  55. package/dist/types/src/events/events_block_comment_delete.d.ts.map +1 -1
  56. package/dist/types/src/events/events_block_comment_move.d.ts +0 -5
  57. package/dist/types/src/events/events_block_comment_move.d.ts.map +1 -1
  58. package/dist/types/src/events/events_block_comment_resize.d.ts +0 -5
  59. package/dist/types/src/events/events_block_comment_resize.d.ts.map +1 -1
  60. package/dist/types/src/events/events_block_drag_end.d.ts +1 -2
  61. package/dist/types/src/events/events_block_drag_end.d.ts.map +1 -1
  62. package/dist/types/src/events/events_block_drag_outside.d.ts +1 -2
  63. package/dist/types/src/events/events_block_drag_outside.d.ts.map +1 -1
  64. package/dist/types/src/events/events_scratch_variable_create.d.ts +0 -5
  65. package/dist/types/src/events/events_scratch_variable_create.d.ts.map +1 -1
  66. package/dist/types/src/fields/field_colour_slider.d.ts +3 -27
  67. package/dist/types/src/fields/field_colour_slider.d.ts.map +1 -1
  68. package/dist/types/src/fields/field_matrix.d.ts +0 -19
  69. package/dist/types/src/fields/field_matrix.d.ts.map +1 -1
  70. package/dist/types/src/fields/field_note.d.ts +8 -23
  71. package/dist/types/src/fields/field_note.d.ts.map +1 -1
  72. package/dist/types/src/fields/field_textinput_removable.d.ts +2 -4
  73. package/dist/types/src/fields/field_textinput_removable.d.ts.map +1 -1
  74. package/dist/types/src/fields/field_variable_getter.d.ts +0 -19
  75. package/dist/types/src/fields/field_variable_getter.d.ts.map +1 -1
  76. package/dist/types/src/fields/field_vertical_separator.d.ts +0 -19
  77. package/dist/types/src/fields/field_vertical_separator.d.ts.map +1 -1
  78. package/dist/types/src/fields/scratch_field_angle.d.ts +0 -19
  79. package/dist/types/src/fields/scratch_field_angle.d.ts.map +1 -1
  80. package/dist/types/src/fields/scratch_field_dropdown.d.ts +0 -5
  81. package/dist/types/src/fields/scratch_field_dropdown.d.ts.map +1 -1
  82. package/dist/types/src/fields/scratch_field_number.d.ts +0 -19
  83. package/dist/types/src/fields/scratch_field_number.d.ts.map +1 -1
  84. package/dist/types/src/fields/scratch_field_variable.d.ts +4 -7
  85. package/dist/types/src/fields/scratch_field_variable.d.ts.map +1 -1
  86. package/dist/types/src/flyout_checkbox_icon.d.ts +2 -3
  87. package/dist/types/src/flyout_checkbox_icon.d.ts.map +1 -1
  88. package/dist/types/src/glows.d.ts +1 -3
  89. package/dist/types/src/glows.d.ts.map +1 -1
  90. package/dist/types/src/index.d.ts +50 -51
  91. package/dist/types/src/index.d.ts.map +1 -1
  92. package/dist/types/src/procedures.d.ts +6 -8
  93. package/dist/types/src/procedures.d.ts.map +1 -1
  94. package/dist/types/src/recyclable_block_flyout_inflater.d.ts +3 -5
  95. package/dist/types/src/recyclable_block_flyout_inflater.d.ts.map +1 -1
  96. package/dist/types/src/renderer/bowler_hat.d.ts +2 -3
  97. package/dist/types/src/renderer/bowler_hat.d.ts.map +1 -1
  98. package/dist/types/src/renderer/cat/cat_face.d.ts +6 -5
  99. package/dist/types/src/renderer/cat/cat_face.d.ts.map +1 -1
  100. package/dist/types/src/renderer/cat/constants.d.ts +2 -2
  101. package/dist/types/src/renderer/cat/constants.d.ts.map +1 -1
  102. package/dist/types/src/renderer/cat/drawer.d.ts +3 -4
  103. package/dist/types/src/renderer/cat/drawer.d.ts.map +1 -1
  104. package/dist/types/src/renderer/cat/path_object.d.ts +2 -3
  105. package/dist/types/src/renderer/cat/path_object.d.ts.map +1 -1
  106. package/dist/types/src/renderer/cat/render_info.d.ts +3 -4
  107. package/dist/types/src/renderer/cat/render_info.d.ts.map +1 -1
  108. package/dist/types/src/renderer/cat/renderer.d.ts +6 -7
  109. package/dist/types/src/renderer/cat/renderer.d.ts.map +1 -1
  110. package/dist/types/src/renderer/constants.d.ts +4 -4
  111. package/dist/types/src/renderer/constants.d.ts.map +1 -1
  112. package/dist/types/src/renderer/drawer.d.ts +5 -4
  113. package/dist/types/src/renderer/drawer.d.ts.map +1 -1
  114. package/dist/types/src/renderer/path_object.d.ts +1 -3
  115. package/dist/types/src/renderer/path_object.d.ts.map +1 -1
  116. package/dist/types/src/renderer/render_info.d.ts +3 -4
  117. package/dist/types/src/renderer/render_info.d.ts.map +1 -1
  118. package/dist/types/src/renderer/renderer.d.ts +8 -15
  119. package/dist/types/src/renderer/renderer.d.ts.map +1 -1
  120. package/dist/types/src/scratch_block_paster.d.ts +0 -5
  121. package/dist/types/src/scratch_block_paster.d.ts.map +1 -1
  122. package/dist/types/src/scratch_blocks_utils.d.ts +0 -20
  123. package/dist/types/src/scratch_blocks_utils.d.ts.map +1 -1
  124. package/dist/types/src/scratch_comment_bubble.d.ts +1 -4
  125. package/dist/types/src/scratch_comment_bubble.d.ts.map +1 -1
  126. package/dist/types/src/scratch_comment_icon.d.ts +2 -3
  127. package/dist/types/src/scratch_comment_icon.d.ts.map +1 -1
  128. package/dist/types/src/scratch_connection_checker.d.ts +0 -5
  129. package/dist/types/src/scratch_connection_checker.d.ts.map +1 -1
  130. package/dist/types/src/scratch_continuous_category.d.ts +5 -5
  131. package/dist/types/src/scratch_continuous_category.d.ts.map +1 -1
  132. package/dist/types/src/scratch_continuous_toolbox.d.ts +3 -6
  133. package/dist/types/src/scratch_continuous_toolbox.d.ts.map +1 -1
  134. package/dist/types/src/scratch_dragger.d.ts +1 -10
  135. package/dist/types/src/scratch_dragger.d.ts.map +1 -1
  136. package/dist/types/src/scratch_insertion_marker_previewer.d.ts +0 -5
  137. package/dist/types/src/scratch_insertion_marker_previewer.d.ts.map +1 -1
  138. package/dist/types/src/scratch_variable_map.d.ts +0 -5
  139. package/dist/types/src/scratch_variable_map.d.ts.map +1 -1
  140. package/dist/types/src/scratch_variable_model.d.ts +1 -2
  141. package/dist/types/src/scratch_variable_model.d.ts.map +1 -1
  142. package/dist/types/src/scratch_zoom_controls.d.ts +4 -6
  143. package/dist/types/src/scratch_zoom_controls.d.ts.map +1 -1
  144. package/dist/types/src/shadows.d.ts +2 -2
  145. package/dist/types/src/shadows.d.ts.map +1 -1
  146. package/dist/types/src/status_indicator_label.d.ts +4 -6
  147. package/dist/types/src/status_indicator_label.d.ts.map +1 -1
  148. package/dist/types/src/status_indicator_label_flyout_inflater.d.ts +1 -6
  149. package/dist/types/src/status_indicator_label_flyout_inflater.d.ts.map +1 -1
  150. package/dist/types/src/variables.d.ts +4 -8
  151. package/dist/types/src/variables.d.ts.map +1 -1
  152. package/dist/types/src/xml.d.ts +2 -3
  153. package/dist/types/src/xml.d.ts.map +1 -1
  154. package/dist/types/tests/jsunit/block_test.d.ts.map +1 -1
  155. package/dist/types/tests/jsunit/connection_db_test.d.ts.map +1 -1
  156. package/dist/types/tests/jsunit/connection_test.d.ts.map +1 -1
  157. package/dist/types/tests/jsunit/event_test.d.ts.map +1 -1
  158. package/dist/types/tests/jsunit/extensions_test.d.ts.map +1 -1
  159. package/dist/types/tests/jsunit/field_number_test.d.ts.map +1 -1
  160. package/dist/types/tests/jsunit/field_test.d.ts.map +1 -1
  161. package/dist/types/tests/jsunit/field_variable_getter_test.d.ts.map +1 -1
  162. package/dist/types/tests/jsunit/field_variable_test.d.ts.map +1 -1
  163. package/dist/types/tests/jsunit/gesture_test.d.ts.map +1 -1
  164. package/dist/types/tests/jsunit/input_test.d.ts +1 -0
  165. package/dist/types/tests/jsunit/input_test.d.ts.map +1 -1
  166. package/dist/types/tests/jsunit/json_test.d.ts.map +1 -1
  167. package/dist/types/tests/jsunit/names_test.d.ts.map +1 -1
  168. package/dist/types/tests/jsunit/procedure_test.d.ts.map +1 -1
  169. package/dist/types/tests/jsunit/scratch_block_comment_test.d.ts.map +1 -1
  170. package/dist/types/tests/jsunit/svg_test.d.ts.map +1 -1
  171. package/dist/types/tests/jsunit/test_utilities.d.ts.map +1 -1
  172. package/dist/types/tests/jsunit/utils_test.d.ts.map +1 -1
  173. package/dist/types/tests/jsunit/variable_map_test.d.ts.map +1 -1
  174. package/dist/types/tests/jsunit/variable_model_test.d.ts.map +1 -1
  175. package/dist/types/tests/jsunit/widget_div_test.d.ts.map +1 -1
  176. package/dist/types/tests/jsunit/workspace_comment_test.d.ts.map +1 -1
  177. package/dist/types/tests/jsunit/workspace_test.d.ts.map +1 -1
  178. package/dist/types/tests/jsunit/workspace_undo_redo_test.d.ts.map +1 -1
  179. package/dist/types/tests/jsunit/xml_test.d.ts.map +1 -1
  180. package/dist/types/tests/workspace_svg/workspace_svg_test.d.ts.map +1 -1
  181. package/eslint.config.mjs +69 -0
  182. package/i18n/create_scratch_msgs.js +44 -45
  183. package/i18n/js_to_json.js +40 -32
  184. package/i18n/json_to_js.js +37 -37
  185. package/i18n/sync_tx_translations.js +64 -65
  186. package/i18n/test_scratch_msgs.js +66 -63
  187. package/msg/js/en.js +289 -287
  188. package/msg/json/en.json +284 -284
  189. package/msg/messages.js +289 -287
  190. package/msg/scratch_msgs.js +22959 -22970
  191. package/package.json +6 -3
  192. package/prettier.config.mjs +3 -0
  193. package/release.config.js +7 -7
  194. package/renovate.json5 +7 -9
  195. package/src/block_reporting.ts +15 -18
  196. package/src/blocks/colour.ts +12 -15
  197. package/src/blocks/control.ts +167 -177
  198. package/src/blocks/data.ts +225 -292
  199. package/src/blocks/event.ts +121 -123
  200. package/src/blocks/looks.ts +165 -167
  201. package/src/blocks/math.ts +44 -46
  202. package/src/blocks/matrix.ts +11 -13
  203. package/src/blocks/motion.ts +151 -153
  204. package/src/blocks/note.ts +11 -13
  205. package/src/blocks/operators.ts +158 -160
  206. package/src/blocks/procedures.ts +415 -523
  207. package/src/blocks/sensing.ts +163 -165
  208. package/src/blocks/sound.ts +58 -60
  209. package/src/blocks/text.ts +10 -12
  210. package/src/blocks/vertical_extensions.ts +86 -102
  211. package/src/checkable_continuous_flyout.ts +25 -42
  212. package/src/checkbox_bubble.ts +83 -100
  213. package/src/colours.ts +35 -37
  214. package/src/constants.ts +22 -29
  215. package/src/context_menu_items.ts +56 -81
  216. package/src/css.ts +3 -4
  217. package/src/data_category.ts +137 -251
  218. package/src/events/events_block_comment_base.ts +21 -31
  219. package/src/events/events_block_comment_change.ts +21 -42
  220. package/src/events/events_block_comment_collapse.ts +22 -43
  221. package/src/events/events_block_comment_create.ts +29 -46
  222. package/src/events/events_block_comment_delete.ts +10 -19
  223. package/src/events/events_block_comment_move.ts +27 -52
  224. package/src/events/events_block_comment_resize.ts +28 -55
  225. package/src/events/events_block_drag_end.ts +16 -26
  226. package/src/events/events_block_drag_outside.ts +12 -22
  227. package/src/events/events_scratch_variable_create.ts +33 -56
  228. package/src/fields/field_colour_slider.ts +173 -228
  229. package/src/fields/field_matrix.ts +200 -269
  230. package/src/fields/field_note.ts +272 -377
  231. package/src/fields/field_textinput_removable.ts +25 -40
  232. package/src/fields/field_variable_getter.ts +26 -31
  233. package/src/fields/field_vertical_separator.ts +19 -24
  234. package/src/fields/scratch_field_angle.ts +150 -186
  235. package/src/fields/scratch_field_dropdown.ts +15 -19
  236. package/src/fields/scratch_field_number.ts +123 -180
  237. package/src/fields/scratch_field_variable.ts +54 -75
  238. package/src/flyout_checkbox_icon.ts +18 -28
  239. package/src/glows.ts +51 -58
  240. package/src/index.ts +119 -133
  241. package/src/procedures.ts +146 -213
  242. package/src/recyclable_block_flyout_inflater.ts +14 -25
  243. package/src/renderer/bowler_hat.ts +6 -8
  244. package/src/renderer/cat/cat_face.ts +98 -99
  245. package/src/renderer/cat/constants.ts +67 -87
  246. package/src/renderer/cat/drawer.ts +21 -27
  247. package/src/renderer/cat/path_object.ts +3 -5
  248. package/src/renderer/cat/render_info.ts +5 -8
  249. package/src/renderer/cat/renderer.ts +11 -15
  250. package/src/renderer/constants.ts +34 -49
  251. package/src/renderer/drawer.ts +35 -51
  252. package/src/renderer/path_object.ts +4 -10
  253. package/src/renderer/render_info.ts +36 -56
  254. package/src/renderer/renderer.ts +16 -29
  255. package/src/scratch_block_paster.ts +12 -20
  256. package/src/scratch_blocks_utils.ts +4 -7
  257. package/src/scratch_comment_bubble.ts +70 -101
  258. package/src/scratch_comment_icon.ts +74 -123
  259. package/src/scratch_connection_checker.ts +7 -17
  260. package/src/scratch_continuous_category.ts +24 -28
  261. package/src/scratch_continuous_toolbox.ts +20 -27
  262. package/src/scratch_dragger.ts +42 -81
  263. package/src/scratch_insertion_marker_previewer.ts +6 -11
  264. package/src/scratch_variable_map.ts +5 -12
  265. package/src/scratch_variable_model.ts +4 -11
  266. package/src/scratch_zoom_controls.ts +101 -156
  267. package/src/shadows.ts +32 -37
  268. package/src/status_indicator_label.ts +54 -67
  269. package/src/status_indicator_label_flyout_inflater.ts +11 -21
  270. package/src/variables.ts +89 -138
  271. package/src/xml.ts +21 -35
  272. package/tsconfig.json +2 -6
  273. package/types/continuous-toolbox.d.ts +1 -1
  274. package/dist/main.mjs.LICENSE.txt +0 -163
@@ -1,5 +1,4 @@
1
1
  /**
2
- * @license
3
2
  * Visual Blocks Editor
4
3
  *
5
4
  * Copyright 2018 Massachusetts Institute of Technology
@@ -17,421 +16,377 @@
17
16
  * See the License for the specific language governing permissions and
18
17
  * limitations under the License.
19
18
  */
20
-
21
19
  /**
22
- * @fileoverview Note input field, for selecting a musical note on a piano.
20
+ * @file Note input field, for selecting a musical note on a piano.
23
21
  * @author ericr@media.mit.edu (Eric Rosenbaum)
24
22
  */
25
- import * as Blockly from "blockly/core";
23
+ import * as Blockly from 'blockly/core'
26
24
 
27
25
  /**
28
26
  * Class for a note input field, for selecting a musical note on a piano.
29
- * @param {(string|number)=} opt_value The initial content of the field. The
27
+ * @param opt_value The initial content of the field. The
30
28
  * value should cast to a number, and if it does not, '0' will be used.
31
- * @param {Function=} opt_validator An optional function that is called
29
+ * @param opt_validator An optional function that is called
32
30
  * to validate any constraints on what the user entered. Takes the new
33
31
  * text as an argument and returns the accepted text or null to abort
34
32
  * the change.
35
- * @extends {Blockly.FieldTextInput}
36
- * @constructor
37
33
  */
38
34
  export class FieldNote extends Blockly.FieldTextInput {
39
35
  /**
40
36
  * Width of the field. Computed when drawing it, and used for animation.
41
37
  */
42
- private fieldEditorWidth_ = 0;
38
+ private fieldEditorWidth_ = 0
43
39
 
44
40
  /**
45
41
  * Height of the field. Computed when drawing it.
46
42
  */
47
- private fieldEditorHeight_ = 0;
43
+ private fieldEditorHeight_ = 0
48
44
 
49
45
  /**
50
46
  * The piano SVG.
51
47
  */
52
- private pianoSVG_: SVGElement | null = null;
48
+ private pianoSVG_: SVGElement | null = null
53
49
 
54
50
  /**
55
51
  * Array of SVG elements representing the clickable piano keys.
56
52
  */
57
- private keySVGs_: SVGElement[] = [];
53
+ private keySVGs_: SVGElement[] = []
58
54
 
59
55
  /**
60
56
  * Note name indicator at the top of the field.
61
57
  */
62
- private noteNameText_: SVGElement | null = null;
58
+ private noteNameText_: SVGElement | null = null
63
59
 
64
60
  /**
65
61
  * Note name indicator on the low C key.
66
62
  */
67
- private lowCText_: SVGElement | null = null;
63
+ private lowCText_: SVGElement | null = null
68
64
 
69
65
  /**
70
66
  * Note name indicator on the low C key.
71
67
  */
72
- private highCText_: SVGElement | null = null;
68
+ private highCText_: SVGElement | null = null
73
69
 
74
70
  /**
75
71
  * Octave number of the currently displayed range of keys.
76
72
  */
77
- private displayedOctave_: number | null = null;
73
+ private displayedOctave_: number | null = null
78
74
 
79
75
  /**
80
76
  * Current animation position of the piano SVG, as it shifts left or right to
81
77
  * change octaves.
82
78
  */
83
- private animationPos_ = 0;
79
+ private animationPos_ = 0
84
80
 
85
81
  /**
86
82
  * Target position for the animation as the piano SVG shifts left or right.
87
83
  */
88
- private animationTarget_ = 0;
84
+ private animationTarget_ = 0
89
85
 
90
86
  /**
91
87
  * A flag indicating that the mouse is currently down. Used in combination with
92
88
  * mouse enter events to update the key selection while dragging.
93
89
  */
94
- private mouseIsDown_ = false;
90
+ private mouseIsDown_ = false
95
91
 
96
92
  /**
97
93
  * An array of wrappers for mouse down events on piano keys.
98
94
  */
99
- private mouseDownWrappers_: Blockly.browserEvents.Data[] = [];
95
+ private mouseDownWrappers_: Blockly.browserEvents.Data[] = []
100
96
 
101
97
  /**
102
98
  * A wrapper for the mouse up event.
103
99
  */
104
- private mouseUpWrapper_: Blockly.browserEvents.Data | null = null;
100
+ private mouseUpWrapper_: Blockly.browserEvents.Data | null = null
105
101
 
106
102
  /**
107
103
  * An array of wrappers for mouse enter events on piano keys.
108
104
  */
109
- private mouseEnterWrappers_: Blockly.browserEvents.Data[] = [];
105
+ private mouseEnterWrappers_: Blockly.browserEvents.Data[] = []
110
106
 
111
107
  /**
112
108
  * A wrapper for the mouse down event on the octave down button.
113
109
  */
114
- private octaveDownMouseDownWrapper_: Blockly.browserEvents.Data | null = null;
110
+ private octaveDownMouseDownWrapper_: Blockly.browserEvents.Data | null = null
115
111
 
116
112
  /**
117
113
  * A wrapper for the mouse down event on the octave up button.
118
114
  */
119
- private octaveUpMouseDownWrapper_: Blockly.browserEvents.Data | null = null;
115
+ private octaveUpMouseDownWrapper_: Blockly.browserEvents.Data | null = null
120
116
 
121
117
  /**
122
118
  * Inset in pixels of content displayed in the field, caused by parent properties.
123
119
  * The inset is actually determined by the CSS property blocklyDropDownDiv- it is
124
120
  * the sum of the padding and border thickness.
125
121
  */
126
- static INSET = 5;
122
+ static INSET = 5
127
123
 
128
124
  /**
129
125
  * Height of the top area of the field, in px.
130
126
  */
131
- static readonly TOP_MENU_HEIGHT = 32 - FieldNote.INSET;
127
+ static readonly TOP_MENU_HEIGHT = 32 - FieldNote.INSET
132
128
 
133
129
  /**
134
130
  * Padding on the top and sides of the field, in px.
135
131
  */
136
- static readonly EDGE_PADDING = 1;
132
+ static readonly EDGE_PADDING = 1
137
133
 
138
134
  /**
139
135
  * Height of the drop shadow on the piano, in px.
140
136
  */
141
- static readonly SHADOW_HEIGHT = 4;
137
+ static readonly SHADOW_HEIGHT = 4
142
138
 
143
139
  /**
144
140
  * Color for the shadow on the piano.
145
141
  */
146
- static readonly SHADOW_COLOR = "#000";
142
+ static readonly SHADOW_COLOR = '#000'
147
143
 
148
144
  /**
149
145
  * Opacity for the shadow on the piano.
150
146
  */
151
- static readonly SHADOW_OPACITY = 0.2;
147
+ static readonly SHADOW_OPACITY = 0.2
152
148
 
153
149
  /**
154
150
  * A color for the white piano keys.
155
151
  */
156
- static readonly WHITE_KEY_COLOR = "#FFFFFF";
152
+ static readonly WHITE_KEY_COLOR = '#FFFFFF'
157
153
 
158
154
  /**
159
155
  * A color for the black piano keys.
160
156
  */
161
- static readonly BLACK_KEY_COLOR = "#323133";
157
+ static readonly BLACK_KEY_COLOR = '#323133'
162
158
 
163
159
  /**
164
160
  * A color for stroke around black piano keys.
165
161
  */
166
- static readonly BLACK_KEY_STROKE = "#555555";
162
+ static readonly BLACK_KEY_STROKE = '#555555'
167
163
 
168
164
  /**
169
165
  * A color for the selected state of a piano key.
170
166
  */
171
- static readonly KEY_SELECTED_COLOR = "#b0d6ff";
167
+ static readonly KEY_SELECTED_COLOR = '#b0d6ff'
172
168
 
173
169
  /**
174
170
  * The number of white keys in one octave on the piano.
175
171
  */
176
- static readonly NUM_WHITE_KEYS = 8;
172
+ static readonly NUM_WHITE_KEYS = 8
177
173
 
178
174
  /**
179
175
  * Height of a white piano key, in px.
180
176
  */
181
- static readonly WHITE_KEY_HEIGHT = 72;
177
+ static readonly WHITE_KEY_HEIGHT = 72
182
178
 
183
179
  /**
184
180
  * Width of a white piano key, in px.
185
181
  */
186
- static readonly WHITE_KEY_WIDTH = 40;
182
+ static readonly WHITE_KEY_WIDTH = 40
187
183
 
188
184
  /**
189
185
  * Height of a black piano key, in px.
190
186
  */
191
- static readonly BLACK_KEY_HEIGHT = 40;
187
+ static readonly BLACK_KEY_HEIGHT = 40
192
188
 
193
189
  /**
194
190
  * Width of a black piano key, in px.
195
191
  */
196
- static readonly BLACK_KEY_WIDTH = 32;
192
+ static readonly BLACK_KEY_WIDTH = 32
197
193
 
198
194
  /**
199
195
  * Radius of the curved bottom corner of a piano key, in px.
200
196
  */
201
- static readonly KEY_RADIUS = 6;
197
+ static readonly KEY_RADIUS = 6
202
198
 
203
199
  /**
204
200
  * Bottom padding for the labels on C keys.
205
201
  */
206
- static readonly KEY_LABEL_PADDING = 8;
202
+ static readonly KEY_LABEL_PADDING = 8
207
203
 
208
204
  /**
209
205
  * An array of objects with data describing the keys on the piano.
210
206
  */
211
207
  static readonly KEY_INFO = [
212
- { name: "C", pitch: 0 },
213
- { name: "C♯", pitch: 1, isBlack: true },
214
- { name: "D", pitch: 2 },
215
- { name: "E♭", pitch: 3, isBlack: true },
216
- { name: "E", pitch: 4 },
217
- { name: "F", pitch: 5 },
218
- { name: "F♯", pitch: 6, isBlack: true },
219
- { name: "G", pitch: 7 },
220
- { name: "G♯", pitch: 8, isBlack: true },
221
- { name: "A", pitch: 9 },
222
- { name: "B♭", pitch: 10, isBlack: true },
223
- { name: "B", pitch: 11 },
224
- { name: "C", pitch: 12 },
225
- ];
208
+ { name: 'C', pitch: 0 },
209
+ { name: 'C♯', pitch: 1, isBlack: true },
210
+ { name: 'D', pitch: 2 },
211
+ { name: 'E♭', pitch: 3, isBlack: true },
212
+ { name: 'E', pitch: 4 },
213
+ { name: 'F', pitch: 5 },
214
+ { name: 'F♯', pitch: 6, isBlack: true },
215
+ { name: 'G', pitch: 7 },
216
+ { name: 'G♯', pitch: 8, isBlack: true },
217
+ { name: 'A', pitch: 9 },
218
+ { name: 'B♭', pitch: 10, isBlack: true },
219
+ { name: 'B', pitch: 11 },
220
+ { name: 'C', pitch: 12 },
221
+ ]
226
222
 
227
223
  /**
228
224
  * The MIDI note number of the highest note selectable on the piano.
229
225
  */
230
- static readonly MAX_NOTE = 130;
226
+ static readonly MAX_NOTE = 130
231
227
 
232
228
  /**
233
229
  * The fraction of the distance to the target location to move the piano at each
234
230
  * step of the animation.
235
231
  */
236
- static readonly ANIMATION_FRACTION = 0.2;
232
+ static readonly ANIMATION_FRACTION = 0.2
237
233
 
238
234
  /**
239
235
  * Path to the arrow svg icon, used on the octave buttons.
240
236
  */
241
- static readonly ARROW_SVG_PATH = "icons/arrow_button.svg";
237
+ static readonly ARROW_SVG_PATH = 'icons/arrow_button.svg'
242
238
 
243
239
  /**
244
240
  * The size of the square octave buttons.
245
241
  */
246
- static readonly OCTAVE_BUTTON_SIZE = 32;
242
+ static readonly OCTAVE_BUTTON_SIZE = 32
247
243
 
248
244
  /**
249
245
  * Construct a FieldNote from a JSON arg object.
250
- *
251
246
  * @param options A JSON object with options.
252
247
  * @returns The new field instance.
253
248
  */
254
249
  static fromJson(options: FieldNoteJsonConfig): FieldNote {
255
- return new FieldNote(options["note"]);
250
+ return new FieldNote(options.note)
256
251
  }
257
252
 
258
253
  /**
259
254
  * Clean up this FieldNote, as well as the inherited FieldTextInput.
260
255
  */
261
256
  dispose() {
262
- super.dispose();
263
- this.mouseDownWrappers_.forEach(function (wrapper) {
264
- Blockly.browserEvents.unbind(wrapper);
265
- });
266
- this.mouseEnterWrappers_.forEach(function (wrapper) {
267
- Blockly.browserEvents.unbind(wrapper);
268
- });
257
+ super.dispose()
258
+ this.mouseDownWrappers_.forEach(wrapper => {
259
+ Blockly.browserEvents.unbind(wrapper)
260
+ })
261
+ this.mouseEnterWrappers_.forEach(wrapper => {
262
+ Blockly.browserEvents.unbind(wrapper)
263
+ })
269
264
  if (this.mouseUpWrapper_) {
270
- Blockly.browserEvents.unbind(this.mouseUpWrapper_);
265
+ Blockly.browserEvents.unbind(this.mouseUpWrapper_)
271
266
  }
272
267
  if (this.octaveDownMouseDownWrapper_) {
273
- Blockly.browserEvents.unbind(this.octaveDownMouseDownWrapper_);
268
+ Blockly.browserEvents.unbind(this.octaveDownMouseDownWrapper_)
274
269
  }
275
270
  if (this.octaveUpMouseDownWrapper_) {
276
- Blockly.browserEvents.unbind(this.octaveUpMouseDownWrapper_);
271
+ Blockly.browserEvents.unbind(this.octaveUpMouseDownWrapper_)
277
272
  }
278
- this.pianoSVG_ = null;
279
- this.keySVGs_.length = 0;
280
- this.noteNameText_ = null;
281
- this.lowCText_ = null;
282
- this.highCText_ = null;
273
+ this.pianoSVG_ = null
274
+ this.keySVGs_.length = 0
275
+ this.noteNameText_ = null
276
+ this.lowCText_ = null
277
+ this.highCText_ = null
283
278
  }
284
279
 
285
280
  /**
286
281
  * Show a field with piano keys.
282
+ * @param event The triggering pointer event.
283
+ * @param quietInput If true, suppress the sound preview while the editor opens.
287
284
  */
288
285
  showEditor_(event: PointerEvent, quietInput = false) {
289
- super.showEditor_(event, quietInput, false);
286
+ super.showEditor_(event, quietInput, false)
290
287
 
291
288
  // Build the SVG DOM.
292
- const div = Blockly.DropDownDiv.getContentDiv();
289
+ const div = Blockly.DropDownDiv.getContentDiv()
293
290
 
294
- this.fieldEditorWidth_ =
295
- FieldNote.NUM_WHITE_KEYS * FieldNote.WHITE_KEY_WIDTH +
296
- FieldNote.EDGE_PADDING;
297
- this.fieldEditorHeight_ =
298
- FieldNote.TOP_MENU_HEIGHT +
299
- FieldNote.WHITE_KEY_HEIGHT +
300
- FieldNote.EDGE_PADDING;
291
+ this.fieldEditorWidth_ = FieldNote.NUM_WHITE_KEYS * FieldNote.WHITE_KEY_WIDTH + FieldNote.EDGE_PADDING
292
+ this.fieldEditorHeight_ = FieldNote.TOP_MENU_HEIGHT + FieldNote.WHITE_KEY_HEIGHT + FieldNote.EDGE_PADDING
301
293
 
302
294
  const svg = Blockly.utils.dom.createSvgElement(
303
- "svg",
295
+ 'svg',
304
296
  {
305
- xmlns: "http://www.w3.org/2000/svg",
306
- "xmlns:html": "http://www.w3.org/1999/xhtml",
307
- "xmlns:xlink": "http://www.w3.org/1999/xlink",
308
- version: "1.1",
309
- height: this.fieldEditorHeight_ + "px",
310
- width: this.fieldEditorWidth_ + "px",
297
+ xmlns: 'http://www.w3.org/2000/svg',
298
+ 'xmlns:html': 'http://www.w3.org/1999/xhtml',
299
+ 'xmlns:xlink': 'http://www.w3.org/1999/xlink',
300
+ version: '1.1',
301
+ height: this.fieldEditorHeight_ + 'px',
302
+ width: this.fieldEditorWidth_ + 'px',
311
303
  },
312
- div
313
- );
304
+ div,
305
+ )
314
306
 
315
307
  // Add the white and black keys
316
308
  // Since we are adding the keys from left to right in order, they need
317
309
  // to be in two groups in order to layer correctly.
318
- this.pianoSVG_ = Blockly.utils.dom.createSvgElement("g", {}, svg);
319
- const whiteKeyGroup = Blockly.utils.dom.createSvgElement(
320
- "g",
321
- {},
322
- this.pianoSVG_
323
- );
324
- const blackKeyGroup = Blockly.utils.dom.createSvgElement(
325
- "g",
326
- {},
327
- this.pianoSVG_
328
- );
310
+ this.pianoSVG_ = Blockly.utils.dom.createSvgElement('g', {}, svg)
311
+ const whiteKeyGroup = Blockly.utils.dom.createSvgElement('g', {}, this.pianoSVG_)
312
+ const blackKeyGroup = Blockly.utils.dom.createSvgElement('g', {}, this.pianoSVG_)
329
313
 
330
314
  // Add three piano octaves, so we can animate moving up or down an octave.
331
315
  // Only the middle octave gets bound to events.
332
- this.keySVGs_ = [];
333
- this.addPianoOctave_(
334
- -this.fieldEditorWidth_ + FieldNote.EDGE_PADDING,
335
- whiteKeyGroup,
336
- blackKeyGroup,
337
- null
338
- );
339
- this.addPianoOctave_(0, whiteKeyGroup, blackKeyGroup, this.keySVGs_);
340
- this.addPianoOctave_(
341
- this.fieldEditorWidth_ - FieldNote.EDGE_PADDING,
342
- whiteKeyGroup,
343
- blackKeyGroup,
344
- null
345
- );
316
+ this.keySVGs_ = []
317
+ this.addPianoOctave_(-this.fieldEditorWidth_ + FieldNote.EDGE_PADDING, whiteKeyGroup, blackKeyGroup, null)
318
+ this.addPianoOctave_(0, whiteKeyGroup, blackKeyGroup, this.keySVGs_)
319
+ this.addPianoOctave_(this.fieldEditorWidth_ - FieldNote.EDGE_PADDING, whiteKeyGroup, blackKeyGroup, null)
346
320
 
347
321
  // Note name indicator at the top of the field
348
322
  this.noteNameText_ = Blockly.utils.dom.createSvgElement(
349
- "text",
323
+ 'text',
350
324
  {
351
325
  x: this.fieldEditorWidth_ / 2,
352
326
  y: FieldNote.TOP_MENU_HEIGHT / 2,
353
- class: "blocklyText",
354
- "text-anchor": "middle",
355
- "dominant-baseline": "middle",
327
+ class: 'blocklyText',
328
+ 'text-anchor': 'middle',
329
+ 'dominant-baseline': 'middle',
356
330
  },
357
- svg
358
- );
331
+ svg,
332
+ )
359
333
 
360
334
  // Note names on the low and high C keys
361
- const lowCX = FieldNote.WHITE_KEY_WIDTH / 2;
362
- this.lowCText_ = this.addCKeyLabel_(lowCX, svg);
363
- const highCX =
364
- lowCX + FieldNote.WHITE_KEY_WIDTH * (FieldNote.NUM_WHITE_KEYS - 1);
365
- this.highCText_ = this.addCKeyLabel_(highCX, svg);
335
+ const lowCX = FieldNote.WHITE_KEY_WIDTH / 2
336
+ this.lowCText_ = this.addCKeyLabel_(lowCX, svg)
337
+ const highCX = lowCX + FieldNote.WHITE_KEY_WIDTH * (FieldNote.NUM_WHITE_KEYS - 1)
338
+ this.highCText_ = this.addCKeyLabel_(highCX, svg)
366
339
 
367
340
  // Horizontal line at the top of the keys
368
341
  Blockly.utils.dom.createSvgElement(
369
- "line",
342
+ 'line',
370
343
  {
371
- stroke: (
372
- this.sourceBlock_!.getParent() as Blockly.BlockSvg
373
- ).getColourTertiary(),
344
+ stroke: (this.sourceBlock_!.getParent() as Blockly.BlockSvg).getColourTertiary(),
374
345
  x1: 0,
375
346
  y1: FieldNote.TOP_MENU_HEIGHT,
376
347
  x2: this.fieldEditorWidth_,
377
348
  y2: FieldNote.TOP_MENU_HEIGHT,
378
349
  },
379
- svg
380
- );
350
+ svg,
351
+ )
381
352
 
382
353
  // Drop shadow at the top of the keys
383
354
  Blockly.utils.dom.createSvgElement(
384
- "rect",
355
+ 'rect',
385
356
  {
386
357
  x: 0,
387
358
  y: FieldNote.TOP_MENU_HEIGHT,
388
359
  width: this.fieldEditorWidth_,
389
360
  height: FieldNote.SHADOW_HEIGHT,
390
361
  fill: FieldNote.SHADOW_COLOR,
391
- "fill-opacity": FieldNote.SHADOW_OPACITY,
362
+ 'fill-opacity': FieldNote.SHADOW_OPACITY,
392
363
  },
393
- svg
394
- );
364
+ svg,
365
+ )
395
366
 
396
367
  // Octave buttons
397
- const octaveDownButton = this.addOctaveButton_(0, true, svg);
368
+ const octaveDownButton = this.addOctaveButton_(0, true, svg)
398
369
  const octaveUpButton = this.addOctaveButton_(
399
- this.fieldEditorWidth_ +
400
- FieldNote.INSET * 2 -
401
- FieldNote.OCTAVE_BUTTON_SIZE,
370
+ this.fieldEditorWidth_ + FieldNote.INSET * 2 - FieldNote.OCTAVE_BUTTON_SIZE,
402
371
  false,
403
- svg
404
- );
405
-
406
- this.octaveDownMouseDownWrapper_ = Blockly.browserEvents.bind(
407
- octaveDownButton,
408
- "mousedown",
409
- this,
410
- () => {
411
- this.changeOctaveBy_(-1);
412
- }
413
- );
414
- this.octaveUpMouseDownWrapper_ = Blockly.browserEvents.bind(
415
- octaveUpButton,
416
- "mousedown",
417
- this,
418
- () => {
419
- this.changeOctaveBy_(1);
420
- }
421
- );
422
- const sourceBlock = this.getSourceBlock() as Blockly.BlockSvg;
423
- Blockly.DropDownDiv.setColour(
424
- (sourceBlock.getParent() as Blockly.BlockSvg).getColour(),
425
- (sourceBlock.getParent() as Blockly.BlockSvg).getColourTertiary()
426
- );
427
- Blockly.DropDownDiv.showPositionedByBlock(this, sourceBlock);
428
-
429
- this.updateSelection_();
372
+ svg,
373
+ )
374
+
375
+ this.octaveDownMouseDownWrapper_ = Blockly.browserEvents.bind(octaveDownButton, 'mousedown', this, () => {
376
+ this.changeOctaveBy_(-1)
377
+ })
378
+ this.octaveUpMouseDownWrapper_ = Blockly.browserEvents.bind(octaveUpButton, 'mousedown', this, () => {
379
+ this.changeOctaveBy_(1)
380
+ })
381
+ const sourceBlock = this.getSourceBlock() as Blockly.BlockSvg
382
+ Blockly.DropDownDiv.setColour(sourceBlock.getParent()!.getColour(), sourceBlock.getParent()!.getColourTertiary())
383
+ Blockly.DropDownDiv.showPositionedByBlock(this, sourceBlock)
384
+
385
+ this.updateSelection_()
430
386
  }
431
387
 
432
388
  /**
433
389
  * Add one octave of piano keys drawn using SVG.
434
- *
435
390
  * @param x The x position of the left edge of this octave of keys.
436
391
  * @param whiteKeyGroup The group for all white piano keys.
437
392
  * @param blackKeyGroup The group for all black piano keys.
@@ -441,59 +396,47 @@ export class FieldNote extends Blockly.FieldTextInput {
441
396
  x: number,
442
397
  whiteKeyGroup: SVGElement,
443
398
  blackKeyGroup: SVGElement,
444
- keySVGarray: SVGElement[] | null
399
+ keySVGarray: SVGElement[] | null,
445
400
  ) {
446
- let xIncrement, width, height, fill, stroke, group;
447
- x += FieldNote.EDGE_PADDING / 2;
448
- const y = FieldNote.TOP_MENU_HEIGHT;
449
- for (var i = 0; i < FieldNote.KEY_INFO.length; i++) {
401
+ let xIncrement, width, height, fill, stroke, group
402
+ x += FieldNote.EDGE_PADDING / 2
403
+ const y = FieldNote.TOP_MENU_HEIGHT
404
+ for (let i = 0; i < FieldNote.KEY_INFO.length; i++) {
450
405
  // Draw a black or white key
451
406
  if (FieldNote.KEY_INFO[i].isBlack) {
452
407
  // Black keys are shifted back half a key
453
- x -= FieldNote.BLACK_KEY_WIDTH / 2;
454
- xIncrement = FieldNote.BLACK_KEY_WIDTH / 2;
455
- width = FieldNote.BLACK_KEY_WIDTH;
456
- height = FieldNote.BLACK_KEY_HEIGHT;
457
- fill = FieldNote.BLACK_KEY_COLOR;
458
- stroke = FieldNote.BLACK_KEY_STROKE;
459
- group = blackKeyGroup;
408
+ x -= FieldNote.BLACK_KEY_WIDTH / 2
409
+ xIncrement = FieldNote.BLACK_KEY_WIDTH / 2
410
+ width = FieldNote.BLACK_KEY_WIDTH
411
+ height = FieldNote.BLACK_KEY_HEIGHT
412
+ fill = FieldNote.BLACK_KEY_COLOR
413
+ stroke = FieldNote.BLACK_KEY_STROKE
414
+ group = blackKeyGroup
460
415
  } else {
461
- xIncrement = FieldNote.WHITE_KEY_WIDTH;
462
- width = FieldNote.WHITE_KEY_WIDTH;
463
- height = FieldNote.WHITE_KEY_HEIGHT;
464
- fill = FieldNote.WHITE_KEY_COLOR;
465
- stroke = (
466
- this.sourceBlock_!.getParent() as Blockly.BlockSvg
467
- ).getColourTertiary();
468
- group = whiteKeyGroup;
416
+ xIncrement = FieldNote.WHITE_KEY_WIDTH
417
+ width = FieldNote.WHITE_KEY_WIDTH
418
+ height = FieldNote.WHITE_KEY_HEIGHT
419
+ fill = FieldNote.WHITE_KEY_COLOR
420
+ stroke = (this.sourceBlock_!.getParent() as Blockly.BlockSvg).getColourTertiary()
421
+ group = whiteKeyGroup
469
422
  }
470
423
  const attr = {
471
424
  d: this.getPianoKeyPath_(x, y, width, height),
472
425
  fill: fill,
473
426
  stroke: stroke,
474
- };
475
- x += xIncrement;
427
+ }
428
+ x += xIncrement
476
429
 
477
- const keySVG = Blockly.utils.dom.createSvgElement("path", attr, group);
430
+ const keySVG = Blockly.utils.dom.createSvgElement('path', attr, group)
478
431
 
479
432
  if (keySVGarray) {
480
- keySVGarray[i] = keySVG;
481
- keySVG.setAttribute("data-pitch", `${FieldNote.KEY_INFO[i].pitch}`);
482
- keySVG.setAttribute("data-name", `${FieldNote.KEY_INFO[i].name}`);
483
- keySVG.setAttribute("data-isBlack", `${FieldNote.KEY_INFO[i].isBlack}`);
484
-
485
- this.mouseDownWrappers_[i] = Blockly.browserEvents.bind(
486
- keySVG,
487
- "mousedown",
488
- this,
489
- this.onMouseDownOnKey_
490
- );
491
- this.mouseEnterWrappers_[i] = Blockly.browserEvents.bind(
492
- keySVG,
493
- "mouseenter",
494
- this,
495
- this.onMouseEnter_
496
- );
433
+ keySVGarray[i] = keySVG
434
+ keySVG.setAttribute('data-pitch', `${FieldNote.KEY_INFO[i].pitch}`)
435
+ keySVG.setAttribute('data-name', `${FieldNote.KEY_INFO[i].name}`)
436
+ keySVG.setAttribute('data-isBlack', `${FieldNote.KEY_INFO[i].isBlack}`)
437
+
438
+ this.mouseDownWrappers_[i] = Blockly.browserEvents.bind(keySVG, 'mousedown', this, this.onMouseDownOnKey_)
439
+ this.mouseEnterWrappers_[i] = Blockly.browserEvents.bind(keySVG, 'mouseenter', this, this.onMouseEnter_)
497
440
  }
498
441
  }
499
442
  }
@@ -501,221 +444,184 @@ export class FieldNote extends Blockly.FieldTextInput {
501
444
  /**
502
445
  * Construct the SVG path string for a piano key shape: a rectangle with rounded
503
446
  * corners at the bottom.
504
- *
505
447
  * @param x the x position for the key.
506
448
  * @param y the y position for the key.
507
- * @param width the width of the key.
508
- * @param height the height of the key.
449
+ * @param width the horizontal extent of the key in pixels.
450
+ * @param height the vertical extent of the key in pixels.
509
451
  * @returns the SVG path as a string.
510
452
  */
511
- private getPianoKeyPath_(
512
- x: number,
513
- y: number,
514
- width: number,
515
- height: number
516
- ): string {
453
+ private getPianoKeyPath_(x: number, y: number, width: number, height: number): string {
517
454
  return (
518
- "M" +
455
+ 'M' +
519
456
  x +
520
- " " +
457
+ ' ' +
521
458
  y +
522
- " " +
523
- "L" +
459
+ ' ' +
460
+ 'L' +
524
461
  x +
525
- " " +
462
+ ' ' +
526
463
  (y + height - FieldNote.KEY_RADIUS) +
527
- " " +
528
- "Q" +
464
+ ' ' +
465
+ 'Q' +
529
466
  x +
530
- " " +
467
+ ' ' +
531
468
  (y + height) +
532
- " " +
469
+ ' ' +
533
470
  (x + FieldNote.KEY_RADIUS) +
534
- " " +
471
+ ' ' +
535
472
  (y + height) +
536
- " " +
537
- "L" +
473
+ ' ' +
474
+ 'L' +
538
475
  (x + width - FieldNote.KEY_RADIUS) +
539
- " " +
476
+ ' ' +
540
477
  (y + height) +
541
- " " +
542
- "Q" +
478
+ ' ' +
479
+ 'Q' +
543
480
  (x + width) +
544
- " " +
481
+ ' ' +
545
482
  (y + height) +
546
- " " +
483
+ ' ' +
547
484
  (x + width) +
548
- " " +
485
+ ' ' +
549
486
  (y + height - FieldNote.KEY_RADIUS) +
550
- " " +
551
- "L" +
487
+ ' ' +
488
+ 'L' +
552
489
  (x + width) +
553
- " " +
490
+ ' ' +
554
491
  y +
555
- " " +
556
- "L" +
492
+ ' ' +
493
+ 'L' +
557
494
  x +
558
- " " +
495
+ ' ' +
559
496
  y
560
- );
497
+ )
561
498
  }
562
499
 
563
500
  /**
564
501
  * Add a button for switching the displayed octave of the piano up or down.
565
- *
566
502
  * @param x The x position of the button.
567
503
  * @param flipped If true, the icon should be flipped.
568
504
  * @param svg The svg element to add the buttons to.
569
505
  * @returns A group containing the button SVG elements.
570
506
  */
571
- private addOctaveButton_(
572
- x: number,
573
- flipped: boolean,
574
- svg: SVGElement
575
- ): SVGElement {
576
- const group = Blockly.utils.dom.createSvgElement("g", {}, svg);
577
- const imageSize = FieldNote.OCTAVE_BUTTON_SIZE;
507
+ private addOctaveButton_(x: number, flipped: boolean, svg: SVGElement): SVGElement {
508
+ const group = Blockly.utils.dom.createSvgElement('g', {}, svg)
509
+ const imageSize = FieldNote.OCTAVE_BUTTON_SIZE
578
510
  const arrow = Blockly.utils.dom.createSvgElement(
579
- "image",
511
+ 'image',
580
512
  {
581
513
  width: imageSize,
582
514
  height: imageSize,
583
515
  x: x - FieldNote.INSET,
584
516
  y: -1 * FieldNote.INSET,
585
517
  },
586
- group
587
- );
518
+ group,
519
+ )
588
520
  arrow.setAttributeNS(
589
- "http://www.w3.org/1999/xlink",
590
- "xlink:href",
591
- Blockly.getMainWorkspace().options.pathToMedia + FieldNote.ARROW_SVG_PATH
592
- );
521
+ 'http://www.w3.org/1999/xlink',
522
+ 'xlink:href',
523
+ Blockly.getMainWorkspace().options.pathToMedia + FieldNote.ARROW_SVG_PATH,
524
+ )
593
525
  Blockly.utils.dom.createSvgElement(
594
- "line",
526
+ 'line',
595
527
  {
596
- stroke: (
597
- this.sourceBlock_!.getParent() as Blockly.BlockSvg
598
- ).getColourTertiary(),
528
+ stroke: (this.sourceBlock_!.getParent() as Blockly.BlockSvg).getColourTertiary(),
599
529
  x1: x - FieldNote.INSET,
600
530
  y1: 0,
601
531
  x2: x - FieldNote.INSET,
602
532
  y2: FieldNote.TOP_MENU_HEIGHT - FieldNote.INSET,
603
533
  },
604
- group
605
- );
534
+ group,
535
+ )
606
536
  if (flipped) {
607
- const translateX =
608
- -1 * FieldNote.OCTAVE_BUTTON_SIZE + FieldNote.INSET * 2;
609
- group.setAttribute(
610
- "transform",
611
- "scale(-1, 1) " + "translate(" + translateX + ", 0)"
612
- );
537
+ const translateX = -1 * FieldNote.OCTAVE_BUTTON_SIZE + FieldNote.INSET * 2
538
+ group.setAttribute('transform', 'scale(-1, 1) ' + 'translate(' + translateX + ', 0)')
613
539
  }
614
- return group;
540
+ return group
615
541
  }
616
542
 
617
543
  /**
618
544
  * Add an SVG text label for display on the C keys of the piano.
619
- *
620
545
  * @param x The x position for the label.
621
546
  * @param svg The SVG element to add the label to.
622
547
  * @returns The SVG element containing the label.
623
548
  */
624
549
  private addCKeyLabel_(x: number, svg: SVGElement): SVGElement {
625
550
  return Blockly.utils.dom.createSvgElement(
626
- "text",
551
+ 'text',
627
552
  {
628
553
  x: x,
629
- y:
630
- FieldNote.TOP_MENU_HEIGHT +
631
- FieldNote.WHITE_KEY_HEIGHT -
632
- FieldNote.KEY_LABEL_PADDING,
633
- class: "scratchNotePickerKeyLabel",
634
- "text-anchor": "middle",
554
+ y: FieldNote.TOP_MENU_HEIGHT + FieldNote.WHITE_KEY_HEIGHT - FieldNote.KEY_LABEL_PADDING,
555
+ class: 'scratchNotePickerKeyLabel',
556
+ 'text-anchor': 'middle',
635
557
  },
636
- svg
637
- );
558
+ svg,
559
+ )
638
560
  }
639
561
 
640
562
  /**
641
563
  * Set the visibility of the C key labels.
642
- *
643
564
  * @param visible If true, set labels to be visible.
644
565
  */
645
566
  private setCKeyLabelsVisible_(visible: boolean) {
646
567
  if (!this.lowCText_ || !this.highCText_) {
647
- console.warn(
648
- "FieldNote.setCKeyLabelsVisible_: C-key label DOM is not fully initialized"
649
- );
650
- return;
568
+ console.warn('FieldNote.setCKeyLabelsVisible_: C-key label DOM is not fully initialized')
569
+ return
651
570
  }
652
- const opacity = visible ? 1 : 0;
653
- this.fadeSvgToOpacity_(this.lowCText_, opacity);
654
- this.fadeSvgToOpacity_(this.highCText_, opacity);
571
+ const opacity = visible ? 1 : 0
572
+ this.fadeSvgToOpacity_(this.lowCText_, opacity)
573
+ this.fadeSvgToOpacity_(this.highCText_, opacity)
655
574
  }
656
575
 
657
576
  /**
658
577
  * Animate an SVG to fade it in or out to a target opacity.
659
- *
660
578
  * @param svg The SVG element to apply the fade to.
661
579
  * @param opacity The target opacity.
662
580
  */
663
581
  private fadeSvgToOpacity_(svg: SVGElement, opacity: number) {
664
- svg.setAttribute(
665
- "style",
666
- "opacity: " + opacity + "; transition: opacity 0.1s;"
667
- );
582
+ svg.setAttribute('style', 'opacity: ' + opacity + '; transition: opacity 0.1s;')
668
583
  }
669
584
 
670
585
  /**
671
586
  * Handle the mouse down event on a piano key.
672
- *
673
587
  * @param e Mouse down event.
674
588
  */
675
589
  private onMouseDownOnKey_(e: PointerEvent) {
676
- this.mouseIsDown_ = true;
677
- this.mouseUpWrapper_ = Blockly.browserEvents.bind(
678
- document.body,
679
- "mouseup",
680
- this,
681
- this.onMouseUp_
682
- );
683
- this.selectNoteWithMouseEvent_(e);
590
+ this.mouseIsDown_ = true
591
+ this.mouseUpWrapper_ = Blockly.browserEvents.bind(document.body, 'mouseup', this, this.onMouseUp_)
592
+ this.selectNoteWithMouseEvent_(e)
684
593
  }
685
594
 
686
595
  /**
687
596
  * Handle the mouse up event following a mouse down on a piano key.
688
597
  */
689
598
  private onMouseUp_() {
690
- this.mouseIsDown_ = false;
599
+ this.mouseIsDown_ = false
691
600
  if (this.mouseUpWrapper_) {
692
- Blockly.browserEvents.unbind(this.mouseUpWrapper_);
693
- this.mouseUpWrapper_ = null;
601
+ Blockly.browserEvents.unbind(this.mouseUpWrapper_)
602
+ this.mouseUpWrapper_ = null
694
603
  }
695
604
  }
696
605
 
697
606
  /**
698
607
  * Handle the event when the mouse enters a piano key.
699
- *
700
608
  * @param e Mouse enter event.
701
609
  */
702
610
  private onMouseEnter_(e: PointerEvent) {
703
611
  if (this.mouseIsDown_) {
704
- this.selectNoteWithMouseEvent_(e);
612
+ this.selectNoteWithMouseEvent_(e)
705
613
  }
706
614
  }
707
615
 
708
616
  /**
709
617
  * Use the data in a mouse event to select a new note, and play it.
710
- *
711
618
  * @param e Mouse event.
712
619
  */
713
620
  private selectNoteWithMouseEvent_(e: PointerEvent) {
714
621
  const newNoteNum =
715
- Number((e.target as HTMLElement).getAttribute("data-pitch")) +
716
- (this.displayedOctave_ ?? 0) * 12;
717
- this.setEditorValue_(newNoteNum);
718
- this.playNoteInternal_();
622
+ Number((e.target as HTMLElement).getAttribute('data-pitch')) + (this.displayedOctave_ ?? 0) * 12
623
+ this.setEditorValue_(newNoteNum)
624
+ this.playNoteInternal_()
719
625
  }
720
626
 
721
627
  /**
@@ -723,94 +629,86 @@ export class FieldNote extends Blockly.FieldTextInput {
723
629
  */
724
630
  private playNoteInternal_() {
725
631
  if (FieldNote.playNote_) {
726
- FieldNote.playNote_(Number(this.getValue()!), "Music");
632
+ FieldNote.playNote_(Number(this.getValue()!), 'Music')
727
633
  }
728
634
  }
729
635
 
730
636
  /**
731
637
  * Function to play a musical note corresponding to the key selected.
732
638
  * Overridden externally.
733
- *
734
639
  * @param noteNum the MIDI note number to play.
735
640
  * @param id An id to select a scratch extension to play the note.
736
641
  */
737
642
  static playNote_ = function (noteNum: number, id: string) {
738
- return;
739
- };
643
+ return
644
+ }
740
645
 
741
646
  /**
742
647
  * Change the selected note by a number of octaves, and start the animation.
743
- *
744
648
  * @param octaves The number of octaves to change by.
745
649
  */
746
650
  private changeOctaveBy_(octaves: number) {
747
- this.displayedOctave_ = (this.displayedOctave_ ?? 0) + octaves;
651
+ this.displayedOctave_ = (this.displayedOctave_ ?? 0) + octaves
748
652
  if (this.displayedOctave_ < 0) {
749
- this.displayedOctave_ = 0;
750
- return;
653
+ this.displayedOctave_ = 0
654
+ return
751
655
  }
752
- const maxOctave = Math.floor(FieldNote.MAX_NOTE / 12);
656
+ const maxOctave = Math.floor(FieldNote.MAX_NOTE / 12)
753
657
  if (this.displayedOctave_ > maxOctave) {
754
- this.displayedOctave_ = maxOctave;
755
- return;
658
+ this.displayedOctave_ = maxOctave
659
+ return
756
660
  }
757
661
 
758
- const newNote = Number(this.getText()) + octaves * 12;
759
- this.setEditorValue_(newNote);
662
+ const newNote = Number(this.getText()) + octaves * 12
663
+ this.setEditorValue_(newNote)
760
664
 
761
- this.animationTarget_ = this.fieldEditorWidth_ * octaves * -1;
762
- this.animationPos_ = 0;
763
- this.stepOctaveAnimation_();
764
- this.setCKeyLabelsVisible_(false);
665
+ this.animationTarget_ = this.fieldEditorWidth_ * octaves * -1
666
+ this.animationPos_ = 0
667
+ this.stepOctaveAnimation_()
668
+ this.setCKeyLabelsVisible_(false)
765
669
  }
766
670
 
767
671
  /**
768
672
  * Animate the piano up or down an octave by sliding it to the left or right.
769
673
  */
770
674
  private stepOctaveAnimation_() {
771
- const absDiff = Math.abs(this.animationPos_ - this.animationTarget_);
675
+ const absDiff = Math.abs(this.animationPos_ - this.animationTarget_)
772
676
  if (absDiff < 1) {
773
- this.pianoSVG_?.setAttribute("transform", "translate(0, 0)");
774
- this.setCKeyLabelsVisible_(true);
775
- this.playNoteInternal_();
776
- return;
677
+ this.pianoSVG_?.setAttribute('transform', 'translate(0, 0)')
678
+ this.setCKeyLabelsVisible_(true)
679
+ this.playNoteInternal_()
680
+ return
777
681
  }
778
- this.animationPos_ +=
779
- (this.animationTarget_ - this.animationPos_) *
780
- FieldNote.ANIMATION_FRACTION;
781
- this.pianoSVG_?.setAttribute(
782
- "transform",
783
- "translate(" + this.animationPos_ + ",0)"
784
- );
785
- requestAnimationFrame(this.stepOctaveAnimation_.bind(this));
682
+ this.animationPos_ += (this.animationTarget_ - this.animationPos_) * FieldNote.ANIMATION_FRACTION
683
+ this.pianoSVG_?.setAttribute('transform', 'translate(' + this.animationPos_ + ',0)')
684
+ requestAnimationFrame(this.stepOctaveAnimation_.bind(this))
786
685
  }
787
686
 
788
687
  doValueUpdate_(newValue: string) {
789
- super.doValueUpdate_(newValue);
688
+ super.doValueUpdate_(newValue)
790
689
 
791
690
  if (!this.textElement_) {
792
691
  // Not rendered yet.
793
- return;
692
+ return
794
693
  }
795
694
 
796
- this.updateSelection_();
695
+ this.updateSelection_()
797
696
  }
798
697
 
799
698
  /**
800
699
  * For a MIDI note number, find the index of the corresponding piano key.
801
- *
802
700
  * @param noteNum The note number.
803
701
  * @returns The index of the piano key.
804
702
  */
805
703
  private noteNumToKeyIndex_(noteNum: number): number {
806
- return Math.floor(noteNum) - (this.displayedOctave_ ?? 0) * 12;
704
+ return Math.floor(noteNum) - (this.displayedOctave_ ?? 0) * 12
807
705
  }
808
706
 
809
707
  /**
810
708
  * Update the selected note and labels on the field.
811
709
  */
812
710
  private updateSelection_() {
813
- const noteNum = Number(this.getText());
711
+ const noteNum = Number(this.getText())
814
712
 
815
713
  // If the note is outside the currently displayed octave, update it
816
714
  if (
@@ -818,68 +716,65 @@ export class FieldNote extends Blockly.FieldTextInput {
818
716
  noteNum > this.displayedOctave_ * 12 + 12 ||
819
717
  noteNum < this.displayedOctave_ * 12
820
718
  ) {
821
- this.displayedOctave_ = Math.floor(noteNum / 12);
719
+ this.displayedOctave_ = Math.floor(noteNum / 12)
822
720
  }
823
721
 
824
- const index = this.noteNumToKeyIndex_(noteNum);
722
+ const index = this.noteNumToKeyIndex_(noteNum)
825
723
 
826
724
  // Clear the highlight on all keys
827
- this.keySVGs_.forEach(function (svg) {
828
- const isBlack = svg.getAttribute("data-isBlack");
829
- if (isBlack === "true") {
830
- svg.setAttribute("fill", FieldNote.BLACK_KEY_COLOR);
725
+ this.keySVGs_.forEach(svg => {
726
+ const isBlack = svg.getAttribute('data-isBlack')
727
+ if (isBlack === 'true') {
728
+ svg.setAttribute('fill', FieldNote.BLACK_KEY_COLOR)
831
729
  } else {
832
- svg.setAttribute("fill", FieldNote.WHITE_KEY_COLOR);
730
+ svg.setAttribute('fill', FieldNote.WHITE_KEY_COLOR)
833
731
  }
834
- });
732
+ })
835
733
  // Set the highlight on the selected key
836
734
  if (this.keySVGs_[index]) {
837
- this.keySVGs_[index].setAttribute("fill", FieldNote.KEY_SELECTED_COLOR);
735
+ this.keySVGs_[index].setAttribute('fill', FieldNote.KEY_SELECTED_COLOR)
838
736
  // Update the note name text
839
- const noteName = FieldNote.KEY_INFO[index].name;
737
+ const noteName = FieldNote.KEY_INFO[index].name
840
738
  if (this.noteNameText_) {
841
- this.noteNameText_.textContent =
842
- noteName + " (" + Math.floor(noteNum) + ")";
739
+ this.noteNameText_.textContent = noteName + ' (' + Math.floor(noteNum) + ')'
843
740
  }
844
741
  // Update the low and high C note names
845
- const lowCNum = (this.displayedOctave_ ?? 0) * 12;
846
- if (this.lowCText_) this.lowCText_.textContent = "C(" + lowCNum + ")";
847
- if (this.highCText_)
848
- this.highCText_.textContent = "C(" + (lowCNum + 12) + ")";
742
+ const lowCNum = (this.displayedOctave_ ?? 0) * 12
743
+ if (this.lowCText_) this.lowCText_.textContent = 'C(' + lowCNum + ')'
744
+ if (this.highCText_) this.highCText_.textContent = 'C(' + (lowCNum + 12) + ')'
849
745
  }
850
746
  }
851
747
 
852
748
  /**
853
749
  * Ensure that only a valid MIDI note number may be entered.
854
- *
855
750
  * @param text The user's text.
856
751
  * @returns A string representing a valid note number, or null if invalid.
857
752
  */
858
753
  doClassValidation_(text: string): string | null {
859
754
  if (text === null) {
860
- return null;
755
+ return null
861
756
  }
862
- var n = parseFloat(text || "0");
757
+ let n = parseFloat(text || '0')
863
758
  if (isNaN(n)) {
864
- return null;
759
+ return null
865
760
  }
866
761
  if (n < 0) {
867
- n = 0;
762
+ n = 0
868
763
  }
869
764
  if (n > FieldNote.MAX_NOTE) {
870
- n = FieldNote.MAX_NOTE;
765
+ n = FieldNote.MAX_NOTE
871
766
  }
872
- return String(n);
767
+ return String(n)
873
768
  }
874
769
  }
875
770
 
876
771
  interface FieldNoteJsonConfig extends Blockly.FieldTextInputFromJsonConfig {
877
- note: string;
772
+ note: string
878
773
  }
879
774
 
880
775
  /**
881
776
  * Register the field and any dependencies.
882
777
  */
883
778
  export function registerFieldNote() {
884
- Blockly.fieldRegistry.register("field_note", FieldNote);
779
+ Blockly.fieldRegistry.register('field_note', FieldNote)
885
780
  }