scratch-blocks 2.0.2 → 2.0.4
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.
- package/.nvmrc +1 -1
- package/commitlint.config.js +2 -2
- package/dist/main.mjs +1 -2
- package/dist/types/msg/scratch_msgs.d.ts.map +1 -1
- package/dist/types/src/block_reporting.d.ts.map +1 -1
- package/dist/types/src/blocks/colour.d.ts +0 -19
- package/dist/types/src/blocks/colour.d.ts.map +1 -1
- package/dist/types/src/blocks/control.d.ts +0 -19
- package/dist/types/src/blocks/control.d.ts.map +1 -1
- package/dist/types/src/blocks/data.d.ts +0 -19
- package/dist/types/src/blocks/data.d.ts.map +1 -1
- package/dist/types/src/blocks/event.d.ts +0 -19
- package/dist/types/src/blocks/event.d.ts.map +1 -1
- package/dist/types/src/blocks/looks.d.ts +0 -19
- package/dist/types/src/blocks/looks.d.ts.map +1 -1
- package/dist/types/src/blocks/math.d.ts +0 -19
- package/dist/types/src/blocks/math.d.ts.map +1 -1
- package/dist/types/src/blocks/matrix.d.ts +0 -19
- package/dist/types/src/blocks/matrix.d.ts.map +1 -1
- package/dist/types/src/blocks/motion.d.ts +0 -19
- package/dist/types/src/blocks/motion.d.ts.map +1 -1
- package/dist/types/src/blocks/note.d.ts +0 -19
- package/dist/types/src/blocks/note.d.ts.map +1 -1
- package/dist/types/src/blocks/operators.d.ts +0 -19
- package/dist/types/src/blocks/operators.d.ts.map +1 -1
- package/dist/types/src/blocks/procedures.d.ts +7 -10
- package/dist/types/src/blocks/procedures.d.ts.map +1 -1
- package/dist/types/src/blocks/sensing.d.ts +0 -19
- package/dist/types/src/blocks/sensing.d.ts.map +1 -1
- package/dist/types/src/blocks/sound.d.ts +0 -19
- package/dist/types/src/blocks/sound.d.ts.map +1 -1
- package/dist/types/src/blocks/text.d.ts +0 -19
- package/dist/types/src/blocks/text.d.ts.map +1 -1
- package/dist/types/src/blocks/vertical_extensions.d.ts +0 -19
- package/dist/types/src/blocks/vertical_extensions.d.ts.map +1 -1
- package/dist/types/src/checkable_continuous_flyout.d.ts +2 -7
- package/dist/types/src/checkable_continuous_flyout.d.ts.map +1 -1
- package/dist/types/src/checkbox_bubble.d.ts +13 -12
- package/dist/types/src/checkbox_bubble.d.ts.map +1 -1
- package/dist/types/src/colours.d.ts.map +1 -1
- package/dist/types/src/constants.d.ts +0 -7
- package/dist/types/src/constants.d.ts.map +1 -1
- package/dist/types/src/context_menu_items.d.ts +0 -5
- package/dist/types/src/context_menu_items.d.ts.map +1 -1
- package/dist/types/src/data_category.d.ts +2 -4
- package/dist/types/src/data_category.d.ts.map +1 -1
- package/dist/types/src/events/events_block_comment_base.d.ts +2 -3
- package/dist/types/src/events/events_block_comment_base.d.ts.map +1 -1
- package/dist/types/src/events/events_block_comment_change.d.ts +0 -5
- package/dist/types/src/events/events_block_comment_change.d.ts.map +1 -1
- package/dist/types/src/events/events_block_comment_collapse.d.ts +0 -5
- package/dist/types/src/events/events_block_comment_collapse.d.ts.map +1 -1
- package/dist/types/src/events/events_block_comment_create.d.ts +0 -5
- package/dist/types/src/events/events_block_comment_create.d.ts.map +1 -1
- package/dist/types/src/events/events_block_comment_delete.d.ts +0 -5
- package/dist/types/src/events/events_block_comment_delete.d.ts.map +1 -1
- package/dist/types/src/events/events_block_comment_move.d.ts +0 -5
- package/dist/types/src/events/events_block_comment_move.d.ts.map +1 -1
- package/dist/types/src/events/events_block_comment_resize.d.ts +0 -5
- package/dist/types/src/events/events_block_comment_resize.d.ts.map +1 -1
- package/dist/types/src/events/events_block_drag_end.d.ts +1 -2
- package/dist/types/src/events/events_block_drag_end.d.ts.map +1 -1
- package/dist/types/src/events/events_block_drag_outside.d.ts +1 -2
- package/dist/types/src/events/events_block_drag_outside.d.ts.map +1 -1
- package/dist/types/src/events/events_scratch_variable_create.d.ts +0 -5
- package/dist/types/src/events/events_scratch_variable_create.d.ts.map +1 -1
- package/dist/types/src/fields/field_colour_slider.d.ts +7 -9
- package/dist/types/src/fields/field_colour_slider.d.ts.map +1 -1
- package/dist/types/src/fields/field_matrix.d.ts +0 -19
- package/dist/types/src/fields/field_matrix.d.ts.map +1 -1
- package/dist/types/src/fields/field_note.d.ts +8 -23
- package/dist/types/src/fields/field_note.d.ts.map +1 -1
- package/dist/types/src/fields/field_textinput_removable.d.ts +2 -4
- package/dist/types/src/fields/field_textinput_removable.d.ts.map +1 -1
- package/dist/types/src/fields/field_variable_getter.d.ts +0 -19
- package/dist/types/src/fields/field_variable_getter.d.ts.map +1 -1
- package/dist/types/src/fields/field_vertical_separator.d.ts +0 -19
- package/dist/types/src/fields/field_vertical_separator.d.ts.map +1 -1
- package/dist/types/src/fields/scratch_field_angle.d.ts +0 -19
- package/dist/types/src/fields/scratch_field_angle.d.ts.map +1 -1
- package/dist/types/src/fields/scratch_field_dropdown.d.ts +0 -5
- package/dist/types/src/fields/scratch_field_dropdown.d.ts.map +1 -1
- package/dist/types/src/fields/scratch_field_number.d.ts +0 -19
- package/dist/types/src/fields/scratch_field_number.d.ts.map +1 -1
- package/dist/types/src/fields/scratch_field_variable.d.ts +4 -7
- package/dist/types/src/fields/scratch_field_variable.d.ts.map +1 -1
- package/dist/types/src/flyout_checkbox_icon.d.ts +2 -3
- package/dist/types/src/flyout_checkbox_icon.d.ts.map +1 -1
- package/dist/types/src/glows.d.ts +1 -3
- package/dist/types/src/glows.d.ts.map +1 -1
- package/dist/types/src/index.d.ts +50 -55
- package/dist/types/src/index.d.ts.map +1 -1
- package/dist/types/src/procedures.d.ts +6 -8
- package/dist/types/src/procedures.d.ts.map +1 -1
- package/dist/types/src/recyclable_block_flyout_inflater.d.ts +3 -5
- package/dist/types/src/recyclable_block_flyout_inflater.d.ts.map +1 -1
- package/dist/types/src/renderer/bowler_hat.d.ts +2 -3
- package/dist/types/src/renderer/bowler_hat.d.ts.map +1 -1
- package/dist/types/src/renderer/cat/cat_face.d.ts +6 -5
- package/dist/types/src/renderer/cat/cat_face.d.ts.map +1 -1
- package/dist/types/src/renderer/cat/constants.d.ts +2 -2
- package/dist/types/src/renderer/cat/constants.d.ts.map +1 -1
- package/dist/types/src/renderer/cat/drawer.d.ts +3 -4
- package/dist/types/src/renderer/cat/drawer.d.ts.map +1 -1
- package/dist/types/src/renderer/cat/path_object.d.ts +2 -3
- package/dist/types/src/renderer/cat/path_object.d.ts.map +1 -1
- package/dist/types/src/renderer/cat/render_info.d.ts +3 -4
- package/dist/types/src/renderer/cat/render_info.d.ts.map +1 -1
- package/dist/types/src/renderer/cat/renderer.d.ts +6 -7
- package/dist/types/src/renderer/cat/renderer.d.ts.map +1 -1
- package/dist/types/src/renderer/constants.d.ts +4 -4
- package/dist/types/src/renderer/constants.d.ts.map +1 -1
- package/dist/types/src/renderer/drawer.d.ts +5 -4
- package/dist/types/src/renderer/drawer.d.ts.map +1 -1
- package/dist/types/src/renderer/path_object.d.ts +1 -3
- package/dist/types/src/renderer/path_object.d.ts.map +1 -1
- package/dist/types/src/renderer/render_info.d.ts +3 -4
- package/dist/types/src/renderer/render_info.d.ts.map +1 -1
- package/dist/types/src/renderer/renderer.d.ts +8 -15
- package/dist/types/src/renderer/renderer.d.ts.map +1 -1
- package/dist/types/src/scratch_block_paster.d.ts +0 -5
- package/dist/types/src/scratch_block_paster.d.ts.map +1 -1
- package/dist/types/src/scratch_blocks_utils.d.ts +0 -20
- package/dist/types/src/scratch_blocks_utils.d.ts.map +1 -1
- package/dist/types/src/scratch_comment_bubble.d.ts +1 -4
- package/dist/types/src/scratch_comment_bubble.d.ts.map +1 -1
- package/dist/types/src/scratch_comment_icon.d.ts +2 -3
- package/dist/types/src/scratch_comment_icon.d.ts.map +1 -1
- package/dist/types/src/scratch_connection_checker.d.ts +0 -5
- package/dist/types/src/scratch_connection_checker.d.ts.map +1 -1
- package/dist/types/src/scratch_continuous_category.d.ts +5 -5
- package/dist/types/src/scratch_continuous_category.d.ts.map +1 -1
- package/dist/types/src/scratch_continuous_toolbox.d.ts +3 -6
- package/dist/types/src/scratch_continuous_toolbox.d.ts.map +1 -1
- package/dist/types/src/scratch_dragger.d.ts +3 -12
- package/dist/types/src/scratch_dragger.d.ts.map +1 -1
- package/dist/types/src/scratch_insertion_marker_previewer.d.ts +0 -5
- package/dist/types/src/scratch_insertion_marker_previewer.d.ts.map +1 -1
- package/dist/types/src/scratch_variable_map.d.ts +0 -5
- package/dist/types/src/scratch_variable_map.d.ts.map +1 -1
- package/dist/types/src/scratch_variable_model.d.ts +1 -2
- package/dist/types/src/scratch_variable_model.d.ts.map +1 -1
- package/dist/types/src/scratch_zoom_controls.d.ts +4 -6
- package/dist/types/src/scratch_zoom_controls.d.ts.map +1 -1
- package/dist/types/src/shadows.d.ts +2 -2
- package/dist/types/src/shadows.d.ts.map +1 -1
- package/dist/types/src/status_indicator_label.d.ts +4 -6
- package/dist/types/src/status_indicator_label.d.ts.map +1 -1
- package/dist/types/src/status_indicator_label_flyout_inflater.d.ts +1 -6
- package/dist/types/src/status_indicator_label_flyout_inflater.d.ts.map +1 -1
- package/dist/types/src/variables.d.ts +4 -8
- package/dist/types/src/variables.d.ts.map +1 -1
- package/dist/types/src/xml.d.ts +2 -3
- package/dist/types/src/xml.d.ts.map +1 -1
- package/dist/types/tests/jsunit/block_test.d.ts.map +1 -1
- package/dist/types/tests/jsunit/connection_db_test.d.ts.map +1 -1
- package/dist/types/tests/jsunit/connection_test.d.ts.map +1 -1
- package/dist/types/tests/jsunit/event_test.d.ts.map +1 -1
- package/dist/types/tests/jsunit/extensions_test.d.ts.map +1 -1
- package/dist/types/tests/jsunit/field_number_test.d.ts.map +1 -1
- package/dist/types/tests/jsunit/field_test.d.ts.map +1 -1
- package/dist/types/tests/jsunit/field_variable_getter_test.d.ts.map +1 -1
- package/dist/types/tests/jsunit/field_variable_test.d.ts.map +1 -1
- package/dist/types/tests/jsunit/gesture_test.d.ts.map +1 -1
- package/dist/types/tests/jsunit/input_test.d.ts +1 -0
- package/dist/types/tests/jsunit/input_test.d.ts.map +1 -1
- package/dist/types/tests/jsunit/json_test.d.ts.map +1 -1
- package/dist/types/tests/jsunit/names_test.d.ts.map +1 -1
- package/dist/types/tests/jsunit/procedure_test.d.ts.map +1 -1
- package/dist/types/tests/jsunit/scratch_block_comment_test.d.ts.map +1 -1
- package/dist/types/tests/jsunit/svg_test.d.ts.map +1 -1
- package/dist/types/tests/jsunit/test_utilities.d.ts.map +1 -1
- package/dist/types/tests/jsunit/utils_test.d.ts.map +1 -1
- package/dist/types/tests/jsunit/variable_map_test.d.ts.map +1 -1
- package/dist/types/tests/jsunit/variable_model_test.d.ts.map +1 -1
- package/dist/types/tests/jsunit/widget_div_test.d.ts.map +1 -1
- package/dist/types/tests/jsunit/workspace_comment_test.d.ts.map +1 -1
- package/dist/types/tests/jsunit/workspace_test.d.ts.map +1 -1
- package/dist/types/tests/jsunit/workspace_undo_redo_test.d.ts.map +1 -1
- package/dist/types/tests/jsunit/xml_test.d.ts.map +1 -1
- package/dist/types/tests/workspace_svg/workspace_svg_test.d.ts.map +1 -1
- package/eslint.config.mjs +69 -0
- package/i18n/create_scratch_msgs.js +44 -45
- package/i18n/js_to_json.js +40 -32
- package/i18n/json_to_js.js +37 -37
- package/i18n/sync_tx_translations.js +64 -65
- package/i18n/test_scratch_msgs.js +66 -63
- package/msg/js/en.js +289 -287
- package/msg/json/en.json +284 -284
- package/msg/messages.js +289 -287
- package/msg/scratch_msgs.js +22959 -22970
- package/package.json +13 -10
- package/prettier.config.mjs +3 -0
- package/release.config.js +7 -7
- package/renovate.json5 +7 -9
- package/src/block_reporting.ts +15 -18
- package/src/blocks/colour.ts +12 -15
- package/src/blocks/control.ts +167 -177
- package/src/blocks/data.ts +225 -292
- package/src/blocks/event.ts +121 -123
- package/src/blocks/looks.ts +165 -167
- package/src/blocks/math.ts +44 -46
- package/src/blocks/matrix.ts +11 -13
- package/src/blocks/motion.ts +151 -153
- package/src/blocks/note.ts +11 -13
- package/src/blocks/operators.ts +158 -160
- package/src/blocks/procedures.ts +488 -536
- package/src/blocks/sensing.ts +163 -165
- package/src/blocks/sound.ts +58 -60
- package/src/blocks/text.ts +10 -12
- package/src/blocks/vertical_extensions.ts +86 -102
- package/src/checkable_continuous_flyout.ts +25 -42
- package/src/checkbox_bubble.ts +83 -100
- package/src/colours.ts +35 -37
- package/src/constants.ts +22 -29
- package/src/context_menu_items.ts +56 -81
- package/src/css.ts +3 -4
- package/src/data_category.ts +136 -250
- package/src/events/events_block_comment_base.ts +21 -31
- package/src/events/events_block_comment_change.ts +21 -42
- package/src/events/events_block_comment_collapse.ts +22 -43
- package/src/events/events_block_comment_create.ts +29 -46
- package/src/events/events_block_comment_delete.ts +10 -19
- package/src/events/events_block_comment_move.ts +27 -52
- package/src/events/events_block_comment_resize.ts +28 -55
- package/src/events/events_block_drag_end.ts +16 -26
- package/src/events/events_block_drag_outside.ts +12 -22
- package/src/events/events_scratch_variable_create.ts +33 -56
- package/src/fields/field_colour_slider.ts +173 -228
- package/src/fields/field_matrix.ts +200 -269
- package/src/fields/field_note.ts +272 -377
- package/src/fields/field_textinput_removable.ts +25 -40
- package/src/fields/field_variable_getter.ts +26 -31
- package/src/fields/field_vertical_separator.ts +19 -24
- package/src/fields/scratch_field_angle.ts +150 -186
- package/src/fields/scratch_field_dropdown.ts +15 -19
- package/src/fields/scratch_field_number.ts +123 -180
- package/src/fields/scratch_field_variable.ts +52 -73
- package/src/flyout_checkbox_icon.ts +18 -28
- package/src/glows.ts +51 -58
- package/src/index.ts +119 -133
- package/src/procedures.ts +144 -211
- package/src/recyclable_block_flyout_inflater.ts +14 -25
- package/src/renderer/bowler_hat.ts +6 -8
- package/src/renderer/cat/cat_face.ts +98 -99
- package/src/renderer/cat/constants.ts +67 -87
- package/src/renderer/cat/drawer.ts +21 -27
- package/src/renderer/cat/path_object.ts +3 -5
- package/src/renderer/cat/render_info.ts +5 -8
- package/src/renderer/cat/renderer.ts +11 -15
- package/src/renderer/constants.ts +34 -49
- package/src/renderer/drawer.ts +35 -51
- package/src/renderer/path_object.ts +13 -15
- package/src/renderer/render_info.ts +36 -56
- package/src/renderer/renderer.ts +16 -29
- package/src/scratch_block_paster.ts +12 -20
- package/src/scratch_blocks_utils.ts +4 -7
- package/src/scratch_comment_bubble.ts +70 -101
- package/src/scratch_comment_icon.ts +74 -123
- package/src/scratch_connection_checker.ts +22 -17
- package/src/scratch_continuous_category.ts +24 -28
- package/src/scratch_continuous_toolbox.ts +20 -27
- package/src/scratch_dragger.ts +54 -86
- package/src/scratch_insertion_marker_previewer.ts +6 -11
- package/src/scratch_variable_map.ts +5 -12
- package/src/scratch_variable_model.ts +4 -11
- package/src/scratch_zoom_controls.ts +101 -156
- package/src/shadows.ts +32 -37
- package/src/status_indicator_label.ts +54 -67
- package/src/status_indicator_label_flyout_inflater.ts +11 -21
- package/src/variables.ts +89 -138
- package/src/xml.ts +21 -35
- package/tsconfig.json +2 -6
- package/types/continuous-toolbox.d.ts +1 -1
- package/dist/main.mjs.LICENSE.txt +0 -163
package/src/fields/field_note.ts
CHANGED
|
@@ -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
|
-
* @
|
|
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
|
|
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
|
|
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
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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:
|
|
213
|
-
{ name:
|
|
214
|
-
{ name:
|
|
215
|
-
{ name:
|
|
216
|
-
{ name:
|
|
217
|
-
{ name:
|
|
218
|
-
{ name:
|
|
219
|
-
{ name:
|
|
220
|
-
{ name:
|
|
221
|
-
{ name:
|
|
222
|
-
{ name:
|
|
223
|
-
{ name:
|
|
224
|
-
{ name:
|
|
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 =
|
|
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
|
|
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(
|
|
264
|
-
Blockly.browserEvents.unbind(wrapper)
|
|
265
|
-
})
|
|
266
|
-
this.mouseEnterWrappers_.forEach(
|
|
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
|
-
|
|
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
|
-
|
|
295
|
+
'svg',
|
|
304
296
|
{
|
|
305
|
-
xmlns:
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
version:
|
|
309
|
-
height: this.fieldEditorHeight_ +
|
|
310
|
-
width: this.fieldEditorWidth_ +
|
|
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(
|
|
319
|
-
const whiteKeyGroup = Blockly.utils.dom.createSvgElement(
|
|
320
|
-
|
|
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
|
-
|
|
335
|
-
|
|
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
|
-
|
|
323
|
+
'text',
|
|
350
324
|
{
|
|
351
325
|
x: this.fieldEditorWidth_ / 2,
|
|
352
326
|
y: FieldNote.TOP_MENU_HEIGHT / 2,
|
|
353
|
-
class:
|
|
354
|
-
|
|
355
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
()
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
)
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
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 (
|
|
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
|
-
|
|
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(
|
|
430
|
+
const keySVG = Blockly.utils.dom.createSvgElement('path', attr, group)
|
|
478
431
|
|
|
479
432
|
if (keySVGarray) {
|
|
480
|
-
keySVGarray[i] = keySVG
|
|
481
|
-
keySVG.setAttribute(
|
|
482
|
-
keySVG.setAttribute(
|
|
483
|
-
keySVG.setAttribute(
|
|
484
|
-
|
|
485
|
-
this.mouseDownWrappers_[i] = Blockly.browserEvents.bind(
|
|
486
|
-
|
|
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
|
|
508
|
-
* @param height the
|
|
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
|
-
|
|
455
|
+
'M' +
|
|
519
456
|
x +
|
|
520
|
-
|
|
457
|
+
' ' +
|
|
521
458
|
y +
|
|
522
|
-
|
|
523
|
-
|
|
459
|
+
' ' +
|
|
460
|
+
'L' +
|
|
524
461
|
x +
|
|
525
|
-
|
|
462
|
+
' ' +
|
|
526
463
|
(y + height - FieldNote.KEY_RADIUS) +
|
|
527
|
-
|
|
528
|
-
|
|
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
|
-
|
|
473
|
+
' ' +
|
|
474
|
+
'L' +
|
|
538
475
|
(x + width - FieldNote.KEY_RADIUS) +
|
|
539
|
-
|
|
476
|
+
' ' +
|
|
540
477
|
(y + height) +
|
|
541
|
-
|
|
542
|
-
|
|
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
|
-
|
|
487
|
+
' ' +
|
|
488
|
+
'L' +
|
|
552
489
|
(x + width) +
|
|
553
|
-
|
|
490
|
+
' ' +
|
|
554
491
|
y +
|
|
555
|
-
|
|
556
|
-
|
|
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
|
-
|
|
573
|
-
|
|
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
|
-
|
|
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
|
-
|
|
590
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
551
|
+
'text',
|
|
627
552
|
{
|
|
628
553
|
x: x,
|
|
629
|
-
y:
|
|
630
|
-
|
|
631
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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(
|
|
716
|
-
|
|
717
|
-
this.
|
|
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()!),
|
|
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(
|
|
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
|
-
|
|
780
|
-
|
|
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(
|
|
828
|
-
const isBlack = svg.getAttribute(
|
|
829
|
-
if (isBlack ===
|
|
830
|
-
svg.setAttribute(
|
|
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(
|
|
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(
|
|
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 =
|
|
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
|
-
|
|
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(
|
|
779
|
+
Blockly.fieldRegistry.register('field_note', FieldNote)
|
|
885
780
|
}
|