@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,410 @@
1
+ /**
2
+ * @license
3
+ * Visual Blocks Editor
4
+ *
5
+ * Copyright 2013 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 Angle input field.
23
+ * @author fraser@google.com (Neil Fraser)
24
+ */
25
+ 'use strict';
26
+
27
+ goog.provide('Blockly.FieldAngle');
28
+
29
+ goog.require('Blockly.DropDownDiv');
30
+ goog.require('Blockly.FieldTextInput');
31
+ goog.require('goog.math');
32
+ goog.require('goog.userAgent');
33
+
34
+
35
+ /**
36
+ * Class for an editable angle field.
37
+ * @param {(string|number)=} opt_value The initial content of the field. The
38
+ * value should cast to a number, and if it does not, '0' will be used.
39
+ * @param {Function=} opt_validator An optional function that is called
40
+ * to validate any constraints on what the user entered. Takes the new
41
+ * text as an argument and returns the accepted text or null to abort
42
+ * the change.
43
+ * @extends {Blockly.FieldTextInput}
44
+ * @constructor
45
+ */
46
+ Blockly.FieldAngle = function(opt_value, opt_validator) {
47
+ // Add degree symbol: '360°' (LTR) or '°360' (RTL)
48
+ this.symbol_ = Blockly.utils.createSvgElement('tspan', {}, null);
49
+ this.symbol_.appendChild(document.createTextNode('\u00B0'));
50
+
51
+ var numRestrictor = new RegExp("[\\d]|[\\.]|[-]|[eE]");
52
+
53
+ opt_value = (opt_value && !isNaN(opt_value)) ? String(opt_value) : '0';
54
+ Blockly.FieldAngle.superClass_.constructor.call(
55
+ this, opt_value, opt_validator, numRestrictor);
56
+ this.addArgType('angle');
57
+ };
58
+ goog.inherits(Blockly.FieldAngle, Blockly.FieldTextInput);
59
+
60
+ /**
61
+ * Construct a FieldAngle from a JSON arg object.
62
+ * @param {!Object} options A JSON object with options (angle).
63
+ * @returns {!Blockly.FieldAngle} The new field instance.
64
+ * @package
65
+ * @nocollapse
66
+ */
67
+ Blockly.FieldAngle.fromJson = function(options) {
68
+ return new Blockly.FieldAngle(options['angle']);
69
+ };
70
+
71
+ /**
72
+ * Round angles to the nearest 15 degrees when using mouse.
73
+ * Set to 0 to disable rounding.
74
+ */
75
+ Blockly.FieldAngle.ROUND = 15;
76
+
77
+ /**
78
+ * Half the width of protractor image.
79
+ */
80
+ Blockly.FieldAngle.HALF = 120 / 2;
81
+
82
+ /* The following two settings work together to set the behaviour of the angle
83
+ * picker. While many combinations are possible, two modes are typical:
84
+ * Math mode.
85
+ * 0 deg is right, 90 is up. This is the style used by protractors.
86
+ * Blockly.FieldAngle.CLOCKWISE = false;
87
+ * Blockly.FieldAngle.OFFSET = 0;
88
+ * Compass mode.
89
+ * 0 deg is up, 90 is right. This is the style used by maps.
90
+ * Blockly.FieldAngle.CLOCKWISE = true;
91
+ * Blockly.FieldAngle.OFFSET = 90;
92
+ */
93
+
94
+ /**
95
+ * Angle increases clockwise (true) or counterclockwise (false).
96
+ */
97
+ Blockly.FieldAngle.CLOCKWISE = true;
98
+
99
+ /**
100
+ * Offset the location of 0 degrees (and all angles) by a constant.
101
+ * Usually either 0 (0 = right) or 90 (0 = up).
102
+ */
103
+ Blockly.FieldAngle.OFFSET = 90;
104
+
105
+ /**
106
+ * Maximum allowed angle before wrapping.
107
+ * Usually either 360 (for 0 to 359.9) or 180 (for -179.9 to 180).
108
+ */
109
+ Blockly.FieldAngle.WRAP = 180;
110
+
111
+ /**
112
+ * Radius of drag handle
113
+ */
114
+ Blockly.FieldAngle.HANDLE_RADIUS = 10;
115
+
116
+ /**
117
+ * Width of drag handle arrow
118
+ */
119
+ Blockly.FieldAngle.ARROW_WIDTH = Blockly.FieldAngle.HANDLE_RADIUS;
120
+
121
+ /**
122
+ * Half the stroke-width used for the "glow" around the drag handle, rounded up to nearest whole pixel
123
+ */
124
+
125
+ Blockly.FieldAngle.HANDLE_GLOW_WIDTH = 3;
126
+
127
+ /**
128
+ * Radius of protractor circle. Slightly smaller than protractor size since
129
+ * otherwise SVG crops off half the border at the edges.
130
+ */
131
+ Blockly.FieldAngle.RADIUS = Blockly.FieldAngle.HALF
132
+ - Blockly.FieldAngle.HANDLE_RADIUS - Blockly.FieldAngle.HANDLE_GLOW_WIDTH;
133
+
134
+ /**
135
+ * Radius of central dot circle.
136
+ */
137
+ Blockly.FieldAngle.CENTER_RADIUS = 2;
138
+
139
+ /**
140
+ * SVG path data for arrow icon.
141
+ */
142
+ Blockly.FieldAngle.ARROW_SVG_PATH_DATA =
143
+ 'M 0.0189 -1.3178' +
144
+ ' L -4.4901 -0.5663' +
145
+ ' C -4.7532 -0.5224 -4.9811 -0.2606 -4.9811 0.0156' +
146
+ ' C -4.9811 0.2836 -4.7613 0.5522 -4.4901 0.5974' +
147
+ ' L 0.0189 1.3489' +
148
+ ' L 0.0189 3.0185' +
149
+ ' C 0.0189 3.5625 0.3833 3.752 0.8327 3.4269' +
150
+ ' L 4.641 0.6721' +
151
+ ' C 5.0982 0.3414 5.0957 -0.1853 4.6527 -0.5168' +
152
+ ' L 0.821 -3.3842' +
153
+ ' C 0.3756 -3.7175 0.0189 -3.5381 0.0189 -2.9874' +
154
+ ' L 0.0189 -1.3178' +
155
+ ' Z';
156
+
157
+ /**
158
+ * Clean up this FieldAngle, as well as the inherited FieldTextInput.
159
+ * @return {!Function} Closure to call on destruction of the WidgetDiv.
160
+ * @private
161
+ */
162
+ Blockly.FieldAngle.prototype.dispose_ = function() {
163
+ var thisField = this;
164
+ return function() {
165
+ Blockly.FieldAngle.superClass_.dispose_.call(thisField)();
166
+ thisField.gauge_ = null;
167
+ if (thisField.mouseDownWrapper_) {
168
+ Blockly.unbindEvent_(thisField.mouseDownWrapper_);
169
+ }
170
+ if (thisField.mouseUpWrapper_) {
171
+ Blockly.unbindEvent_(thisField.mouseUpWrapper_);
172
+ }
173
+ if (thisField.mouseMoveWrapper_) {
174
+ Blockly.unbindEvent_(thisField.mouseMoveWrapper_);
175
+ }
176
+ };
177
+ };
178
+
179
+ /**
180
+ * Show the inline free-text editor on top of the text.
181
+ * @private
182
+ */
183
+ Blockly.FieldAngle.prototype.showEditor_ = function() {
184
+ // Mobile browsers have issues with in-line textareas (focus & keyboards).
185
+ Blockly.FieldAngle.superClass_.showEditor_.call(this, this.useTouchInteraction_);
186
+ // If there is an existing drop-down someone else owns, hide it immediately and clear it.
187
+ Blockly.DropDownDiv.hideWithoutAnimation();
188
+ Blockly.DropDownDiv.clearContent();
189
+ var div = Blockly.DropDownDiv.getContentDiv();
190
+ // Build the SVG DOM.
191
+ var parentBlock = this.sourceBlock_.parentBlock_;
192
+ var svg = Blockly.utils.createSvgElement('svg', {
193
+ 'xmlns': 'http://www.w3.org/2000/svg',
194
+ 'xmlns:html': 'http://www.w3.org/1999/xhtml',
195
+ 'xmlns:xlink': 'http://www.w3.org/1999/xlink',
196
+ 'version': '1.1',
197
+ 'height': (Blockly.FieldAngle.HALF * 2) + 'px',
198
+ 'width': (Blockly.FieldAngle.HALF * 2) + 'px'
199
+ }, div);
200
+ Blockly.utils.createSvgElement('circle', {
201
+ 'cx': Blockly.FieldAngle.HALF, 'cy': Blockly.FieldAngle.HALF,
202
+ 'r': Blockly.FieldAngle.RADIUS,
203
+ 'fill': parentBlock.getColourSecondary(),
204
+ 'stroke': parentBlock.getColourTertiary(),
205
+ 'class': 'blocklyAngleCircle'
206
+ }, svg);
207
+ this.gauge_ = Blockly.utils.createSvgElement('path',
208
+ {'class': 'blocklyAngleGauge'}, svg);
209
+ // The moving line, x2 and y2 are set in updateGraph_
210
+ this.line_ = Blockly.utils.createSvgElement('line',{
211
+ 'x1': Blockly.FieldAngle.HALF,
212
+ 'y1': Blockly.FieldAngle.HALF,
213
+ 'class': 'blocklyAngleLine'
214
+ }, svg);
215
+ // The fixed vertical line at the offset
216
+ var offsetRadians = Math.PI * Blockly.FieldAngle.OFFSET / 180;
217
+ Blockly.utils.createSvgElement('line', {
218
+ 'x1': Blockly.FieldAngle.HALF,
219
+ 'y1': Blockly.FieldAngle.HALF,
220
+ 'x2': Blockly.FieldAngle.HALF + Blockly.FieldAngle.RADIUS * Math.cos(offsetRadians),
221
+ 'y2': Blockly.FieldAngle.HALF - Blockly.FieldAngle.RADIUS * Math.sin(offsetRadians),
222
+ 'class': 'blocklyAngleLine'
223
+ }, svg);
224
+ // Draw markers around the edge.
225
+ for (var angle = 0; angle < 360; angle += 15) {
226
+ Blockly.utils.createSvgElement('line', {
227
+ 'x1': Blockly.FieldAngle.HALF + Blockly.FieldAngle.RADIUS - 13,
228
+ 'y1': Blockly.FieldAngle.HALF,
229
+ 'x2': Blockly.FieldAngle.HALF + Blockly.FieldAngle.RADIUS - 7,
230
+ 'y2': Blockly.FieldAngle.HALF,
231
+ 'class': 'blocklyAngleMarks',
232
+ 'transform': 'rotate(' + angle + ',' +
233
+ Blockly.FieldAngle.HALF + ',' + Blockly.FieldAngle.HALF + ')'
234
+ }, svg);
235
+ }
236
+ // Center point
237
+ Blockly.utils.createSvgElement('circle', {
238
+ 'cx': Blockly.FieldAngle.HALF, 'cy': Blockly.FieldAngle.HALF,
239
+ 'r': Blockly.FieldAngle.CENTER_RADIUS,
240
+ 'class': 'blocklyAngleCenterPoint'
241
+ }, svg);
242
+ // Handle group: a circle and the arrow image
243
+ this.handle_ = Blockly.utils.createSvgElement('g', {}, svg);
244
+ Blockly.utils.createSvgElement('circle', {
245
+ 'cx': 0,
246
+ 'cy': 0,
247
+ 'r': Blockly.FieldAngle.HANDLE_RADIUS,
248
+ 'class': 'blocklyAngleDragHandle'
249
+ }, this.handle_);
250
+ this.arrowSvg_ = Blockly.utils.createSvgElement('path',
251
+ {
252
+ 'width': Blockly.FieldAngle.ARROW_WIDTH,
253
+ 'height': Blockly.FieldAngle.ARROW_WIDTH,
254
+ 'x': -Blockly.FieldAngle.ARROW_WIDTH / 2,
255
+ 'y': -Blockly.FieldAngle.ARROW_WIDTH / 2,
256
+ 'class': 'blocklyAngleDragArrow',
257
+ 'fill': parentBlock.getColour(),
258
+ 'd': Blockly.FieldAngle.ARROW_SVG_PATH_DATA
259
+ },
260
+ this.handle_);
261
+
262
+ Blockly.DropDownDiv.setColour(parentBlock.getColour(), this.sourceBlock_.getColourTertiary());
263
+ Blockly.DropDownDiv.setCategory(parentBlock.getCategory());
264
+ Blockly.DropDownDiv.showPositionedByBlock(this, this.sourceBlock_);
265
+
266
+ this.mouseDownWrapper_ =
267
+ Blockly.bindEvent_(this.handle_, 'mousedown', this, this.onMouseDown);
268
+
269
+ this.updateGraph_();
270
+ };
271
+ /**
272
+ * Set the angle to match the mouse's position.
273
+ * @param {!Event} e Mouse move event.
274
+ */
275
+ Blockly.FieldAngle.prototype.onMouseDown = function() {
276
+ this.mouseMoveWrapper_ = Blockly.bindEvent_(document.body, 'mousemove', this, this.onMouseMove);
277
+ this.mouseUpWrapper_ = Blockly.bindEvent_(document.body, 'mouseup', this, this.onMouseUp);
278
+ };
279
+
280
+ /**
281
+ * Set the angle to match the mouse's position.
282
+ * @param {!Event} e Mouse move event.
283
+ */
284
+ Blockly.FieldAngle.prototype.onMouseUp = function() {
285
+ Blockly.unbindEvent_(this.mouseMoveWrapper_);
286
+ Blockly.unbindEvent_(this.mouseUpWrapper_);
287
+ };
288
+
289
+ /**
290
+ * Set the angle to match the mouse's position.
291
+ * @param {!Event} e Mouse move event.
292
+ */
293
+ Blockly.FieldAngle.prototype.onMouseMove = function(e) {
294
+ e.preventDefault();
295
+ var bBox = this.gauge_.ownerSVGElement.getBoundingClientRect();
296
+ var dx = e.clientX - bBox.left - Blockly.FieldAngle.HALF;
297
+ var dy = e.clientY - bBox.top - Blockly.FieldAngle.HALF;
298
+ var angle = Math.atan(-dy / dx);
299
+ if (isNaN(angle)) {
300
+ // This shouldn't happen, but let's not let this error propagate further.
301
+ return;
302
+ }
303
+ angle = goog.math.toDegrees(angle);
304
+ // 0: East, 90: North, 180: West, 270: South.
305
+ if (dx < 0) {
306
+ angle += 180;
307
+ } else if (dy > 0) {
308
+ angle += 360;
309
+ }
310
+ if (Blockly.FieldAngle.CLOCKWISE) {
311
+ angle = Blockly.FieldAngle.OFFSET + 360 - angle;
312
+ } else {
313
+ angle -= Blockly.FieldAngle.OFFSET;
314
+ }
315
+ if (Blockly.FieldAngle.ROUND) {
316
+ angle = Math.round(angle / Blockly.FieldAngle.ROUND) *
317
+ Blockly.FieldAngle.ROUND;
318
+ }
319
+ angle = this.callValidator(angle);
320
+ Blockly.FieldTextInput.htmlInput_.value = angle;
321
+ this.setValue(angle);
322
+ this.validate_();
323
+ this.resizeEditor_();
324
+ };
325
+
326
+ /**
327
+ * Insert a degree symbol.
328
+ * @param {?string} text New text.
329
+ */
330
+ Blockly.FieldAngle.prototype.setText = function(text) {
331
+ Blockly.FieldAngle.superClass_.setText.call(this, text);
332
+ if (!this.textElement_) {
333
+ // Not rendered yet.
334
+ return;
335
+ }
336
+ this.updateGraph_();
337
+ // Cached width is obsolete. Clear it.
338
+ this.size_.width = 0;
339
+ };
340
+
341
+ /**
342
+ * Redraw the graph with the current angle.
343
+ * @private
344
+ */
345
+ Blockly.FieldAngle.prototype.updateGraph_ = function() {
346
+ if (!this.gauge_) {
347
+ return;
348
+ }
349
+ var angleDegrees = Number(this.getText()) % 360 + Blockly.FieldAngle.OFFSET;
350
+ var angleRadians = goog.math.toRadians(angleDegrees);
351
+ var path = ['M ', Blockly.FieldAngle.HALF, ',', Blockly.FieldAngle.HALF];
352
+ var x2 = Blockly.FieldAngle.HALF;
353
+ var y2 = Blockly.FieldAngle.HALF;
354
+ if (!isNaN(angleRadians)) {
355
+ var angle1 = goog.math.toRadians(Blockly.FieldAngle.OFFSET);
356
+ var x1 = Math.cos(angle1) * Blockly.FieldAngle.RADIUS;
357
+ var y1 = Math.sin(angle1) * -Blockly.FieldAngle.RADIUS;
358
+ if (Blockly.FieldAngle.CLOCKWISE) {
359
+ angleRadians = 2 * angle1 - angleRadians;
360
+ }
361
+ x2 += Math.cos(angleRadians) * Blockly.FieldAngle.RADIUS;
362
+ y2 -= Math.sin(angleRadians) * Blockly.FieldAngle.RADIUS;
363
+ // Use large arc only if input value is greater than wrap
364
+ var largeFlag = Math.abs(angleDegrees - Blockly.FieldAngle.OFFSET) > 180 ? 1 : 0;
365
+ var sweepFlag = Number(Blockly.FieldAngle.CLOCKWISE);
366
+ if (angleDegrees < Blockly.FieldAngle.OFFSET) {
367
+ sweepFlag = 1 - sweepFlag; // Sweep opposite direction if less than the offset
368
+ }
369
+ path.push(' l ', x1, ',', y1,
370
+ ' A ', Blockly.FieldAngle.RADIUS, ',', Blockly.FieldAngle.RADIUS,
371
+ ' 0 ', largeFlag, ' ', sweepFlag, ' ', x2, ',', y2, ' z');
372
+
373
+ // Image rotation needs to be set in degrees
374
+ if (Blockly.FieldAngle.CLOCKWISE) {
375
+ var imageRotation = angleDegrees + 2 * Blockly.FieldAngle.OFFSET;
376
+ } else {
377
+ var imageRotation = -angleDegrees;
378
+ }
379
+ this.arrowSvg_.setAttribute('transform', 'rotate(' + (imageRotation) + ')');
380
+ }
381
+ this.gauge_.setAttribute('d', path.join(''));
382
+ this.line_.setAttribute('x2', x2);
383
+ this.line_.setAttribute('y2', y2);
384
+ this.handle_.setAttribute('transform', 'translate(' + x2 + ',' + y2 + ')');
385
+ };
386
+
387
+ /**
388
+ * Ensure that only an angle may be entered.
389
+ * @param {string} text The user's text.
390
+ * @return {?string} A string representing a valid angle, or null if invalid.
391
+ */
392
+ Blockly.FieldAngle.prototype.classValidator = function(text) {
393
+ if (text === null) {
394
+ return null;
395
+ }
396
+ var n = parseFloat(text || 0);
397
+ if (isNaN(n)) {
398
+ return null;
399
+ }
400
+ n = n % 360;
401
+ if (n < 0) {
402
+ n += 360;
403
+ }
404
+ if (n > Blockly.FieldAngle.WRAP) {
405
+ n -= 360;
406
+ }
407
+ return String(n);
408
+ };
409
+
410
+ Blockly.Field.register('field_angle', Blockly.FieldAngle);
@@ -0,0 +1,133 @@
1
+ /**
2
+ * @license
3
+ * Visual Blocks Editor
4
+ *
5
+ * Copyright 2012 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 Checkbox field. Checked or not checked.
23
+ * @author fraser@google.com (Neil Fraser)
24
+ */
25
+ 'use strict';
26
+
27
+ goog.provide('Blockly.FieldCheckbox');
28
+
29
+ goog.require('Blockly.Field');
30
+
31
+
32
+ /**
33
+ * Class for a checkbox field.
34
+ * @param {string} state The initial state of the field ('TRUE' or 'FALSE').
35
+ * @param {Function=} opt_validator A function that is executed when a new
36
+ * option is selected. Its sole argument is the new checkbox state. If
37
+ * it returns a value, this becomes the new checkbox state, unless the
38
+ * value is null, in which case the change is aborted.
39
+ * @extends {Blockly.Field}
40
+ * @constructor
41
+ */
42
+ Blockly.FieldCheckbox = function(state, opt_validator) {
43
+ Blockly.FieldCheckbox.superClass_.constructor.call(this, '', opt_validator);
44
+ // Set the initial state.
45
+ this.setValue(state);
46
+ this.addArgType('checkbox');
47
+ };
48
+ goog.inherits(Blockly.FieldCheckbox, Blockly.Field);
49
+
50
+ /**
51
+ * Construct a FieldCheckbox from a JSON arg object.
52
+ * @param {!Object} options A JSON object with options (checked).
53
+ * @returns {!Blockly.FieldCheckbox} The new field instance.
54
+ * @package
55
+ * @nocollapse
56
+ */
57
+ Blockly.FieldCheckbox.fromJson = function(options) {
58
+ return new Blockly.FieldCheckbox(options['checked'] ? 'TRUE' : 'FALSE');
59
+ };
60
+
61
+ /**
62
+ * Character for the checkmark.
63
+ */
64
+ Blockly.FieldCheckbox.CHECK_CHAR = '\u2713';
65
+
66
+ /**
67
+ * Mouse cursor style when over the hotspot that initiates editability.
68
+ */
69
+ Blockly.FieldCheckbox.prototype.CURSOR = 'default';
70
+
71
+ /**
72
+ * Install this checkbox on a block.
73
+ */
74
+ Blockly.FieldCheckbox.prototype.init = function() {
75
+ if (this.fieldGroup_) {
76
+ // Checkbox has already been initialized once.
77
+ return;
78
+ }
79
+ Blockly.FieldCheckbox.superClass_.init.call(this);
80
+ // The checkbox doesn't use the inherited text element.
81
+ // Instead it uses a custom checkmark element that is either visible or not.
82
+ this.checkElement_ = Blockly.utils.createSvgElement('text',
83
+ {'class': 'blocklyText blocklyCheckbox', 'x': -3, 'y': 14},
84
+ this.fieldGroup_);
85
+ var textNode = document.createTextNode(Blockly.FieldCheckbox.CHECK_CHAR);
86
+ this.checkElement_.appendChild(textNode);
87
+ this.checkElement_.style.display = this.state_ ? 'block' : 'none';
88
+ };
89
+
90
+ /**
91
+ * Return 'TRUE' if the checkbox is checked, 'FALSE' otherwise.
92
+ * @return {string} Current state.
93
+ */
94
+ Blockly.FieldCheckbox.prototype.getValue = function() {
95
+ return String(this.state_).toUpperCase();
96
+ };
97
+
98
+ /**
99
+ * Set the checkbox to be checked if newBool is 'TRUE' or true,
100
+ * unchecks otherwise.
101
+ * @param {string|boolean} newBool New state.
102
+ */
103
+ Blockly.FieldCheckbox.prototype.setValue = function(newBool) {
104
+ var newState = (typeof newBool == 'string') ?
105
+ (newBool.toUpperCase() == 'TRUE') : !!newBool;
106
+ if (this.state_ !== newState) {
107
+ if (this.sourceBlock_ && Blockly.Events.isEnabled()) {
108
+ Blockly.Events.fire(new Blockly.Events.BlockChange(
109
+ this.sourceBlock_, 'field', this.name, this.state_, newState));
110
+ }
111
+ this.state_ = newState;
112
+ if (this.checkElement_) {
113
+ this.checkElement_.style.display = newState ? 'block' : 'none';
114
+ }
115
+ }
116
+ };
117
+
118
+ /**
119
+ * Toggle the state of the checkbox.
120
+ * @private
121
+ */
122
+ Blockly.FieldCheckbox.prototype.showEditor_ = function() {
123
+ var newState = !this.state_;
124
+ if (this.sourceBlock_) {
125
+ // Call any validation function, and allow it to override.
126
+ newState = this.callValidator(newState);
127
+ }
128
+ if (newState !== null) {
129
+ this.setValue(String(newState).toUpperCase());
130
+ }
131
+ };
132
+
133
+ Blockly.Field.register('field_checkbox', Blockly.FieldCheckbox);