@blockdia/scratch-blocks 0.1.0

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 (243) hide show
  1. package/.nvmrc +1 -0
  2. package/LICENSE +674 -0
  3. package/README.md +57 -0
  4. package/TRADEMARK +1 -0
  5. package/blockly_compressed_horizontal.js +2268 -0
  6. package/blockly_compressed_vertical.js +2296 -0
  7. package/blockly_uncompressed_horizontal.js +1212 -0
  8. package/blockly_uncompressed_vertical.js +1212 -0
  9. package/blocks_common/colour.js +61 -0
  10. package/blocks_common/math.js +159 -0
  11. package/blocks_common/matrix.js +54 -0
  12. package/blocks_common/note.js +58 -0
  13. package/blocks_common/text.js +57 -0
  14. package/blocks_compressed.js +37 -0
  15. package/blocks_compressed_horizontal.js +68 -0
  16. package/blocks_compressed_vertical.js +216 -0
  17. package/blocks_horizontal/control.js +212 -0
  18. package/blocks_horizontal/default_toolbox.js +139 -0
  19. package/blocks_horizontal/event.js +190 -0
  20. package/blocks_horizontal/wedo.js +325 -0
  21. package/blocks_vertical/control.js +532 -0
  22. package/blocks_vertical/data.js +666 -0
  23. package/blocks_vertical/default_toolbox.js +571 -0
  24. package/blocks_vertical/event.js +329 -0
  25. package/blocks_vertical/extensions.js +294 -0
  26. package/blocks_vertical/looks.js +591 -0
  27. package/blocks_vertical/motion.js +587 -0
  28. package/blocks_vertical/operators.js +470 -0
  29. package/blocks_vertical/procedures.js +1051 -0
  30. package/blocks_vertical/sensing.js +555 -0
  31. package/blocks_vertical/sound.js +246 -0
  32. package/blocks_vertical/vertical_extensions.js +289 -0
  33. package/build/gen_blocks.js +1 -0
  34. package/build/test_expect.js +1 -0
  35. package/build/test_input.js +1 -0
  36. package/build.py +647 -0
  37. package/cleanup.sh +101 -0
  38. package/core/block.js +1837 -0
  39. package/core/block_animations.js +107 -0
  40. package/core/block_drag_surface.js +299 -0
  41. package/core/block_dragger.js +424 -0
  42. package/core/block_events.js +531 -0
  43. package/core/block_render_svg_horizontal.js +892 -0
  44. package/core/block_render_svg_vertical.js +1734 -0
  45. package/core/block_svg.js +1355 -0
  46. package/core/blockly.js +620 -0
  47. package/core/blocks.js +37 -0
  48. package/core/bubble.js +664 -0
  49. package/core/bubble_dragger.js +285 -0
  50. package/core/colours.js +177 -0
  51. package/core/comment.js +293 -0
  52. package/core/comment_events.js +539 -0
  53. package/core/connection.js +776 -0
  54. package/core/connection_db.js +300 -0
  55. package/core/constants.js +408 -0
  56. package/core/contextmenu.js +534 -0
  57. package/core/css.js +1354 -0
  58. package/core/data_category.js +490 -0
  59. package/core/dragged_connection_manager.js +260 -0
  60. package/core/dropdowndiv.js +408 -0
  61. package/core/events.js +429 -0
  62. package/core/events_abstract.js +113 -0
  63. package/core/extensions.js +450 -0
  64. package/core/field.js +810 -0
  65. package/core/field_angle.js +410 -0
  66. package/core/field_checkbox.js +133 -0
  67. package/core/field_colour.js +253 -0
  68. package/core/field_colour_slider.js +387 -0
  69. package/core/field_date.js +353 -0
  70. package/core/field_dropdown.js +447 -0
  71. package/core/field_iconmenu.js +309 -0
  72. package/core/field_image.js +200 -0
  73. package/core/field_label.js +136 -0
  74. package/core/field_label_serializable.js +125 -0
  75. package/core/field_matrix.js +566 -0
  76. package/core/field_note.js +850 -0
  77. package/core/field_number.js +366 -0
  78. package/core/field_numberdropdown.js +77 -0
  79. package/core/field_textdropdown.js +164 -0
  80. package/core/field_textinput.js +675 -0
  81. package/core/field_textinput_removable.js +105 -0
  82. package/core/field_variable.js +385 -0
  83. package/core/field_variable_getter.js +185 -0
  84. package/core/field_vertical_separator.js +161 -0
  85. package/core/flyout_base.js +935 -0
  86. package/core/flyout_button.js +324 -0
  87. package/core/flyout_dragger.js +83 -0
  88. package/core/flyout_extension_category_header.js +159 -0
  89. package/core/flyout_horizontal.js +475 -0
  90. package/core/flyout_vertical.js +770 -0
  91. package/core/generator.js +426 -0
  92. package/core/gesture.js +1010 -0
  93. package/core/grid.js +227 -0
  94. package/core/icon.js +205 -0
  95. package/core/inject.js +496 -0
  96. package/core/input.js +285 -0
  97. package/core/insertion_marker_manager.js +678 -0
  98. package/core/intersection_observer.js +102 -0
  99. package/core/msg.js +62 -0
  100. package/core/mutator.js +426 -0
  101. package/core/names.js +198 -0
  102. package/core/options.js +244 -0
  103. package/core/procedures.js +739 -0
  104. package/core/rendered_connection.js +417 -0
  105. package/core/scratch_block_comment.js +646 -0
  106. package/core/scratch_blocks_utils.js +246 -0
  107. package/core/scratch_bubble.js +699 -0
  108. package/core/scratch_events.js +131 -0
  109. package/core/scratch_msgs.js +85 -0
  110. package/core/scrollbar.js +875 -0
  111. package/core/toolbox.js +803 -0
  112. package/core/tooltip.js +337 -0
  113. package/core/touch.js +226 -0
  114. package/core/trashcan.js +343 -0
  115. package/core/ui_events.js +91 -0
  116. package/core/ui_menu_utils.js +68 -0
  117. package/core/utils.js +825 -0
  118. package/core/variable_events.js +259 -0
  119. package/core/variable_map.js +415 -0
  120. package/core/variable_model.js +116 -0
  121. package/core/variables.js +674 -0
  122. package/core/warning.js +199 -0
  123. package/core/widgetdiv.js +344 -0
  124. package/core/workspace.js +673 -0
  125. package/core/workspace_audio.js +170 -0
  126. package/core/workspace_comment.js +426 -0
  127. package/core/workspace_comment_render_svg.js +706 -0
  128. package/core/workspace_comment_svg.js +609 -0
  129. package/core/workspace_drag_surface_svg.js +195 -0
  130. package/core/workspace_dragger.js +132 -0
  131. package/core/workspace_svg.js +2382 -0
  132. package/core/xml.js +930 -0
  133. package/core/zoom_controls.js +301 -0
  134. package/dist/horizontal.js +222 -0
  135. package/dist/vertical.js +222 -0
  136. package/dist/web/horizontal.js +232 -0
  137. package/dist/web/vertical.js +232 -0
  138. package/i18n/common.py +234 -0
  139. package/i18n/create_messages.py +162 -0
  140. package/i18n/create_scratch_msgs.js +69 -0
  141. package/i18n/dedup_json.py +73 -0
  142. package/i18n/js_to_json.js +46 -0
  143. package/i18n/js_to_json.py +136 -0
  144. package/i18n/json_to_js.js +52 -0
  145. package/i18n/json_to_js.py +185 -0
  146. package/i18n/sync_tx_translations.js +111 -0
  147. package/i18n/test_scratch_msgs.js +87 -0
  148. package/i18n/tests.py +47 -0
  149. package/i18n/xliff_to_json.py +232 -0
  150. package/local_build.sh +70 -0
  151. package/media/click.mp3 +0 -0
  152. package/media/click.ogg +0 -0
  153. package/media/click.wav +0 -0
  154. package/media/comment-arrow-down.svg +10 -0
  155. package/media/comment-arrow-up.svg +10 -0
  156. package/media/delete-x.svg +10 -0
  157. package/media/delete.mp3 +0 -0
  158. package/media/delete.ogg +0 -0
  159. package/media/delete.wav +0 -0
  160. package/media/dropdown-arrow-dark.svg +1 -0
  161. package/media/dropdown-arrow.svg +1 -0
  162. package/media/extensions/microbit-block-icon.svg +130 -0
  163. package/media/extensions/music-block-icon.svg +17 -0
  164. package/media/extensions/pen-block-icon.svg +19 -0
  165. package/media/extensions/wedo2-block-icon.svg +36 -0
  166. package/media/eyedropper.svg +22 -0
  167. package/media/green-flag.svg +17 -0
  168. package/media/handclosed.cur +0 -0
  169. package/media/handdelete.cur +0 -0
  170. package/media/handopen.cur +0 -0
  171. package/media/icons/arrow.svg +12 -0
  172. package/media/icons/arrow_button.svg +1 -0
  173. package/media/icons/control_forever.svg +1 -0
  174. package/media/icons/control_repeat.svg +1 -0
  175. package/media/icons/control_stop.svg +1 -0
  176. package/media/icons/control_wait.svg +1 -0
  177. package/media/icons/event_broadcast_blue.svg +1 -0
  178. package/media/icons/event_broadcast_coral.svg +1 -0
  179. package/media/icons/event_broadcast_green.svg +1 -0
  180. package/media/icons/event_broadcast_magenta.svg +1 -0
  181. package/media/icons/event_broadcast_orange.svg +1 -0
  182. package/media/icons/event_broadcast_purple.svg +1 -0
  183. package/media/icons/event_when-broadcast-received_blue.svg +1 -0
  184. package/media/icons/event_when-broadcast-received_coral.svg +1 -0
  185. package/media/icons/event_when-broadcast-received_green.svg +1 -0
  186. package/media/icons/event_when-broadcast-received_magenta.svg +1 -0
  187. package/media/icons/event_when-broadcast-received_orange.svg +1 -0
  188. package/media/icons/event_when-broadcast-received_purple.svg +1 -0
  189. package/media/icons/event_whenflagclicked.svg +1 -0
  190. package/media/icons/remove.svg +19 -0
  191. package/media/icons/set-led_blue.svg +1 -0
  192. package/media/icons/set-led_coral.svg +1 -0
  193. package/media/icons/set-led_green.svg +1 -0
  194. package/media/icons/set-led_magenta.svg +1 -0
  195. package/media/icons/set-led_mystery.svg +1 -0
  196. package/media/icons/set-led_orange.svg +1 -0
  197. package/media/icons/set-led_purple.svg +1 -0
  198. package/media/icons/set-led_white.svg +1 -0
  199. package/media/icons/set-led_yellow.svg +1 -0
  200. package/media/icons/wedo_motor-clockwise.svg +1 -0
  201. package/media/icons/wedo_motor-counterclockwise.svg +1 -0
  202. package/media/icons/wedo_motor-speed_fast.svg +1 -0
  203. package/media/icons/wedo_motor-speed_med.svg +1 -0
  204. package/media/icons/wedo_motor-speed_slow.svg +1 -0
  205. package/media/icons/wedo_when-distance_close.svg +1 -0
  206. package/media/icons/wedo_when-tilt-backward.svg +1 -0
  207. package/media/icons/wedo_when-tilt-forward.svg +1 -0
  208. package/media/icons/wedo_when-tilt-left.svg +1 -0
  209. package/media/icons/wedo_when-tilt-right.svg +1 -0
  210. package/media/icons/wedo_when-tilt.svg +1 -0
  211. package/media/repeat.svg +18 -0
  212. package/media/rotate-left.svg +1 -0
  213. package/media/rotate-right.svg +1 -0
  214. package/media/sprites.png +0 -0
  215. package/media/status-not-ready.svg +13 -0
  216. package/media/status-ready.svg +13 -0
  217. package/media/zoom-in.svg +1 -0
  218. package/media/zoom-out.svg +1 -0
  219. package/media/zoom-reset.svg +1 -0
  220. package/msg/js/en.js +290 -0
  221. package/msg/json/en.json +285 -0
  222. package/msg/messages.js +359 -0
  223. package/msg/scratch_msgs.js +22969 -0
  224. package/package.json +60 -0
  225. package/pull_from_blockly.sh +151 -0
  226. package/renovate.json5 +15 -0
  227. package/shim/blockly_compressed_horizontal-blocks_compressed.js +1 -0
  228. package/shim/blockly_compressed_horizontal.Blockly.js +1 -0
  229. package/shim/blockly_compressed_horizontal.goog.js +1 -0
  230. package/shim/blockly_compressed_horizontal.js +1 -0
  231. package/shim/blockly_compressed_vertical-blocks_compressed.js +1 -0
  232. package/shim/blockly_compressed_vertical.Blockly.js +1 -0
  233. package/shim/blockly_compressed_vertical.goog.js +1 -0
  234. package/shim/blockly_compressed_vertical.js +1 -0
  235. package/shim/blocks_compressed_horizontal-blockly_compressed_horizontal-messages.js +1 -0
  236. package/shim/blocks_compressed_horizontal.js +1 -0
  237. package/shim/blocks_compressed_vertical-blockly_compressed_vertical-messages.js +1 -0
  238. package/shim/blocks_compressed_vertical.js +1 -0
  239. package/shim/gh-pages.js +1 -0
  240. package/shim/horizontal.js +1 -0
  241. package/shim/index.js +17 -0
  242. package/shim/vertical.js +1 -0
  243. package/universal-python.js +82 -0
@@ -0,0 +1,125 @@
1
+ /**
2
+ * @license
3
+ * Visual Blocks Editor
4
+ *
5
+ * Copyright 2017 Google Inc.
6
+ * https://developers.google.com/blockly/
7
+ *
8
+ * Licensed under the Apache License, Version 2.0 (the "License");
9
+ * you may not use this file except in compliance with the License.
10
+ * You may obtain a copy of the License at
11
+ *
12
+ * http://www.apache.org/licenses/LICENSE-2.0
13
+ *
14
+ * Unless required by applicable law or agreed to in writing, software
15
+ * distributed under the License is distributed on an "AS IS" BASIS,
16
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17
+ * See the License for the specific language governing permissions and
18
+ * limitations under the License.
19
+ */
20
+
21
+ /**
22
+ * @fileoverview Serialized label field. Behaves like a normal label but is
23
+ * always serialized to XML. It may only be edited programmatically.
24
+ * @author fenichel@google.com (Rachel Fenichel)
25
+ */
26
+ 'use strict';
27
+
28
+ goog.provide('Blockly.FieldLabelSerializable');
29
+
30
+ goog.require('Blockly.FieldLabel');
31
+
32
+
33
+ /**
34
+ * Class for a variable getter field.
35
+ * @param {string} text The initial content of the field.
36
+ * @param {string} opt_class Optional CSS class for the field's text.
37
+ * @extends {Blockly.FieldLabel}
38
+ * @constructor
39
+ *
40
+ */
41
+ Blockly.FieldLabelSerializable = function(text, opt_class) {
42
+ Blockly.FieldLabelSerializable.superClass_.constructor.call(this, text,
43
+ opt_class);
44
+ // Used in base field rendering, but we don't need it.
45
+ this.arrowWidth_ = 0;
46
+ };
47
+ goog.inherits(Blockly.FieldLabelSerializable, Blockly.FieldLabel);
48
+
49
+ /**
50
+ * Construct a FieldLabelSerializable from a JSON arg object,
51
+ * dereferencing any string table references.
52
+ * @param {!Object} options A JSON object with options (text, and class).
53
+ * @returns {!Blockly.FieldLabelSerializable} The new field instance.
54
+ * @package
55
+ * @nocollapse
56
+ */
57
+ Blockly.FieldLabelSerializable.fromJson = function(options) {
58
+ var text = Blockly.utils.replaceMessageReferences(options['text']);
59
+ return new Blockly.FieldLabelSerializable(text, options['class']);
60
+ };
61
+
62
+ /**
63
+ * Editable fields usually show some sort of UI for the user to change them.
64
+ * This field should be serialized, but only edited programmatically.
65
+ * @type {boolean}
66
+ * @public
67
+ */
68
+ Blockly.FieldLabelSerializable.prototype.EDITABLE = false;
69
+
70
+ /**
71
+ * Serializable fields are saved by the XML renderer, non-serializable fields
72
+ * are not. This field should be serialized, but only edited programmatically.
73
+ * @type {boolean}
74
+ * @public
75
+ */
76
+ Blockly.FieldLabelSerializable.prototype.SERIALIZABLE = true;
77
+
78
+ /**
79
+ * Updates the width of the field. This calls getCachedWidth which won't cache
80
+ * the approximated width on IE/Edge when `getComputedTextLength` fails. Once
81
+ * it eventually does succeed, the result will be cached.
82
+ **/
83
+ Blockly.FieldLabelSerializable.prototype.updateWidth = function() {
84
+ // Set width of the field.
85
+ // Unlike the base Field class, this doesn't add space to editable fields.
86
+ this.size_.width = Blockly.Field.getCachedWidth(this.textElement_);
87
+ };
88
+
89
+ /**
90
+ * Draws the border with the correct width.
91
+ * Saves the computed width in a property.
92
+ * @private
93
+ */
94
+ Blockly.FieldLabelSerializable.prototype.render_ = function() {
95
+ if (this.visible_ && this.textElement_) {
96
+ // Replace the text.
97
+ goog.dom.removeChildren(/** @type {!Element} */ (this.textElement_));
98
+ var textNode = document.createTextNode(this.getDisplayText_());
99
+ this.textElement_.appendChild(textNode);
100
+ this.updateWidth();
101
+
102
+ // Update text centering, based on newly calculated width.
103
+ var centerTextX = this.size_.width / 2;
104
+
105
+ // If half the text length is not at least center of
106
+ // visible field (FIELD_WIDTH), center it there instead.
107
+ var minOffset = Blockly.BlockSvg.FIELD_WIDTH / 2;
108
+ if (this.sourceBlock_.RTL) {
109
+ // X position starts at the left edge of the block, in both RTL and LTR.
110
+ // First offset by the width of the block to move to the right edge,
111
+ // and then subtract to move to the same position as LTR.
112
+ var minCenter = this.size_.width - minOffset;
113
+ centerTextX = Math.min(minCenter, centerTextX);
114
+ } else {
115
+ // (width / 2) should exceed Blockly.BlockSvg.FIELD_WIDTH / 2
116
+ // if the text is longer.
117
+ centerTextX = Math.max(minOffset, centerTextX);
118
+ }
119
+ // Apply new text element x position.
120
+ this.textElement_.setAttribute('x', centerTextX);
121
+ }
122
+ };
123
+
124
+ Blockly.Field.register(
125
+ 'field_label_serializable', Blockly.FieldLabelSerializable);
@@ -0,0 +1,566 @@
1
+ /**
2
+ * @license
3
+ * Visual Blocks Editor
4
+ *
5
+ * Copyright 2016 Massachusetts Institute of Technology
6
+ * All rights reserved.
7
+ *
8
+ * Licensed under the Apache License, Version 2.0 (the "License");
9
+ * you may not use this file except in compliance with the License.
10
+ * You may obtain a copy of the License at
11
+ *
12
+ * http://www.apache.org/licenses/LICENSE-2.0
13
+ *
14
+ * Unless required by applicable law or agreed to in writing, software
15
+ * distributed under the License is distributed on an "AS IS" BASIS,
16
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17
+ * See the License for the specific language governing permissions and
18
+ * limitations under the License.
19
+ */
20
+
21
+ /**
22
+ * @fileoverview 5x5 matrix input field.
23
+ * Displays an editable 5x5 matrix for controlling LED arrays.
24
+ * @author khanning@gmail.com (Kreg Hanning)
25
+ */
26
+ 'use strict';
27
+
28
+ goog.provide('Blockly.FieldMatrix');
29
+
30
+ goog.require('Blockly.DropDownDiv');
31
+
32
+ /**
33
+ * Class for a matrix field.
34
+ * @param {number} matrix The default matrix value represented by a 25-bit integer.
35
+ * @extends {Blockly.Field}
36
+ * @constructor
37
+ */
38
+ Blockly.FieldMatrix = function(matrix) {
39
+ Blockly.FieldMatrix.superClass_.constructor.call(this, matrix);
40
+ this.addArgType('matrix');
41
+ /**
42
+ * Array of SVGElement<rect> for matrix thumbnail image on block field.
43
+ * @type {!Array<SVGElement>}
44
+ * @private
45
+ */
46
+ this.ledThumbNodes_ = [];
47
+ /**
48
+ * Array of SVGElement<rect> for matrix editor in dropdown menu.
49
+ * @type {!Array<SVGElement>}
50
+ * @private
51
+ */
52
+ this.ledButtons_ = [];
53
+ /**
54
+ * String for storing current matrix value.
55
+ * @type {!String]
56
+ * @private
57
+ */
58
+ this.matrix_ = '';
59
+ /**
60
+ * SVGElement for LED matrix in editor.
61
+ * @type {?SVGElement}
62
+ * @private
63
+ */
64
+ this.matrixStage_ = null;
65
+ /**
66
+ * SVG image for dropdown arrow.
67
+ * @type {?SVGElement}
68
+ * @private
69
+ */
70
+ this.arrow_ = null;
71
+ /**
72
+ * String indicating matrix paint style.
73
+ * value can be [null, 'fill', 'clear'].
74
+ * @type {?String}
75
+ * @private
76
+ */
77
+ this.paintStyle_ = null;
78
+ /**
79
+ * Touch event wrapper.
80
+ * Runs when the field is selected.
81
+ * @type {!Array}
82
+ * @private
83
+ */
84
+ this.mouseDownWrapper_ = null;
85
+ /**
86
+ * Touch event wrapper.
87
+ * Runs when the clear button editor button is selected.
88
+ * @type {!Array}
89
+ * @private
90
+ */
91
+ this.clearButtonWrapper_ = null;
92
+ /**
93
+ * Touch event wrapper.
94
+ * Runs when the fill button editor button is selected.
95
+ * @type {!Array}
96
+ * @private
97
+ */
98
+ this.fillButtonWrapper_ = null;
99
+ /**
100
+ * Touch event wrapper.
101
+ * Runs when the matrix editor is touched.
102
+ * @type {!Array}
103
+ * @private
104
+ */
105
+ this.matrixTouchWrapper_ = null;
106
+ /**
107
+ * Touch event wrapper.
108
+ * Runs when the matrix editor touch event moves.
109
+ * @type {!Array}
110
+ * @private
111
+ */
112
+ this.matrixMoveWrapper_ = null;
113
+ /**
114
+ * Touch event wrapper.
115
+ * Runs when the matrix editor is released.
116
+ * @type {!Array}
117
+ * @private
118
+ */
119
+ this.matrixReleaseWrapper_ = null;
120
+ };
121
+ goog.inherits(Blockly.FieldMatrix, Blockly.Field);
122
+
123
+ /**
124
+ * Construct a FieldMatrix from a JSON arg object.
125
+ * @param {!Object} options A JSON object with options (matrix).
126
+ * @returns {!Blockly.FieldMatrix} The new field instance.
127
+ * @package
128
+ * @nocollapse
129
+ */
130
+ Blockly.FieldMatrix.fromJson = function(options) {
131
+ return new Blockly.FieldMatrix(options['matrix']);
132
+ };
133
+
134
+ /**
135
+ * Fixed size of the matrix thumbnail in the input field, in px.
136
+ * @type {number}
137
+ * @const
138
+ */
139
+ Blockly.FieldMatrix.THUMBNAIL_SIZE = 26;
140
+
141
+ /**
142
+ * Fixed size of each matrix thumbnail node, in px.
143
+ * @type {number}
144
+ * @const
145
+ */
146
+ Blockly.FieldMatrix.THUMBNAIL_NODE_SIZE = 4;
147
+
148
+ /**
149
+ * Fixed size of each matrix thumbnail node, in px.
150
+ * @type {number}
151
+ * @const
152
+ */
153
+ Blockly.FieldMatrix.THUMBNAIL_NODE_PAD = 1;
154
+
155
+ /**
156
+ * Fixed size of arrow icon in drop down menu, in px.
157
+ * @type {number}
158
+ * @const
159
+ */
160
+ Blockly.FieldMatrix.ARROW_SIZE = 12;
161
+
162
+ /**
163
+ * Fixed size of each button inside the 5x5 matrix, in px.
164
+ * @type {number}
165
+ * @const
166
+ */
167
+ Blockly.FieldMatrix.MATRIX_NODE_SIZE = 18;
168
+
169
+ /**
170
+ * Fixed corner radius for 5x5 matrix buttons, in px.
171
+ * @type {number}
172
+ * @const
173
+ */
174
+ Blockly.FieldMatrix.MATRIX_NODE_RADIUS = 4;
175
+
176
+ /**
177
+ * Fixed padding for 5x5 matrix buttons, in px.
178
+ * @type {number}
179
+ * @const
180
+ */
181
+ Blockly.FieldMatrix.MATRIX_NODE_PAD = 5;
182
+
183
+ /**
184
+ * String with 25 '0' chars.
185
+ * Used for clearing a matrix or filling an LED node array.
186
+ * @type {string}
187
+ * @const
188
+ */
189
+ Blockly.FieldMatrix.ZEROS = '0000000000000000000000000';
190
+
191
+ /**
192
+ * String with 25 '1' chars.
193
+ * Used for filling a matrix.
194
+ * @type {string}
195
+ * @const
196
+ */
197
+ Blockly.FieldMatrix.ONES = '1111111111111111111111111';
198
+
199
+ /**
200
+ * Called when the field is placed on a block.
201
+ * @param {Block} block The owning block.
202
+ */
203
+ Blockly.FieldMatrix.prototype.init = function() {
204
+ if (this.fieldGroup_) {
205
+ // Matrix menu has already been initialized once.
206
+ return;
207
+ }
208
+
209
+ // Build the DOM.
210
+ this.fieldGroup_ = Blockly.utils.createSvgElement('g', {}, null);
211
+ this.size_.width = Blockly.FieldMatrix.THUMBNAIL_SIZE +
212
+ Blockly.FieldMatrix.ARROW_SIZE + (Blockly.BlockSvg.DROPDOWN_ARROW_PADDING * 1.5);
213
+
214
+ this.sourceBlock_.getSvgRoot().appendChild(this.fieldGroup_);
215
+
216
+ var thumbX = Blockly.BlockSvg.DROPDOWN_ARROW_PADDING / 2;
217
+ var thumbY = (this.size_.height - Blockly.FieldMatrix.THUMBNAIL_SIZE) / 2;
218
+ var thumbnail = Blockly.utils.createSvgElement('g', {
219
+ 'transform': 'translate(' + thumbX + ', ' + thumbY + ')',
220
+ 'pointer-events': 'bounding-box', 'cursor': 'pointer'
221
+ }, this.fieldGroup_);
222
+ this.ledThumbNodes_ = [];
223
+ var nodeSize = Blockly.FieldMatrix.THUMBNAIL_NODE_SIZE;
224
+ var nodePad = Blockly.FieldMatrix.THUMBNAIL_NODE_PAD;
225
+ for (var i = 0; i < 5; i++) {
226
+ for (var n = 0; n < 5; n++) {
227
+ var attr = {
228
+ 'x': ((nodeSize + nodePad) * n) + nodePad,
229
+ 'y': ((nodeSize + nodePad) * i) + nodePad,
230
+ 'width': nodeSize, 'height': nodeSize,
231
+ 'rx': nodePad, 'ry': nodePad
232
+ };
233
+ this.ledThumbNodes_.push(
234
+ Blockly.utils.createSvgElement('rect', attr, thumbnail)
235
+ );
236
+ }
237
+ thumbnail.style.cursor = 'default';
238
+ this.updateMatrix_();
239
+ }
240
+
241
+ if (!this.arrow_) {
242
+ var arrowX = Blockly.FieldMatrix.THUMBNAIL_SIZE +
243
+ Blockly.BlockSvg.DROPDOWN_ARROW_PADDING * 1.5;
244
+ var arrowY = (this.size_.height - Blockly.FieldMatrix.ARROW_SIZE) / 2;
245
+ this.arrow_ = Blockly.utils.createSvgElement('image', {
246
+ 'height': Blockly.FieldMatrix.ARROW_SIZE + 'px',
247
+ 'width': Blockly.FieldMatrix.ARROW_SIZE + 'px',
248
+ 'transform': 'translate(' + arrowX + ', ' + arrowY + ')'
249
+ }, this.fieldGroup_);
250
+ this.arrow_.setAttributeNS('http://www.w3.org/1999/xlink',
251
+ 'xlink:href', Blockly.mainWorkspace.options.pathToMedia +
252
+ 'dropdown-arrow.svg');
253
+ this.arrow_.style.cursor = 'default';
254
+ }
255
+
256
+ this.mouseDownWrapper_ = Blockly.bindEventWithChecks_(
257
+ this.getClickTarget_(), 'mousedown', this, this.onMouseDown_);
258
+ };
259
+
260
+ /**
261
+ * Set the value for this matrix menu.
262
+ * @param {string} matrix The new matrix value represented by a 25-bit integer.
263
+ * @override
264
+ */
265
+ Blockly.FieldMatrix.prototype.setValue = function(matrix) {
266
+ if (!matrix || matrix === this.matrix_) {
267
+ return; // No change
268
+ }
269
+ if (this.sourceBlock_ && Blockly.Events.isEnabled()) {
270
+ Blockly.Events.fire(new Blockly.Events.Change(
271
+ this.sourceBlock_, 'field', this.name, this.matrix_, matrix));
272
+ }
273
+ matrix = matrix + Blockly.FieldMatrix.ZEROS.substr(0, 25 - matrix.length);
274
+ this.matrix_ = matrix;
275
+ this.updateMatrix_();
276
+ };
277
+
278
+ /**
279
+ * Get the value from this matrix menu.
280
+ * @return {string} Current matrix value.
281
+ */
282
+ Blockly.FieldMatrix.prototype.getValue = function() {
283
+ return String(this.matrix_);
284
+ };
285
+
286
+ /**
287
+ * Show the drop-down menu for editing this field.
288
+ * @private
289
+ */
290
+ Blockly.FieldMatrix.prototype.showEditor_ = function() {
291
+ // If there is an existing drop-down someone else owns, hide it immediately and clear it.
292
+ Blockly.DropDownDiv.hideWithoutAnimation();
293
+ Blockly.DropDownDiv.clearContent();
294
+ var div = Blockly.DropDownDiv.getContentDiv();
295
+ // Build the SVG DOM.
296
+ var matrixSize = (Blockly.FieldMatrix.MATRIX_NODE_SIZE * 5) +
297
+ (Blockly.FieldMatrix.MATRIX_NODE_PAD * 6);
298
+ this.matrixStage_ = Blockly.utils.createSvgElement('svg', {
299
+ 'xmlns': 'http://www.w3.org/2000/svg',
300
+ 'xmlns:html': 'http://www.w3.org/1999/xhtml',
301
+ 'xmlns:xlink': 'http://www.w3.org/1999/xlink',
302
+ 'version': '1.1',
303
+ 'height': matrixSize + 'px',
304
+ 'width': matrixSize + 'px'
305
+ }, div);
306
+ // Create the 5x5 matrix
307
+ this.ledButtons_ = [];
308
+ for (var i = 0; i < 5; i++) {
309
+ for (var n = 0; n < 5; n++) {
310
+ var x = (Blockly.FieldMatrix.MATRIX_NODE_SIZE * n) +
311
+ (Blockly.FieldMatrix.MATRIX_NODE_PAD * (n + 1));
312
+ var y = (Blockly.FieldMatrix.MATRIX_NODE_SIZE * i) +
313
+ (Blockly.FieldMatrix.MATRIX_NODE_PAD * (i + 1));
314
+ var attr = {
315
+ 'x': x + 'px', 'y': y + 'px',
316
+ 'width': Blockly.FieldMatrix.MATRIX_NODE_SIZE,
317
+ 'height': Blockly.FieldMatrix.MATRIX_NODE_SIZE,
318
+ 'rx': Blockly.FieldMatrix.MATRIX_NODE_RADIUS,
319
+ 'ry': Blockly.FieldMatrix.MATRIX_NODE_RADIUS
320
+ };
321
+ var led = Blockly.utils.createSvgElement('rect', attr, this.matrixStage_);
322
+ this.matrixStage_.appendChild(led);
323
+ this.ledButtons_.push(led);
324
+ }
325
+ }
326
+ // Div for lower button menu
327
+ var buttonDiv = document.createElement('div');
328
+ // Button to clear matrix
329
+ var clearButtonDiv = document.createElement('div');
330
+ clearButtonDiv.className = 'scratchMatrixButtonDiv';
331
+ var clearButton = this.createButton_(this.sourceBlock_.colourSecondary_);
332
+ clearButtonDiv.appendChild(clearButton);
333
+ // Button to fill matrix
334
+ var fillButtonDiv = document.createElement('div');
335
+ fillButtonDiv.className = 'scratchMatrixButtonDiv';
336
+ var fillButton = this.createButton_('#FFFFFF');
337
+ fillButtonDiv.appendChild(fillButton);
338
+
339
+ buttonDiv.appendChild(clearButtonDiv);
340
+ buttonDiv.appendChild(fillButtonDiv);
341
+ div.appendChild(buttonDiv);
342
+
343
+ Blockly.DropDownDiv.setColour(this.sourceBlock_.getColour(),
344
+ this.sourceBlock_.getColourTertiary());
345
+ Blockly.DropDownDiv.setCategory(this.sourceBlock_.getCategory());
346
+ Blockly.DropDownDiv.showPositionedByBlock(this, this.sourceBlock_);
347
+
348
+ this.matrixTouchWrapper_ =
349
+ Blockly.bindEvent_(this.matrixStage_, 'mousedown', this, this.onMouseDown);
350
+ this.clearButtonWrapper_ =
351
+ Blockly.bindEvent_(clearButton, 'click', this, this.clearMatrix_);
352
+ this.fillButtonWrapper_ =
353
+ Blockly.bindEvent_(fillButton, 'click', this, this.fillMatrix_);
354
+
355
+ // Update the matrix for the current value
356
+ this.updateMatrix_();
357
+
358
+ };
359
+
360
+ this.nodeCallback_ = function(e, num) {
361
+ console.log(num);
362
+ };
363
+
364
+ /**
365
+ * Make an svg object that resembles a 3x3 matrix to be used as a button.
366
+ * @param {string} fill The color to fill the matrix nodes.
367
+ * @return {SvgElement} The button svg element.
368
+ */
369
+ Blockly.FieldMatrix.prototype.createButton_ = function(fill) {
370
+ var button = Blockly.utils.createSvgElement('svg', {
371
+ 'xmlns': 'http://www.w3.org/2000/svg',
372
+ 'xmlns:html': 'http://www.w3.org/1999/xhtml',
373
+ 'xmlns:xlink': 'http://www.w3.org/1999/xlink',
374
+ 'version': '1.1',
375
+ 'height': Blockly.FieldMatrix.MATRIX_NODE_SIZE + 'px',
376
+ 'width': Blockly.FieldMatrix.MATRIX_NODE_SIZE + 'px'
377
+ });
378
+ var nodeSize = Blockly.FieldMatrix.MATRIX_NODE_SIZE / 4;
379
+ var nodePad = Blockly.FieldMatrix.MATRIX_NODE_SIZE / 16;
380
+ for (var i = 0; i < 3; i++) {
381
+ for (var n = 0; n < 3; n++) {
382
+ Blockly.utils.createSvgElement('rect', {
383
+ 'x': ((nodeSize + nodePad) * n) + nodePad,
384
+ 'y': ((nodeSize + nodePad) * i) + nodePad,
385
+ 'width': nodeSize, 'height': nodeSize,
386
+ 'rx': nodePad, 'ry': nodePad,
387
+ 'fill': fill
388
+ }, button);
389
+ }
390
+ }
391
+ return button;
392
+ };
393
+
394
+ /**
395
+ * Redraw the matrix with the current value.
396
+ * @private
397
+ */
398
+ Blockly.FieldMatrix.prototype.updateMatrix_ = function() {
399
+ for (var i = 0; i < this.matrix_.length; i++) {
400
+ if (this.matrix_[i] === '0') {
401
+ this.fillMatrixNode_(this.ledButtons_, i, this.sourceBlock_.colourSecondary_);
402
+ this.fillMatrixNode_(this.ledThumbNodes_, i, this.sourceBlock_.colour_);
403
+ } else {
404
+ this.fillMatrixNode_(this.ledButtons_, i, '#FFFFFF');
405
+ this.fillMatrixNode_(this.ledThumbNodes_, i, '#FFFFFF');
406
+ }
407
+ }
408
+ };
409
+
410
+ /**
411
+ * Clear the matrix.
412
+ * @param {!Event} e Mouse event.
413
+ */
414
+ Blockly.FieldMatrix.prototype.clearMatrix_ = function(e) {
415
+ if (e.button != 0) return;
416
+ this.setValue(Blockly.FieldMatrix.ZEROS);
417
+ };
418
+
419
+ /**
420
+ * Fill the matrix.
421
+ * @param {!Event} e Mouse event.
422
+ */
423
+ Blockly.FieldMatrix.prototype.fillMatrix_ = function(e) {
424
+ if (e.button != 0) return;
425
+ this.setValue(Blockly.FieldMatrix.ONES);
426
+ };
427
+
428
+ /**
429
+ * Fill matrix node with specified colour.
430
+ * @param {!Array<SVGElement>} node The array of matrix nodes.
431
+ * @param {!number} index The index of the matrix node.
432
+ * @param {!string} fill The fill colour in '#rrggbb' format.
433
+ */
434
+ Blockly.FieldMatrix.prototype.fillMatrixNode_ = function(node, index, fill) {
435
+ if (!node || !node[index] || !fill) return;
436
+ node[index].setAttribute('fill', fill);
437
+ };
438
+
439
+ Blockly.FieldMatrix.prototype.setLEDNode_ = function(led, state) {
440
+ if (led < 0 || led > 24) return;
441
+ var matrix = this.matrix_.substr(0, led) + state + this.matrix_.substr(led + 1);
442
+ this.setValue(matrix);
443
+ };
444
+
445
+ Blockly.FieldMatrix.prototype.fillLEDNode_ = function(led) {
446
+ if (led < 0 || led > 24) return;
447
+ this.setLEDNode_(led, '1');
448
+ };
449
+
450
+ Blockly.FieldMatrix.prototype.clearLEDNode_ = function(led) {
451
+ if (led < 0 || led > 24) return;
452
+ this.setLEDNode_(led, '0');
453
+ };
454
+
455
+ Blockly.FieldMatrix.prototype.toggleLEDNode_ = function(led) {
456
+ if (led < 0 || led > 24) return;
457
+ if (this.matrix_.charAt(led) === '0') {
458
+ this.setLEDNode_(led, '1');
459
+ } else {
460
+ this.setLEDNode_(led, '0');
461
+ }
462
+ };
463
+
464
+ /**
465
+ * Toggle matrix nodes on and off.
466
+ * @param {!Event} e Mouse event.
467
+ */
468
+ Blockly.FieldMatrix.prototype.onMouseDown = function(e) {
469
+ this.matrixMoveWrapper_ =
470
+ Blockly.bindEvent_(document.body, 'mousemove', this, this.onMouseMove);
471
+ this.matrixReleaseWrapper_ =
472
+ Blockly.bindEvent_(document.body, 'mouseup', this, this.onMouseUp);
473
+ var ledHit = this.checkForLED_(e);
474
+ if (ledHit > -1) {
475
+ if (this.matrix_.charAt(ledHit) === '0') {
476
+ this.paintStyle_ = 'fill';
477
+ } else {
478
+ this.paintStyle_ = 'clear';
479
+ }
480
+ this.toggleLEDNode_(ledHit);
481
+ this.updateMatrix_();
482
+ } else {
483
+ this.paintStyle_ = null;
484
+ }
485
+ };
486
+
487
+ /**
488
+ * Unbind mouse move event and clear the paint style.
489
+ * @param {!Event} e Mouse move event.
490
+ */
491
+ Blockly.FieldMatrix.prototype.onMouseUp = function() {
492
+ Blockly.unbindEvent_(this.matrixMoveWrapper_);
493
+ Blockly.unbindEvent_(this.matrixReleaseWrapper_);
494
+ this.paintStyle_ = null;
495
+ };
496
+
497
+ /**
498
+ * Toggle matrix nodes on and off by dragging mouse.
499
+ * @param {!Event} e Mouse move event.
500
+ */
501
+ Blockly.FieldMatrix.prototype.onMouseMove = function(e) {
502
+ e.preventDefault();
503
+ if (this.paintStyle_) {
504
+ var led = this.checkForLED_(e);
505
+ if (led < 0) return;
506
+ if (this.paintStyle_ === 'clear') {
507
+ this.clearLEDNode_(led);
508
+ } else if (this.paintStyle_ === 'fill') {
509
+ this.fillLEDNode_(led);
510
+ }
511
+ }
512
+ };
513
+
514
+ /**
515
+ * Check if mouse coordinates collide with a matrix node.
516
+ * @param {!Event} e Mouse move event.
517
+ * @return {number} The matching matrix node or -1 for none.
518
+ */
519
+ Blockly.FieldMatrix.prototype.checkForLED_ = function(e) {
520
+ var bBox = this.matrixStage_.getBoundingClientRect();
521
+ var nodeSize = Blockly.FieldMatrix.MATRIX_NODE_SIZE;
522
+ var nodePad = Blockly.FieldMatrix.MATRIX_NODE_PAD;
523
+ var dx = e.clientX - bBox.left;
524
+ var dy = e.clientY - bBox.top;
525
+ var min = nodePad / 2;
526
+ var max = bBox.width - (nodePad / 2);
527
+ if (dx < min || dx > max || dy < min || dy > max) {
528
+ return -1;
529
+ }
530
+ var xDiv = Math.trunc((dx - nodePad / 2) / (nodeSize + nodePad));
531
+ var yDiv = Math.trunc((dy - nodePad / 2) / (nodeSize + nodePad));
532
+ return xDiv + (yDiv * nodePad);
533
+ };
534
+
535
+ /**
536
+ * Clean up this FieldMatrix, as well as the inherited Field.
537
+ * @return {!Function} Closure to call on destruction of the WidgetDiv.
538
+ * @private
539
+ */
540
+ Blockly.FieldMatrix.prototype.dispose_ = function() {
541
+ var thisField = this;
542
+ return function() {
543
+ Blockly.FieldMatrix.superClass_.dispose_.call(thisField)();
544
+ thisField.matrixStage_ = null;
545
+ if (thisField.mouseDownWrapper_) {
546
+ Blockly.unbindEvent_(thisField.mouseDownWrapper_);
547
+ }
548
+ if (thisField.matrixTouchWrapper_) {
549
+ Blockly.unbindEvent_(thisField.matrixTouchWrapper_);
550
+ }
551
+ if (thisField.matrixReleaseWrapper_) {
552
+ Blockly.unbindEvent_(thisField.matrixReleaseWrapper_);
553
+ }
554
+ if (thisField.matrixMoveWrapper_) {
555
+ Blockly.unbindEvent_(thisField.matrixMoveWrapper_);
556
+ }
557
+ if (thisField.clearButtonWrapper_) {
558
+ Blockly.unbindEvent_(thisField.clearButtonWrapper_);
559
+ }
560
+ if (thisField.fillButtonWrapper_) {
561
+ Blockly.unbindEvent_(thisField.fillButtonWrapper_);
562
+ }
563
+ };
564
+ };
565
+
566
+ Blockly.Field.register('field_matrix', Blockly.FieldMatrix);