scratch-blocks 0.1.0-prerelease.20211005172512

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