@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,803 @@
1
+ /**
2
+ * @license
3
+ * Visual Blocks Editor
4
+ *
5
+ * Copyright 2011 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 Toolbox from whence to create blocks.
23
+ * @author fraser@google.com (Neil Fraser)
24
+ */
25
+ 'use strict';
26
+
27
+ goog.provide('Blockly.Toolbox');
28
+
29
+ goog.require('Blockly.Events.Ui');
30
+ goog.require('Blockly.HorizontalFlyout');
31
+ goog.require('Blockly.Touch');
32
+ goog.require('Blockly.VerticalFlyout');
33
+ goog.require('goog.dom');
34
+ goog.require('goog.dom.TagName');
35
+ goog.require('goog.events');
36
+ goog.require('goog.events.BrowserFeature');
37
+ goog.require('goog.html.SafeHtml');
38
+ goog.require('goog.html.SafeStyle');
39
+ goog.require('goog.math.Rect');
40
+ goog.require('goog.style');
41
+ goog.require('goog.ui.tree.TreeControl');
42
+ goog.require('goog.ui.tree.TreeNode');
43
+ goog.require('goog.string');
44
+
45
+
46
+ /**
47
+ * Class for a Toolbox.
48
+ * Creates the toolbox's DOM.
49
+ * @param {!Blockly.Workspace} workspace The workspace in which to create new
50
+ * blocks.
51
+ * @constructor
52
+ */
53
+ Blockly.Toolbox = function(workspace) {
54
+ /**
55
+ * @type {!Blockly.Workspace}
56
+ * @private
57
+ */
58
+ this.workspace_ = workspace;
59
+
60
+ /**
61
+ * Whether toolbox categories should be represented by icons instead of text.
62
+ * @type {boolean}
63
+ * @private
64
+ */
65
+ this.iconic_ = false;
66
+
67
+ /**
68
+ * Is RTL vs LTR.
69
+ * @type {boolean}
70
+ */
71
+ this.RTL = workspace.options.RTL;
72
+
73
+ /**
74
+ * Whether the toolbox should be laid out horizontally.
75
+ * @type {boolean}
76
+ * @private
77
+ */
78
+ this.horizontalLayout_ = workspace.options.horizontalLayout;
79
+
80
+ /**
81
+ * Position of the toolbox and flyout relative to the workspace.
82
+ * @type {number}
83
+ */
84
+ this.toolboxPosition = workspace.options.toolboxPosition;
85
+
86
+ };
87
+
88
+ /**
89
+ * Width of the toolbox, which changes only in vertical layout.
90
+ * This is the sum of the width of the flyout (250) and the category menu (60).
91
+ * @type {number}
92
+ */
93
+ Blockly.Toolbox.prototype.width = 310;
94
+
95
+ /**
96
+ * Height of the toolbox, which changes only in horizontal layout.
97
+ * @type {number}
98
+ */
99
+ Blockly.Toolbox.prototype.height = 0;
100
+
101
+ Blockly.Toolbox.prototype.selectedItem_ = null;
102
+
103
+ /**
104
+ * Initializes the toolbox.
105
+ */
106
+ Blockly.Toolbox.prototype.init = function() {
107
+ var workspace = this.workspace_;
108
+ var svg = this.workspace_.getParentSvg();
109
+
110
+ /**
111
+ * HTML container for the Toolbox menu.
112
+ * @type {Element}
113
+ */
114
+ this.HtmlDiv =
115
+ goog.dom.createDom(goog.dom.TagName.DIV, 'blocklyToolboxDiv');
116
+ this.HtmlDiv.setAttribute('dir', workspace.RTL ? 'RTL' : 'LTR');
117
+ svg.parentNode.insertBefore(this.HtmlDiv, svg);
118
+
119
+ // Clicking on toolbox closes popups.
120
+ Blockly.bindEventWithChecks_(this.HtmlDiv, 'mousedown', this,
121
+ function(e) {
122
+ // Cancel any gestures in progress.
123
+ this.workspace_.cancelCurrentGesture();
124
+ if (Blockly.utils.isRightButton(e) || e.target == this.HtmlDiv) {
125
+ // Close flyout.
126
+ Blockly.hideChaff(false);
127
+ } else {
128
+ // Just close popups.
129
+ Blockly.hideChaff(true);
130
+ }
131
+ Blockly.Touch.clearTouchIdentifier(); // Don't block future drags.
132
+ }, /*opt_noCaptureIdentifier*/ false, /*opt_noPreventDefault*/ true);
133
+
134
+ this.createFlyout_();
135
+ this.categoryMenu_ = new Blockly.Toolbox.CategoryMenu(this, this.HtmlDiv);
136
+ this.populate_(workspace.options.languageTree);
137
+ this.position();
138
+ };
139
+
140
+ /**
141
+ * Dispose of this toolbox.
142
+ */
143
+ Blockly.Toolbox.prototype.dispose = function() {
144
+ this.flyout_.dispose();
145
+ this.categoryMenu_.dispose();
146
+ this.categoryMenu_ = null;
147
+ goog.dom.removeNode(this.HtmlDiv);
148
+ this.workspace_ = null;
149
+ this.lastCategory_ = null;
150
+ };
151
+
152
+ /**
153
+ * Create and configure a flyout based on the main workspace's options.
154
+ * @private
155
+ */
156
+ Blockly.Toolbox.prototype.createFlyout_ = function() {
157
+ var workspace = this.workspace_;
158
+
159
+ var options = {
160
+ disabledPatternId: workspace.options.disabledPatternId,
161
+ parentWorkspace: workspace,
162
+ RTL: workspace.RTL,
163
+ oneBasedIndex: workspace.options.oneBasedIndex,
164
+ horizontalLayout: workspace.horizontalLayout,
165
+ toolboxPosition: workspace.options.toolboxPosition,
166
+ stackGlowFilterId: workspace.options.stackGlowFilterId,
167
+ pathToMedia: workspace.options.pathToMedia
168
+ };
169
+
170
+ if (workspace.horizontalLayout) {
171
+ this.flyout_ = new Blockly.HorizontalFlyout(options);
172
+ } else {
173
+ this.flyout_ = new Blockly.VerticalFlyout(options);
174
+ }
175
+ this.flyout_.setParentToolbox(this);
176
+
177
+ goog.dom.insertSiblingAfter(
178
+ this.flyout_.createDom('svg'), this.workspace_.getParentSvg());
179
+ this.flyout_.init(workspace);
180
+ };
181
+
182
+ /**
183
+ * Fill the toolbox with categories and blocks.
184
+ * @param {!Node} newTree DOM tree of blocks.
185
+ * @private
186
+ */
187
+ Blockly.Toolbox.prototype.populate_ = function(newTree) {
188
+ this.categoryMenu_.populate(newTree);
189
+ this.showAll_();
190
+ this.setSelectedItem(this.categoryMenu_.categories_[0], false);
191
+ };
192
+
193
+ /**
194
+ * Show all blocks for all categories in the flyout
195
+ * @private
196
+ */
197
+ Blockly.Toolbox.prototype.showAll_ = function() {
198
+ var allContents = [];
199
+ for (var i = 0; i < this.categoryMenu_.categories_.length; i++) {
200
+ var category = this.categoryMenu_.categories_[i];
201
+
202
+ // create a label node to go at the top of the category
203
+ var labelString = '<xml><label text="' + goog.string.htmlEscape(category.name_) + '"' +
204
+ ' id="' + goog.string.htmlEscape(category.id_) + '"' +
205
+ ' category-label="true"' +
206
+ ' showStatusButton="' + goog.string.htmlEscape(category.showStatusButton_) + '"' +
207
+ ' web-class="categoryLabel">' +
208
+ '</label></xml>';
209
+ var labelXML = Blockly.Xml.textToDom(labelString);
210
+
211
+ allContents.push(labelXML.firstChild);
212
+
213
+ allContents = allContents.concat(category.getContents());
214
+ }
215
+ this.flyout_.show(allContents);
216
+ };
217
+
218
+ /**
219
+ * Get the width of the toolbox.
220
+ * @return {number} The width of the toolbox.
221
+ */
222
+ Blockly.Toolbox.prototype.getWidth = function() {
223
+ return this.width;
224
+ };
225
+
226
+ /**
227
+ * Get the height of the toolbox, not including the block menu.
228
+ * @return {number} The height of the toolbox.
229
+ */
230
+ Blockly.Toolbox.prototype.getHeight = function() {
231
+ return this.categoryMenu_ ? this.categoryMenu_.getHeight() : 0;
232
+ };
233
+
234
+ /**
235
+ * Move the toolbox to the edge.
236
+ */
237
+ Blockly.Toolbox.prototype.position = function() {
238
+ var treeDiv = this.HtmlDiv;
239
+ if (!treeDiv) {
240
+ // Not initialized yet.
241
+ return;
242
+ }
243
+ var svg = this.workspace_.getParentSvg();
244
+ var svgSize = Blockly.svgSize(svg);
245
+ if (this.horizontalLayout_) {
246
+ treeDiv.style.left = '0';
247
+ treeDiv.style.height = 'auto';
248
+ treeDiv.style.width = svgSize.width + 'px';
249
+ this.height = treeDiv.offsetHeight;
250
+ if (this.toolboxPosition == Blockly.TOOLBOX_AT_TOP) { // Top
251
+ treeDiv.style.top = '0';
252
+ } else { // Bottom
253
+ treeDiv.style.bottom = '0';
254
+ }
255
+ } else {
256
+ if (this.toolboxPosition == Blockly.TOOLBOX_AT_RIGHT) { // Right
257
+ treeDiv.style.right = '0';
258
+ } else { // Left
259
+ treeDiv.style.left = '0';
260
+ }
261
+ treeDiv.style.height = '100%';
262
+ }
263
+ this.flyout_.position();
264
+ };
265
+
266
+ /**
267
+ * Unhighlight any previously specified option.
268
+ */
269
+ Blockly.Toolbox.prototype.clearSelection = function() {
270
+ this.setSelectedItem(null);
271
+ };
272
+
273
+ /**
274
+ * Adds a style on the toolbox. Usually used to change the cursor.
275
+ * @param {string} style The name of the class to add.
276
+ * @package
277
+ */
278
+ Blockly.Toolbox.prototype.addStyle = function(style) {
279
+ Blockly.utils.addClass(/** @type {!Element} */ (this.HtmlDiv), style);
280
+ };
281
+
282
+ /**
283
+ * Removes a style from the toolbox. Usually used to change the cursor.
284
+ * @param {string} style The name of the class to remove.
285
+ * @package
286
+ */
287
+ Blockly.Toolbox.prototype.removeStyle = function(style) {
288
+ Blockly.utils.removeClass(/** @type {!Element} */ (this.HtmlDiv), style);
289
+ };
290
+
291
+ /**
292
+ * Return the deletion rectangle for this toolbox.
293
+ * @return {goog.math.Rect} Rectangle in which to delete.
294
+ */
295
+ Blockly.Toolbox.prototype.getClientRect = function() {
296
+ if (!this.HtmlDiv) {
297
+ return null;
298
+ }
299
+
300
+ // If not an auto closing flyout, always use the (larger) flyout client rect
301
+ if (!this.flyout_.autoClose) {
302
+ return this.flyout_.getClientRect();
303
+ }
304
+
305
+ // BIG_NUM is offscreen padding so that blocks dragged beyond the toolbox
306
+ // area are still deleted. Must be smaller than Infinity, but larger than
307
+ // the largest screen size.
308
+ var BIG_NUM = 10000000;
309
+ var toolboxRect = this.HtmlDiv.getBoundingClientRect();
310
+
311
+ var x = toolboxRect.left;
312
+ var y = toolboxRect.top;
313
+ var width = toolboxRect.width;
314
+ var height = toolboxRect.height;
315
+
316
+ // Assumes that the toolbox is on the SVG edge. If this changes
317
+ // (e.g. toolboxes in mutators) then this code will need to be more complex.
318
+ if (this.toolboxPosition == Blockly.TOOLBOX_AT_LEFT) {
319
+ return new goog.math.Rect(-BIG_NUM, -BIG_NUM, BIG_NUM + x + width,
320
+ 2 * BIG_NUM);
321
+ } else if (this.toolboxPosition == Blockly.TOOLBOX_AT_RIGHT) {
322
+ return new goog.math.Rect(toolboxRect.right - width, -BIG_NUM, BIG_NUM + width, 2 * BIG_NUM);
323
+ } else if (this.toolboxPosition == Blockly.TOOLBOX_AT_TOP) {
324
+ return new goog.math.Rect(-BIG_NUM, -BIG_NUM, 2 * BIG_NUM,
325
+ BIG_NUM + y + height);
326
+ } else { // Bottom
327
+ return new goog.math.Rect(0, y, 2 * BIG_NUM, BIG_NUM);
328
+ }
329
+ };
330
+
331
+ /**
332
+ * Update the flyout's contents without closing it. Should be used in response
333
+ * to a change in one of the dynamic categories, such as variables or
334
+ * procedures.
335
+ */
336
+ Blockly.Toolbox.prototype.refreshSelection = function() {
337
+ this.showAll_();
338
+ };
339
+
340
+ /**
341
+ * @return {Blockly.Toolbox.Category} the currently selected category.
342
+ */
343
+ Blockly.Toolbox.prototype.getSelectedItem = function() {
344
+ return this.selectedItem_;
345
+ };
346
+
347
+ /**
348
+ * @return {string} The name of the currently selected category.
349
+ */
350
+ Blockly.Toolbox.prototype.getSelectedCategoryName = function() {
351
+ return this.selectedItem_.name_;
352
+ };
353
+
354
+ /**
355
+ * @return {string} The id of the currently selected category.
356
+ * @public
357
+ */
358
+ Blockly.Toolbox.prototype.getSelectedCategoryId = function() {
359
+ return this.selectedItem_.id_;
360
+ };
361
+
362
+ /**
363
+ * @return {number} The distance flyout is scrolled below the top of the currently
364
+ * selected category.
365
+ */
366
+ Blockly.Toolbox.prototype.getCategoryScrollOffset = function() {
367
+ var categoryPos = this.getCategoryPositionById(this.getSelectedCategoryId());
368
+ return this.flyout_.getScrollPos() - categoryPos;
369
+ };
370
+
371
+ /**
372
+ * Get the position of a category by name.
373
+ * @param {string} name The name of the category.
374
+ * @return {number} The position of the category.
375
+ */
376
+ Blockly.Toolbox.prototype.getCategoryPositionByName = function(name) {
377
+ var scrollPositions = this.flyout_.categoryScrollPositions;
378
+ for (var i = 0; i < scrollPositions.length; i++) {
379
+ if (name === scrollPositions[i].categoryName) {
380
+ return scrollPositions[i].position;
381
+ }
382
+ }
383
+ };
384
+
385
+ /**
386
+ * Get the position of a category by id.
387
+ * @param {string} id The id of the category.
388
+ * @return {number} The position of the category.
389
+ * @public
390
+ */
391
+ Blockly.Toolbox.prototype.getCategoryPositionById = function(id) {
392
+ var scrollPositions = this.flyout_.categoryScrollPositions;
393
+ for (var i = 0; i < scrollPositions.length; i++) {
394
+ if (id === scrollPositions[i].categoryId) {
395
+ return scrollPositions[i].position;
396
+ }
397
+ }
398
+ };
399
+
400
+ /**
401
+ * Get the length of a category by name.
402
+ * @param {string} name The name of the category.
403
+ * @return {number} The length of the category.
404
+ */
405
+ Blockly.Toolbox.prototype.getCategoryLengthByName = function(name) {
406
+ var scrollPositions = this.flyout_.categoryScrollPositions;
407
+ for (var i = 0; i < scrollPositions.length; i++) {
408
+ if (name === scrollPositions[i].categoryName) {
409
+ return scrollPositions[i].length;
410
+ }
411
+ }
412
+ };
413
+
414
+ /**
415
+ * Get the length of a category by id.
416
+ * @param {string} id The id of the category.
417
+ * @return {number} The length of the category.
418
+ * @public
419
+ */
420
+ Blockly.Toolbox.prototype.getCategoryLengthById = function(id) {
421
+ var scrollPositions = this.flyout_.categoryScrollPositions;
422
+ for (var i = 0; i < scrollPositions.length; i++) {
423
+ if (id === scrollPositions[i].categoryId) {
424
+ return scrollPositions[i].length;
425
+ }
426
+ }
427
+ };
428
+
429
+ /**
430
+ * Set the scroll position of the flyout.
431
+ * @param {number} pos The position to set.
432
+ */
433
+ Blockly.Toolbox.prototype.setFlyoutScrollPos = function(pos) {
434
+ this.flyout_.setScrollPos(pos);
435
+ };
436
+
437
+
438
+ /**
439
+ * Set the currently selected category.
440
+ * @param {Blockly.Toolbox.Category} item The category to select.
441
+ * @param {boolean=} opt_shouldScroll Whether to scroll to the selected category. Defaults to true.
442
+ */
443
+ Blockly.Toolbox.prototype.setSelectedItem = function(item, opt_shouldScroll) {
444
+ if (typeof opt_shouldScroll === 'undefined') {
445
+ opt_shouldScroll = true;
446
+ }
447
+ if (this.selectedItem_) {
448
+ // They selected a different category but one was already open. Close it.
449
+ this.selectedItem_.setSelected(false);
450
+ }
451
+ this.selectedItem_ = item;
452
+ if (this.selectedItem_ != null) {
453
+ this.selectedItem_.setSelected(true);
454
+ // Scroll flyout to the top of the selected category
455
+ var categoryId = item.id_;
456
+ if (opt_shouldScroll) {
457
+ this.scrollToCategoryById(categoryId);
458
+ }
459
+ }
460
+ };
461
+
462
+ /**
463
+ * Select and scroll to a category by name.
464
+ * @param {string} name The name of the category to select and scroll to.
465
+ */
466
+ Blockly.Toolbox.prototype.setSelectedCategoryByName = function(name) {
467
+ this.selectCategoryByName(name);
468
+ this.scrollToCategoryByName(name);
469
+ };
470
+
471
+ /**
472
+ * Select and scroll to a category by id.
473
+ * @param {string} id The id of the category to select and scroll to.
474
+ * @public
475
+ */
476
+ Blockly.Toolbox.prototype.setSelectedCategoryById = function(id) {
477
+ this.selectCategoryById(id);
478
+ this.scrollToCategoryById(id);
479
+ };
480
+
481
+ /**
482
+ * Scroll to a category by name.
483
+ * @param {string} name The name of the category to scroll to.
484
+ * @package
485
+ */
486
+ Blockly.Toolbox.prototype.scrollToCategoryByName = function(name) {
487
+ var scrollPositions = this.flyout_.categoryScrollPositions;
488
+ for (var i = 0; i < scrollPositions.length; i++) {
489
+ if (name === scrollPositions[i].categoryName) {
490
+ this.flyout_.setVisible(true);
491
+ this.flyout_.scrollTo(scrollPositions[i].position);
492
+ return;
493
+ }
494
+ }
495
+ };
496
+
497
+ /**
498
+ * Scroll to a category by id.
499
+ * @param {string} id The id of the category to scroll to.
500
+ * @public
501
+ */
502
+ Blockly.Toolbox.prototype.scrollToCategoryById = function(id) {
503
+ var scrollPositions = this.flyout_.categoryScrollPositions;
504
+ for (var i = 0; i < scrollPositions.length; i++) {
505
+ if (id === scrollPositions[i].categoryId) {
506
+ this.flyout_.setVisible(true);
507
+ this.flyout_.scrollTo(scrollPositions[i].position);
508
+ return;
509
+ }
510
+ }
511
+ };
512
+
513
+ /**
514
+ * Get a category by its index.
515
+ * @param {number} index The index of the category.
516
+ * @return {Blockly.Toolbox.Category} the category, or null if there are no categories.
517
+ * @package
518
+ */
519
+ Blockly.Toolbox.prototype.getCategoryByIndex = function(index) {
520
+ if (!this.categoryMenu_.categories_) return null;
521
+ return this.categoryMenu_.categories_[index];
522
+ };
523
+
524
+ /**
525
+ * Select a category by name.
526
+ * @param {string} name The name of the category to select.
527
+ * @package
528
+ */
529
+ Blockly.Toolbox.prototype.selectCategoryByName = function(name) {
530
+ for (var i = 0; i < this.categoryMenu_.categories_.length; i++) {
531
+ var category = this.categoryMenu_.categories_[i];
532
+ if (name === category.name_) {
533
+ this.selectedItem_.setSelected(false);
534
+ this.selectedItem_ = category;
535
+ this.selectedItem_.setSelected(true);
536
+ }
537
+ }
538
+ };
539
+
540
+ /**
541
+ * Select a category by id.
542
+ * @param {string} id The id of the category to select.
543
+ * @package
544
+ */
545
+ Blockly.Toolbox.prototype.selectCategoryById = function(id) {
546
+ for (var i = 0; i < this.categoryMenu_.categories_.length; i++) {
547
+ var category = this.categoryMenu_.categories_[i];
548
+ if (id === category.id_) {
549
+ this.selectedItem_.setSelected(false);
550
+ this.selectedItem_ = category;
551
+ this.selectedItem_.setSelected(true);
552
+ }
553
+ }
554
+ };
555
+
556
+ /**
557
+ * Wrapper function for calling setSelectedItem from a touch handler.
558
+ * @param {Blockly.Toolbox.Category} item The category to select.
559
+ * @return {function} A function that can be passed to bindEvent.
560
+ */
561
+ Blockly.Toolbox.prototype.setSelectedItemFactory = function(item) {
562
+ var selectedItem = item;
563
+ return function() {
564
+ if (!this.workspace_.isDragging()) {
565
+ this.setSelectedItem(selectedItem);
566
+ Blockly.Touch.clearTouchIdentifier();
567
+ }
568
+ };
569
+ };
570
+
571
+ // Category menu
572
+ /**
573
+ * Class for a table of category titles that will control which category is
574
+ * displayed.
575
+ * @param {Blockly.Toolbox} parent The toolbox that owns the category menu.
576
+ * @param {Element} parentHtml The containing html div.
577
+ * @constructor
578
+ */
579
+ Blockly.Toolbox.CategoryMenu = function(parent, parentHtml) {
580
+ this.parent_ = parent;
581
+ this.height_ = 0;
582
+ this.parentHtml_ = parentHtml;
583
+ this.createDom();
584
+ this.categories_ = [];
585
+ };
586
+
587
+ /**
588
+ * @return {number} the height of the category menu.
589
+ */
590
+ Blockly.Toolbox.CategoryMenu.prototype.getHeight = function() {
591
+ return this.height_;
592
+ };
593
+
594
+ /**
595
+ * Create the DOM for the category menu.
596
+ */
597
+ Blockly.Toolbox.CategoryMenu.prototype.createDom = function() {
598
+ this.table = goog.dom.createDom('div', this.parent_.horizontalLayout_ ?
599
+ 'scratchCategoryMenuHorizontal' : 'scratchCategoryMenu');
600
+ this.parentHtml_.appendChild(this.table);
601
+ };
602
+
603
+ /**
604
+ * Fill the toolbox with categories and blocks by creating a new
605
+ * {Blockly.Toolbox.Category} for every category tag in the toolbox xml.
606
+ * @param {Node} domTree DOM tree of blocks, or null.
607
+ */
608
+ Blockly.Toolbox.CategoryMenu.prototype.populate = function(domTree) {
609
+ if (!domTree) {
610
+ return;
611
+ }
612
+
613
+ // Remove old categories
614
+ this.dispose();
615
+ this.createDom();
616
+ var categories = [];
617
+ // Find actual categories from the DOM tree.
618
+ for (var i = 0, child; child = domTree.childNodes[i]; i++) {
619
+ if (!child.tagName || child.tagName.toUpperCase() != 'CATEGORY') {
620
+ continue;
621
+ }
622
+ categories.push(child);
623
+ }
624
+
625
+ // Create a single column of categories
626
+ for (var i = 0; i < categories.length; i++) {
627
+ var child = categories[i];
628
+ var row = goog.dom.createDom('div', 'scratchCategoryMenuRow');
629
+ this.table.appendChild(row);
630
+ if (child) {
631
+ this.categories_.push(new Blockly.Toolbox.Category(this, row,
632
+ child));
633
+ }
634
+ }
635
+ this.height_ = this.table.offsetHeight;
636
+ };
637
+
638
+ /**
639
+ * Dispose of this Category Menu and all of its children.
640
+ */
641
+ Blockly.Toolbox.CategoryMenu.prototype.dispose = function() {
642
+ for (var i = 0, category; category = this.categories_[i]; i++) {
643
+ category.dispose();
644
+ }
645
+ this.categories_ = [];
646
+ if (this.table) {
647
+ goog.dom.removeNode(this.table);
648
+ this.table = null;
649
+ }
650
+ };
651
+
652
+
653
+ // Category
654
+ /**
655
+ * Class for the data model of a category in the toolbox.
656
+ * @param {Blockly.Toolbox.CategoryMenu} parent The category menu that owns this
657
+ * category.
658
+ * @param {Element} parentHtml The containing html div.
659
+ * @param {Node} domTree DOM tree of blocks.
660
+ * @constructor
661
+ */
662
+ Blockly.Toolbox.Category = function(parent, parentHtml, domTree) {
663
+ this.parent_ = parent;
664
+ this.parentHtml_ = parentHtml;
665
+ this.name_ = domTree.getAttribute('name');
666
+ this.id_ = domTree.getAttribute('id');
667
+ this.setColour(domTree);
668
+ this.custom_ = domTree.getAttribute('custom');
669
+ this.iconURI_ = domTree.getAttribute('iconURI');
670
+ this.showStatusButton_ = domTree.getAttribute('showStatusButton');
671
+ this.contents_ = [];
672
+ if (!this.custom_) {
673
+ this.parseContents_(domTree);
674
+ }
675
+ this.createDom();
676
+ };
677
+
678
+ /**
679
+ * Dispose of this category and all of its contents.
680
+ */
681
+ Blockly.Toolbox.Category.prototype.dispose = function() {
682
+ if (this.item_) {
683
+ goog.dom.removeNode(this.item_);
684
+ this.item = null;
685
+ }
686
+ this.parent_ = null;
687
+ this.parentHtml_ = null;
688
+ this.contents_ = null;
689
+ };
690
+
691
+ /**
692
+ * Used to determine the css classes for the menu item for this category
693
+ * based on its current state.
694
+ * @private
695
+ * @param {boolean=} selected Indication whether the category is currently selected.
696
+ * @return {string} The css class names to be applied, space-separated.
697
+ */
698
+ Blockly.Toolbox.Category.prototype.getMenuItemClassName_ = function(selected) {
699
+ var classNames = [
700
+ 'scratchCategoryMenuItem',
701
+ 'scratchCategoryId-' + this.id_,
702
+ ];
703
+ if (selected) {
704
+ classNames.push('categorySelected');
705
+ }
706
+ return classNames.join(' ');
707
+ };
708
+
709
+ /**
710
+ * Create the DOM for a category in the toolbox.
711
+ */
712
+ Blockly.Toolbox.Category.prototype.createDom = function() {
713
+ var toolbox = this.parent_.parent_;
714
+ this.item_ = goog.dom.createDom('div',
715
+ {'class': this.getMenuItemClassName_()});
716
+ this.label_ = goog.dom.createDom('div',
717
+ {'class': 'scratchCategoryMenuItemLabel'},
718
+ Blockly.utils.replaceMessageReferences(this.name_));
719
+ if (this.iconURI_) {
720
+ this.bubble_ = goog.dom.createDom('div',
721
+ {'class': 'scratchCategoryItemIcon'});
722
+ this.bubble_.style.backgroundImage = 'url(' + this.iconURI_ + ')';
723
+ } else {
724
+ this.bubble_ = goog.dom.createDom('div',
725
+ {'class': 'scratchCategoryItemBubble'});
726
+ this.bubble_.style.backgroundColor = this.colour_;
727
+ this.bubble_.style.borderColor = this.secondaryColour_;
728
+ }
729
+ this.item_.appendChild(this.bubble_);
730
+ this.item_.appendChild(this.label_);
731
+ this.parentHtml_.appendChild(this.item_);
732
+ Blockly.bindEvent_(
733
+ this.item_, 'mouseup', toolbox, toolbox.setSelectedItemFactory(this));
734
+ };
735
+
736
+ /**
737
+ * Set the selected state of this category.
738
+ * @param {boolean} selected Whether this category is selected.
739
+ */
740
+ Blockly.Toolbox.Category.prototype.setSelected = function(selected) {
741
+ this.item_.className = this.getMenuItemClassName_(selected);
742
+ };
743
+
744
+ /**
745
+ * Set the contents of this category from DOM.
746
+ * @param {Node} domTree DOM tree of blocks.
747
+ * @constructor
748
+ */
749
+ Blockly.Toolbox.Category.prototype.parseContents_ = function(domTree) {
750
+ for (var i = 0, child; child = domTree.childNodes[i]; i++) {
751
+ if (!child.tagName) {
752
+ // Skip
753
+ continue;
754
+ }
755
+ switch (child.tagName.toUpperCase()) {
756
+ case 'BLOCK':
757
+ case 'SHADOW':
758
+ case 'LABEL':
759
+ case 'BUTTON':
760
+ case 'SEP':
761
+ case 'TEXT':
762
+ this.contents_.push(child);
763
+ break;
764
+ default:
765
+ break;
766
+ }
767
+ }
768
+ };
769
+
770
+ /**
771
+ * Get the contents of this category.
772
+ * @return {!Array|string} xmlList List of blocks to show, or a string with the
773
+ * name of a custom category.
774
+ */
775
+ Blockly.Toolbox.Category.prototype.getContents = function() {
776
+ return this.custom_ ? this.custom_ : this.contents_;
777
+ };
778
+
779
+ /**
780
+ * Set the colour of the category's background from a DOM node.
781
+ * @param {Node} node DOM node with "colour" and "secondaryColour" attribute.
782
+ * Colours are a hex string or hue on a colour wheel (0-360).
783
+ */
784
+ Blockly.Toolbox.Category.prototype.setColour = function(node) {
785
+ var colour = node.getAttribute('colour');
786
+ var secondaryColour = node.getAttribute('secondaryColour');
787
+ if (goog.isString(colour)) {
788
+ if (colour.match(/^#[0-9a-fA-F]{6,8}$/)) {
789
+ this.colour_ = colour;
790
+ } else {
791
+ this.colour_ = Blockly.hueToRgb(colour);
792
+ }
793
+ if (secondaryColour.match(/^#[0-9a-fA-F]{6,8}$/)) {
794
+ this.secondaryColour_ = secondaryColour;
795
+ } else {
796
+ this.secondaryColour_ = Blockly.hueToRgb(secondaryColour);
797
+ }
798
+ this.hasColours_ = true;
799
+ } else {
800
+ this.colour_ = '#000000';
801
+ this.secondaryColour_ = '#000000';
802
+ }
803
+ };