@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,706 @@
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 Methods for rendering a workspace comment as SVG
23
+ * @author fenichel@google.com (Rachel Fenichel)
24
+ */
25
+ 'use strict';
26
+
27
+ goog.provide('Blockly.WorkspaceCommentSvg.render');
28
+
29
+ goog.require('Blockly.WorkspaceCommentSvg');
30
+
31
+ /**
32
+ * Radius of the border around the comment.
33
+ * @type {number}
34
+ * @const
35
+ * @private
36
+ */
37
+ Blockly.WorkspaceCommentSvg.BORDER_WIDTH = 1;
38
+
39
+ /**
40
+ * Size of the resize icon.
41
+ * @type {number}
42
+ * @const
43
+ * @private
44
+ */
45
+ Blockly.WorkspaceCommentSvg.RESIZE_SIZE = 16;
46
+
47
+ /**
48
+ * Offset from the foreignobject edge to the textarea edge.
49
+ * @type {number}
50
+ * @const
51
+ * @private
52
+ */
53
+ Blockly.WorkspaceCommentSvg.TEXTAREA_OFFSET = 12;
54
+
55
+ /**
56
+ * The height of the comment top bar.
57
+ * @package
58
+ */
59
+ Blockly.WorkspaceCommentSvg.TOP_BAR_HEIGHT = 32;
60
+
61
+ /**
62
+ * The size of the minimize arrow icon in the comment top bar.
63
+ * @private
64
+ */
65
+ Blockly.WorkspaceCommentSvg.MINIMIZE_ICON_SIZE = 32;
66
+
67
+ /**
68
+ * The size of the delete icon in the comment top bar.
69
+ * @private
70
+ */
71
+ Blockly.WorkspaceCommentSvg.DELETE_ICON_SIZE = 32;
72
+
73
+ /**
74
+ * The inset for the top bar icons.
75
+ * @private
76
+ */
77
+ Blockly.WorkspaceCommentSvg.TOP_BAR_ICON_INSET = 0;
78
+
79
+ /**
80
+ * The bottom corner padding of the resize handle touch target.
81
+ * Extends slightly outside the comment box.
82
+ * @private
83
+ */
84
+ Blockly.WorkspaceCommentSvg.RESIZE_CORNER_PAD = 4;
85
+
86
+ /**
87
+ * The top/side padding around resize handle touch target.
88
+ * Extends about one extra "diagonal" above resize handle.
89
+ * @private
90
+ */
91
+ Blockly.WorkspaceCommentSvg.RESIZE_OUTER_PAD = 8;
92
+
93
+ /**
94
+ * Width that a minimized comment should have.
95
+ * @private
96
+ */
97
+ Blockly.WorkspaceCommentSvg.MINIMIZE_WIDTH = 200;
98
+
99
+ /**
100
+ * Returns a bounding box describing the dimensions of this comment.
101
+ * @return {!{height: number, width: number}} Object with height and width
102
+ * properties in workspace units.
103
+ * @package
104
+ */
105
+ Blockly.WorkspaceCommentSvg.prototype.getHeightWidth = function() {
106
+ return { width: this.getWidth(), height: this.getHeight() };
107
+ };
108
+
109
+ /**
110
+ * Renders the workspace comment.
111
+ * @package
112
+ */
113
+ Blockly.WorkspaceCommentSvg.prototype.render = function() {
114
+ if (this.rendered_) {
115
+ return;
116
+ }
117
+
118
+ var size = this.getHeightWidth();
119
+
120
+ // Add text area
121
+ this.commentEditor_ = this.createEditor_();
122
+ this.svgGroup_.appendChild(this.commentEditor_);
123
+
124
+ this.createCommentTopBar_();
125
+
126
+ // Add the resize icon
127
+ this.addResizeDom_();
128
+
129
+ // Show / hide relevant things based on minimized state
130
+ if (this.isMinimized()) {
131
+ this.minimizeArrow_.setAttributeNS('http://www.w3.org/1999/xlink',
132
+ 'xlink:href', Blockly.mainWorkspace.options.pathToMedia + 'comment-arrow-up.svg');
133
+ this.commentEditor_.setAttribute('display', 'none');
134
+ this.resizeGroup_.setAttribute('display', 'none');
135
+ } else {
136
+ this.minimizeArrow_.setAttributeNS('http://www.w3.org/1999/xlink',
137
+ 'xlink:href', Blockly.mainWorkspace.options.pathToMedia + 'comment-arrow-down.svg');
138
+ this.topBarLabel_.setAttribute('display', 'none');
139
+ }
140
+
141
+ this.setSize(size.width, size.height);
142
+
143
+ // Set the content
144
+ this.textarea_.value = this.content_;
145
+
146
+ this.rendered_ = true;
147
+
148
+ if (this.resizeGroup_) {
149
+ Blockly.bindEventWithChecks_(
150
+ this.resizeGroup_, 'mousedown', this, this.resizeMouseDown_);
151
+ Blockly.bindEventWithChecks_(
152
+ this.resizeGroup_, 'mouseup', this, this.resizeMouseUp_);
153
+ }
154
+
155
+ Blockly.bindEventWithChecks_(
156
+ this.minimizeArrow_, 'mousedown', this, this.minimizeArrowMouseDown_, true);
157
+ Blockly.bindEventWithChecks_(
158
+ this.minimizeArrow_, 'mouseout', this, this.minimizeArrowMouseOut_, true);
159
+ Blockly.bindEventWithChecks_(
160
+ this.minimizeArrow_, 'mouseup', this, this.minimizeArrowMouseUp_, true);
161
+ Blockly.bindEventWithChecks_(
162
+ this.deleteIcon_, 'mousedown', this, this.deleteMouseDown_, true);
163
+ Blockly.bindEventWithChecks_(
164
+ this.deleteIcon_, 'mouseout', this, this.deleteMouseOut_, true);
165
+ Blockly.bindEventWithChecks_(
166
+ this.deleteIcon_, 'mouseup', this, this.deleteMouseUp_, true);
167
+ };
168
+
169
+ /**
170
+ * Create the text area for the comment.
171
+ * @return {!Element} The top-level node of the editor.
172
+ * @private
173
+ */
174
+ Blockly.WorkspaceCommentSvg.prototype.createEditor_ = function() {
175
+ this.foreignObject_ = Blockly.utils.createSvgElement(
176
+ 'foreignObject',
177
+ {
178
+ 'x': Blockly.WorkspaceCommentSvg.BORDER_WIDTH,
179
+ 'y': Blockly.WorkspaceCommentSvg.BORDER_WIDTH + Blockly.WorkspaceCommentSvg.TOP_BAR_HEIGHT,
180
+ 'class': 'scratchCommentForeignObject'
181
+ },
182
+ null);
183
+ var body = document.createElementNS(Blockly.HTML_NS, 'body');
184
+ body.setAttribute('xmlns', Blockly.HTML_NS);
185
+ body.className = 'blocklyMinimalBody scratchCommentBody';
186
+ var textarea = document.createElementNS(Blockly.HTML_NS, 'textarea');
187
+ textarea.className = 'scratchCommentTextarea scratchCommentText';
188
+ textarea.setAttribute('dir', this.RTL ? 'RTL' : 'LTR');
189
+ textarea.setAttribute('placeholder', Blockly.Msg.WORKSPACE_COMMENT_DEFAULT_TEXT);
190
+ body.appendChild(textarea);
191
+ this.textarea_ = textarea;
192
+ this.textarea_.style.margin = (Blockly.WorkspaceCommentSvg.TEXTAREA_OFFSET) + 'px';
193
+ this.foreignObject_.appendChild(body);
194
+ Blockly.bindEventWithChecks_(textarea, 'mousedown', this, function(e) {
195
+ e.stopPropagation(); // Propagation causes preventDefault from workspace handler
196
+ }, true, true);
197
+ // Don't zoom with mousewheel.
198
+ Blockly.bindEventWithChecks_(textarea, 'wheel', this, function(e) {
199
+ if (!e.ctrlKey && textarea.clientHeight !== textarea.scrollHeight) {
200
+ e.stopPropagation();
201
+ }
202
+ });
203
+ Blockly.bindEventWithChecks_(textarea, 'change', this, function(_e) {
204
+ if (this.text_ != textarea.value) {
205
+ this.setText(textarea.value);
206
+ }
207
+ });
208
+
209
+ this.labelText_ = this.getLabelText();
210
+
211
+ return this.foreignObject_;
212
+ };
213
+
214
+ /**
215
+ * Add the resize icon to the DOM
216
+ * @private
217
+ */
218
+ Blockly.WorkspaceCommentSvg.prototype.addResizeDom_ = function() {
219
+ this.resizeGroup_ = Blockly.utils.createSvgElement(
220
+ 'g',
221
+ {
222
+ 'class': this.RTL ? 'scratchCommentResizeSW' : 'scratchCommentResizeSE'
223
+ },
224
+ this.svgGroup_);
225
+ var resizeSize = Blockly.WorkspaceCommentSvg.RESIZE_SIZE;
226
+ var outerPad = Blockly.ScratchBubble.RESIZE_OUTER_PAD;
227
+ var cornerPad = Blockly.ScratchBubble.RESIZE_CORNER_PAD;
228
+ // Build an (invisible) triangle that will catch resizes. It is padded on the
229
+ // top/left by outerPad, and padded down/right by cornerPad.
230
+ Blockly.utils.createSvgElement('polygon',
231
+ {
232
+ 'points': [
233
+ -outerPad, resizeSize + cornerPad,
234
+ resizeSize + cornerPad, resizeSize + cornerPad,
235
+ resizeSize + cornerPad, -outerPad
236
+ ].join(' ')
237
+ },
238
+ this.resizeGroup_);
239
+ Blockly.utils.createSvgElement(
240
+ 'line',
241
+ {
242
+ 'class': 'blocklyResizeLine',
243
+ 'x1': resizeSize / 3, 'y1': resizeSize - 1,
244
+ 'x2': resizeSize - 1, 'y2': resizeSize / 3
245
+ }, this.resizeGroup_);
246
+ Blockly.utils.createSvgElement(
247
+ 'line',
248
+ {
249
+ 'class': 'blocklyResizeLine',
250
+ 'x1': resizeSize * 2 / 3, 'y1': resizeSize - 1,
251
+ 'x2': resizeSize - 1, 'y2': resizeSize * 2 / 3
252
+ }, this.resizeGroup_);
253
+ };
254
+
255
+ /**
256
+ * Create the comment top bar and its contents.
257
+ * @private
258
+ */
259
+ Blockly.WorkspaceCommentSvg.prototype.createCommentTopBar_ = function() {
260
+ this.svgHandleTarget_ = Blockly.utils.createSvgElement('rect',
261
+ {
262
+ 'class': 'blocklyDraggable scratchCommentTopBar',
263
+ 'rx': Blockly.WorkspaceCommentSvg.BORDER_WIDTH,
264
+ 'ry': Blockly.WorkspaceCommentSvg.BORDER_WIDTH,
265
+ 'height': Blockly.WorkspaceCommentSvg.TOP_BAR_HEIGHT
266
+ }, this.svgGroup_);
267
+
268
+ this.createTopBarIcons_();
269
+ this.createTopBarLabel_();
270
+ };
271
+
272
+ /**
273
+ * Create the comment top bar label. This is the truncated comment text
274
+ * that shows when comment is minimized.
275
+ * @private
276
+ */
277
+ Blockly.WorkspaceCommentSvg.prototype.createTopBarLabel_ = function() {
278
+ this.topBarLabel_ = Blockly.utils.createSvgElement('text',
279
+ {
280
+ 'class': 'scratchCommentText',
281
+ 'x': this.width_ / 2,
282
+ 'y': (Blockly.WorkspaceCommentSvg.TOP_BAR_HEIGHT / 2) + Blockly.WorkspaceCommentSvg.BORDER_WIDTH,
283
+ 'text-anchor': 'middle',
284
+ 'dominant-baseline': 'middle'
285
+ }, this.svgGroup_);
286
+
287
+ var labelTextNode = document.createTextNode(this.labelText_);
288
+ this.topBarLabel_.appendChild(labelTextNode);
289
+ };
290
+
291
+ /**
292
+ * Create the minimize toggle and delete icons that in the comment top bar.
293
+ * @private
294
+ */
295
+ Blockly.WorkspaceCommentSvg.prototype.createTopBarIcons_ = function() {
296
+ var topBarMiddleY = (Blockly.WorkspaceCommentSvg.TOP_BAR_HEIGHT / 2) +
297
+ Blockly.WorkspaceCommentSvg.BORDER_WIDTH;
298
+
299
+ // Minimize Toggle Icon in Comment Top Bar
300
+ var xInset = Blockly.WorkspaceCommentSvg.TOP_BAR_ICON_INSET;
301
+ this.minimizeArrow_ = Blockly.utils.createSvgElement('image',
302
+ {
303
+ 'x': xInset,
304
+ 'y': topBarMiddleY - Blockly.WorkspaceCommentSvg.MINIMIZE_ICON_SIZE / 2,
305
+ 'width': Blockly.WorkspaceCommentSvg.MINIMIZE_ICON_SIZE,
306
+ 'height': Blockly.WorkspaceCommentSvg.MINIMIZE_ICON_SIZE
307
+ }, this.svgGroup_);
308
+
309
+ // Delete Icon in Comment Top Bar
310
+ this.deleteIcon_ = Blockly.utils.createSvgElement('image',
311
+ {
312
+ 'x': xInset,
313
+ 'y': topBarMiddleY - Blockly.WorkspaceCommentSvg.DELETE_ICON_SIZE / 2,
314
+ 'width': Blockly.WorkspaceCommentSvg.DELETE_ICON_SIZE,
315
+ 'height': Blockly.WorkspaceCommentSvg.DELETE_ICON_SIZE
316
+ }, this.svgGroup_);
317
+ this.deleteIcon_.setAttributeNS('http://www.w3.org/1999/xlink',
318
+ 'xlink:href', Blockly.mainWorkspace.options.pathToMedia + 'delete-x.svg');
319
+ };
320
+
321
+ /**
322
+ * Handle a mouse-down on bubble's minimize icon.
323
+ * @param {!Event} e Mouse down event.
324
+ * @private
325
+ */
326
+ Blockly.WorkspaceCommentSvg.prototype.minimizeArrowMouseDown_ = function(e) {
327
+ // Set a property to indicate that this minimize arrow icon had a mouse down
328
+ // event. This property will get reset if the mouse leaves the icon, or when
329
+ // a mouse up event occurs on this icon.
330
+ this.shouldToggleMinimize_ = true;
331
+ e.stopPropagation();
332
+ };
333
+
334
+ /**
335
+ * Handle a mouse-out on bubble's minimize icon.
336
+ * @param {!Event} _e Mouse out event.
337
+ * @private
338
+ */
339
+ Blockly.WorkspaceCommentSvg.prototype.minimizeArrowMouseOut_ = function(_e) {
340
+ // If the mouse leaves the minimize arrow icon, make sure the
341
+ // shouldToggleMinimize_ property gets reset.
342
+ this.shouldToggleMinimize_ = false;
343
+ };
344
+
345
+ /**
346
+ * Handle a mouse-up on bubble's minimize icon.
347
+ * @param {!Event} e Mouse up event.
348
+ * @private
349
+ */
350
+ Blockly.WorkspaceCommentSvg.prototype.minimizeArrowMouseUp_ = function(e) {
351
+ // First check if this is the icon that had a mouse down event on it and that
352
+ // the mouse never left the icon.
353
+ if (this.shouldToggleMinimize_) {
354
+ this.shouldToggleMinimize = false;
355
+ this.toggleMinimize_();
356
+ }
357
+ e.stopPropagation();
358
+ };
359
+
360
+ /**
361
+ * Handle a mouse-down on bubble's minimize icon.
362
+ * @param {!Event} e Mouse down event.
363
+ * @private
364
+ */
365
+ Blockly.WorkspaceCommentSvg.prototype.deleteMouseDown_ = function(e) {
366
+ // Set a property to indicate that this delete icon had a mouse down event.
367
+ // This property will get reset if the mouse leaves the icon, or when
368
+ // a mouse up event occurs on this icon.
369
+ this.shouldDelete_ = true;
370
+ e.stopPropagation();
371
+ };
372
+
373
+ /**
374
+ * Handle a mouse-out on bubble's minimize icon.
375
+ * @param {!Event} _e Mouse out event.
376
+ * @private
377
+ */
378
+ Blockly.WorkspaceCommentSvg.prototype.deleteMouseOut_ = function(_e) {
379
+ // If the mouse leaves the delete icon, reset the shouldDelete_ property.
380
+ this.shouldDelete_ = false;
381
+ };
382
+
383
+ /**
384
+ * Handle a mouse-up on bubble's delete icon.
385
+ * @param {!Event} e Mouse up event.
386
+ * @private
387
+ */
388
+ Blockly.WorkspaceCommentSvg.prototype.deleteMouseUp_ = function(e) {
389
+ // First check that this same icon had a mouse down event on it and that the
390
+ // mouse never left the icon.
391
+ if (this.shouldDelete_) {
392
+ this.dispose();
393
+ }
394
+ e.stopPropagation();
395
+ };
396
+
397
+ /**
398
+ * Handle a mouse-down on comment's resize corner.
399
+ * @param {!Event} e Mouse down event.
400
+ * @private
401
+ */
402
+ Blockly.WorkspaceCommentSvg.prototype.resizeMouseDown_ = function(e) {
403
+ this.resizeStartSize_ = {width: this.width_, height: this.height_};
404
+ this.unbindDragEvents_();
405
+ this.workspace.setResizesEnabled(false);
406
+ if (Blockly.utils.isRightButton(e)) {
407
+ // No right-click.
408
+ e.stopPropagation();
409
+ return;
410
+ }
411
+ // Left-click (or middle click)
412
+ this.workspace.startDrag(e, new goog.math.Coordinate(
413
+ this.workspace.RTL ? -this.width_ : this.width_, this.height_));
414
+
415
+ this.onMouseUpWrapper_ = Blockly.bindEventWithChecks_(
416
+ document, 'mouseup', this, this.resizeMouseUp_);
417
+ this.onMouseMoveWrapper_ = Blockly.bindEventWithChecks_(
418
+ document, 'mousemove', this, this.resizeMouseMove_);
419
+ Blockly.hideChaff();
420
+ // This event has been handled. No need to bubble up to the document.
421
+ e.stopPropagation();
422
+ };
423
+
424
+
425
+ /**
426
+ * Set the apperance of the workspace comment bubble to the minimized or full size
427
+ * appearance. In the minimized state, the comment should only have the top bar
428
+ * displayed, with the minimize icon swapped to the minimized state, and
429
+ * truncated comment text is shown in the middle of the top bar. There should be
430
+ * no resize handle when the workspace comment is in its minimized state.
431
+ * @param {boolean} minimize Whether the bubble should be minimized
432
+ * @param {?string} labelText Optional label text for the comment top bar
433
+ * when it is minimized.
434
+ * @private
435
+ */
436
+ Blockly.WorkspaceCommentSvg.prototype.setRenderedMinimizeState_ = function(minimize, labelText) {
437
+ if (minimize) {
438
+ // Change minimize icon
439
+ this.minimizeArrow_.setAttributeNS('http://www.w3.org/1999/xlink',
440
+ 'xlink:href', Blockly.mainWorkspace.options.pathToMedia + 'comment-arrow-up.svg');
441
+ // Hide text area
442
+ this.commentEditor_.setAttribute('display', 'none');
443
+ // Hide resize handle if it exists
444
+ if (this.resizeGroup_) {
445
+ this.resizeGroup_.setAttribute('display', 'none');
446
+ }
447
+ if (labelText && this.labelText_ != labelText) {
448
+ // Update label and display
449
+ // TODO is there a better way to do this?
450
+ this.topBarLabel_.textContent = labelText;
451
+ }
452
+ Blockly.utils.removeAttribute(this.topBarLabel_, 'display');
453
+ } else {
454
+ // Change minimize icon
455
+ this.minimizeArrow_.setAttributeNS('http://www.w3.org/1999/xlink',
456
+ 'xlink:href', Blockly.mainWorkspace.options.pathToMedia + 'comment-arrow-down.svg');
457
+ // Hide label
458
+ this.topBarLabel_.setAttribute('display', 'none');
459
+ // Show text area
460
+ Blockly.utils.removeAttribute(this.commentEditor_, 'display');
461
+ // Display resize handle if it exists
462
+ if (this.resizeGroup_) {
463
+ Blockly.utils.removeAttribute(this.resizeGroup_, 'display');
464
+ }
465
+ }
466
+ };
467
+
468
+ /**
469
+ * Stop binding to the global mouseup and mousemove events.
470
+ * @private
471
+ */
472
+ Blockly.WorkspaceCommentSvg.prototype.unbindDragEvents_ = function() {
473
+ if (this.onMouseUpWrapper_) {
474
+ Blockly.unbindEvent_(this.onMouseUpWrapper_);
475
+ this.onMouseUpWrapper_ = null;
476
+ }
477
+ if (this.onMouseMoveWrapper_) {
478
+ Blockly.unbindEvent_(this.onMouseMoveWrapper_);
479
+ this.onMouseMoveWrapper_ = null;
480
+ }
481
+ };
482
+
483
+ /*
484
+ * Handle a mouse-up event while dragging a comment's border or resize handle.
485
+ * @param {!Event} e Mouse up event.
486
+ * @private
487
+ */
488
+ Blockly.WorkspaceCommentSvg.prototype.resizeMouseUp_ = function(/*e*/) {
489
+ Blockly.Touch.clearTouchIdentifier();
490
+ this.unbindDragEvents_();
491
+ var oldHW = this.resizeStartSize_;
492
+ this.resizeStartSize_ = null;
493
+ if (this.width_ == oldHW.width && this.height_ == oldHW.height) {
494
+ return;
495
+ }
496
+ // Fire a change event for the new width/height after
497
+ // resize mouse up
498
+ Blockly.Events.fire(new Blockly.Events.CommentChange(
499
+ this, {width: oldHW.width , height: oldHW.height},
500
+ {width: this.width_, height: this.height_}));
501
+
502
+ this.workspace.setResizesEnabled(true);
503
+ };
504
+
505
+ /**
506
+ * Resize this comment to follow the mouse.
507
+ * @param {!Event} e Mouse move event.
508
+ * @private
509
+ */
510
+ Blockly.WorkspaceCommentSvg.prototype.resizeMouseMove_ = function(e) {
511
+ this.autoLayout_ = false;
512
+ var newXY = this.workspace.moveDrag(e);
513
+ // The call to setSize below emits a CommentChange event,
514
+ // but we don't want multiple CommentChange events to be
515
+ // emitted while the user is still in the process of resizing
516
+ // the comment, so disable events here. The event is emitted in
517
+ // resizeMouseUp_.
518
+ var disabled = false;
519
+ if (Blockly.Events.isEnabled()) {
520
+ Blockly.Events.disable();
521
+ disabled = true;
522
+ }
523
+ this.setSize(this.RTL ? -newXY.x : newXY.x, newXY.y);
524
+ if (disabled) {
525
+ Blockly.Events.enable();
526
+ }
527
+ };
528
+
529
+ /**
530
+ * Callback function triggered when the comment has resized.
531
+ * Resize the text area accordingly.
532
+ * @private
533
+ */
534
+ Blockly.WorkspaceCommentSvg.prototype.resizeComment_ = function() {
535
+ var doubleBorderWidth = 2 * Blockly.WorkspaceCommentSvg.BORDER_WIDTH;
536
+ var topOffset = Blockly.WorkspaceCommentSvg.TOP_BAR_HEIGHT;
537
+ var textOffset = Blockly.WorkspaceCommentSvg.TEXTAREA_OFFSET * 2;
538
+
539
+ this.foreignObject_.setAttribute('width',
540
+ this.width_ - doubleBorderWidth);
541
+ this.foreignObject_.setAttribute('height',
542
+ this.height_ - doubleBorderWidth - topOffset);
543
+ if (this.RTL) {
544
+ this.foreignObject_.setAttribute('x',
545
+ -this.width_);
546
+ }
547
+ this.textarea_.style.width =
548
+ (this.width_ - textOffset) + 'px';
549
+ this.textarea_.style.height =
550
+ (this.height_ - doubleBorderWidth - textOffset - topOffset) + 'px';
551
+ };
552
+
553
+ /**
554
+ * Set size
555
+ * @param {number} width width of the container
556
+ * @param {number} height height of the container
557
+ * @package
558
+ */
559
+ Blockly.WorkspaceCommentSvg.prototype.setSize = function(width, height) {
560
+ var oldWidth = this.width_;
561
+ var oldHeight = this.height_;
562
+
563
+ var doubleBorderWidth = 2 * Blockly.WorkspaceCommentSvg.BORDER_WIDTH;
564
+
565
+ if (this.isMinimized_) {
566
+ width = Blockly.WorkspaceCommentSvg.MINIMIZE_WIDTH;
567
+ height = Blockly.WorkspaceCommentSvg.TOP_BAR_HEIGHT;
568
+ } else {
569
+ // Minimum size of a 'full size' (not minimized) comment.
570
+ width = Math.max(width, doubleBorderWidth + 50);
571
+ height = Math.max(height, doubleBorderWidth + 20 + Blockly.WorkspaceCommentSvg.TOP_BAR_HEIGHT);
572
+
573
+ // Note we are only updating this.width_ or this.height_ here
574
+ // and not in the case above, because when we're minimizing a comment,
575
+ // we want to keep track of the width/height of the maximized comment
576
+ this.width_ = width;
577
+ this.height_ = height;
578
+ Blockly.Events.fire(new Blockly.Events.CommentChange(this,
579
+ {width: oldWidth, height: oldHeight},
580
+ {width: this.width_, height: this.height_}));
581
+ }
582
+ this.svgRect_.setAttribute('width', width);
583
+ this.svgRect_.setAttribute('height', height);
584
+ this.svgHandleTarget_.setAttribute('width', width);
585
+ this.svgHandleTarget_.setAttribute('height', Blockly.WorkspaceCommentSvg.TOP_BAR_HEIGHT);
586
+ if (this.RTL) {
587
+ this.minimizeArrow_.setAttribute('x', width -
588
+ (Blockly.WorkspaceCommentSvg.MINIMIZE_ICON_SIZE) -
589
+ Blockly.WorkspaceCommentSvg.TOP_BAR_ICON_INSET);
590
+ this.deleteIcon_.setAttribute('x', (-width +
591
+ Blockly.WorkspaceCommentSvg.TOP_BAR_ICON_INSET));
592
+ this.svgRect_.setAttribute('transform', 'scale(-1 1)');
593
+ this.svgHandleTarget_.setAttribute('transform', 'scale(-1 1)');
594
+ this.svgHandleTarget_.setAttribute('transform', 'translate(' + -width + ', 1)');
595
+ this.minimizeArrow_.setAttribute('transform', 'translate(' + -width + ', 1)');
596
+ this.deleteIcon_.setAttribute('tranform', 'translate(' + -width + ', 1)');
597
+ this.topBarLabel_.setAttribute('transform', 'translate(' + -width + ', 1)');
598
+ } else {
599
+ this.deleteIcon_.setAttribute('x', width -
600
+ Blockly.WorkspaceCommentSvg.DELETE_ICON_SIZE -
601
+ Blockly.WorkspaceCommentSvg.TOP_BAR_ICON_INSET);
602
+ }
603
+
604
+ var resizeSize = Blockly.WorkspaceCommentSvg.RESIZE_SIZE;
605
+ if (this.resizeGroup_) {
606
+ if (this.RTL) {
607
+ // Mirror the resize group.
608
+ this.resizeGroup_.setAttribute('transform', 'translate(' +
609
+ (-width + doubleBorderWidth + resizeSize) + ',' +
610
+ (height - doubleBorderWidth - resizeSize) + ') scale(-1 1)');
611
+ } else {
612
+ this.resizeGroup_.setAttribute('transform', 'translate(' +
613
+ (width - doubleBorderWidth - resizeSize) + ',' +
614
+ (height - doubleBorderWidth - resizeSize) + ')');
615
+ }
616
+ }
617
+
618
+ if (this.isMinimized_) {
619
+ this.topBarLabel_.setAttribute('x', width / 2);
620
+ this.topBarLabel_.setAttribute('y', height / 2);
621
+ }
622
+
623
+ // Allow the contents to resize.
624
+ this.resizeComment_();
625
+ };
626
+
627
+ /**
628
+ * Toggle the minimization state of this comment.
629
+ * @private
630
+ */
631
+ Blockly.WorkspaceComment.prototype.toggleMinimize_ = function() {
632
+ this.setMinimized(!this.isMinimized_);
633
+ };
634
+
635
+ /**
636
+ * Set the minimized state for this comment. If the comment is rendered,
637
+ * change the appearance of the comment accordingly.
638
+ * @param {boolean} minimize Whether the comment should be minimized
639
+ * @package
640
+ */
641
+ Blockly.WorkspaceComment.prototype.setMinimized = function(minimize) {
642
+ if (this.isMinimized_ == minimize) {
643
+ return;
644
+ }
645
+ Blockly.Events.fire(new Blockly.Events.CommentChange(this,
646
+ {minimized: this.isMinimized_}, {minimized: minimize}));
647
+ this.isMinimized_ = minimize;
648
+ if (minimize) {
649
+ if (this.rendered_) {
650
+ this.setRenderedMinimizeState_(true, this.getLabelText());
651
+ }
652
+ this.setSize(Blockly.WorkspaceCommentSvg.MINIMIZE_WIDTH,
653
+ Blockly.WorkspaceCommentSvg.TOP_BAR_HEIGHT);
654
+ } else {
655
+ if (this.rendered_) {
656
+ this.setRenderedMinimizeState_(false);
657
+ }
658
+ this.setText(this.content_);
659
+ this.setSize(this.width_, this.height_);
660
+ }
661
+ };
662
+
663
+ /**
664
+ * Dispose of any rendered comment components.
665
+ * @private
666
+ */
667
+ Blockly.WorkspaceCommentSvg.prototype.disposeInternal_ = function() {
668
+ this.textarea_ = null;
669
+ this.foreignObject_ = null;
670
+ this.svgRect_ = null;
671
+ this.svgHandleTarget_ = null;
672
+ };
673
+
674
+ /**
675
+ * Set the focus on the text area.
676
+ * @package
677
+ */
678
+ Blockly.WorkspaceCommentSvg.prototype.setFocus = function() {
679
+ var comment = this;
680
+ this.focused_ = true;
681
+ comment.textarea_.focus();
682
+ // Defer CSS changes.
683
+ setTimeout(function() {
684
+ comment.addFocus();
685
+ Blockly.utils.addClass(
686
+ comment.svgHandleTarget_, 'scratchCommentHandleTargetFocused');
687
+ }, 0);
688
+ };
689
+
690
+ /**
691
+ * Remove focus from the text area.
692
+ * @package
693
+ */
694
+ Blockly.WorkspaceCommentSvg.prototype.blurFocus = function() {
695
+ var comment = this;
696
+ this.focused_ = false;
697
+ comment.textarea_.blur();
698
+ // Defer CSS changes.
699
+ setTimeout(function() {
700
+ if (comment.svgGroup_) { // Could have been deleted in the meantime
701
+ comment.removeFocus();
702
+ Blockly.utils.removeClass(
703
+ comment.svgHandleTarget_, 'scratchCommentHandleTargetFocused');
704
+ }
705
+ }, 0);
706
+ };