blockly 7.20211209.4 → 8.0.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 (262) hide show
  1. package/blockly.d.ts +18963 -18432
  2. package/blockly.min.js +852 -844
  3. package/blockly_compressed.js +669 -664
  4. package/blockly_compressed.js.map +1 -1
  5. package/blocks/blocks.js +47 -0
  6. package/blocks/colour.js +13 -3
  7. package/blocks/lists.js +22 -13
  8. package/blocks/logic.js +13 -3
  9. package/blocks/loops.js +24 -11
  10. package/blocks/math.js +12 -3
  11. package/blocks/procedures.js +41 -27
  12. package/blocks/text.js +22 -13
  13. package/blocks/variables.js +14 -3
  14. package/blocks/variables_dynamic.js +13 -3
  15. package/blocks_compressed.js +146 -141
  16. package/blocks_compressed.js.map +1 -1
  17. package/core/block.js +1869 -1814
  18. package/core/block_drag_surface.js +201 -200
  19. package/core/block_dragger.js +377 -373
  20. package/core/block_svg.js +1593 -1479
  21. package/core/blockly.js +8 -22
  22. package/core/blocks.js +9 -2
  23. package/core/browser_events.js +22 -5
  24. package/core/bubble.js +841 -797
  25. package/core/bubble_dragger.js +213 -206
  26. package/core/bump_objects.js +2 -2
  27. package/core/clipboard.js +9 -9
  28. package/core/comment.js +353 -332
  29. package/core/common.js +46 -17
  30. package/core/component_manager.js +181 -174
  31. package/core/config.js +87 -0
  32. package/core/connection.js +595 -584
  33. package/core/connection_checker.js +242 -244
  34. package/core/connection_db.js +235 -230
  35. package/core/contextmenu.js +9 -6
  36. package/core/contextmenu_items.js +1 -2
  37. package/core/contextmenu_registry.js +93 -89
  38. package/core/css.js +474 -474
  39. package/core/delete_area.js +45 -42
  40. package/core/drag_target.js +57 -56
  41. package/core/dropdowndiv.js +153 -163
  42. package/core/events/events.js +2 -2
  43. package/core/events/events_abstract.js +89 -77
  44. package/core/events/events_block_base.js +37 -36
  45. package/core/events/events_block_change.js +130 -124
  46. package/core/events/events_block_create.js +73 -71
  47. package/core/events/events_block_delete.js +84 -82
  48. package/core/events/events_block_drag.js +50 -49
  49. package/core/events/events_block_move.js +147 -140
  50. package/core/events/events_bubble_open.js +51 -50
  51. package/core/events/events_click.js +48 -44
  52. package/core/events/events_comment_base.js +72 -69
  53. package/core/events/events_comment_change.js +63 -61
  54. package/core/events/events_comment_create.js +44 -42
  55. package/core/events/events_comment_delete.js +42 -40
  56. package/core/events/events_comment_move.js +106 -104
  57. package/core/events/events_marker_move.js +65 -64
  58. package/core/events/events_selected.js +46 -45
  59. package/core/events/events_theme_change.js +36 -35
  60. package/core/events/events_toolbox_item_select.js +46 -45
  61. package/core/events/events_trashcan_open.js +37 -36
  62. package/core/events/events_ui.js +47 -46
  63. package/core/events/events_ui_base.js +30 -29
  64. package/core/events/events_var_base.js +37 -36
  65. package/core/events/events_var_create.js +50 -48
  66. package/core/events/events_var_delete.js +50 -48
  67. package/core/events/events_var_rename.js +51 -49
  68. package/core/events/events_viewport.js +66 -65
  69. package/core/events/utils.js +29 -14
  70. package/core/events/workspace_events.js +49 -55
  71. package/core/extensions.js +4 -3
  72. package/core/field.js +1061 -997
  73. package/core/field_angle.js +462 -442
  74. package/core/field_checkbox.js +194 -182
  75. package/core/field_colour.js +519 -505
  76. package/core/field_dropdown.js +617 -598
  77. package/core/field_image.js +229 -220
  78. package/core/field_label.js +102 -91
  79. package/core/field_label_serializable.js +42 -41
  80. package/core/field_multilineinput.js +372 -358
  81. package/core/field_number.js +272 -253
  82. package/core/field_textinput.js +499 -467
  83. package/core/field_variable.js +458 -420
  84. package/core/flyout_base.js +1005 -952
  85. package/core/flyout_button.js +277 -260
  86. package/core/flyout_horizontal.js +304 -302
  87. package/core/flyout_metrics_manager.js +64 -64
  88. package/core/flyout_vertical.js +306 -300
  89. package/core/generator.js +459 -446
  90. package/core/gesture.js +829 -813
  91. package/core/grid.js +166 -163
  92. package/core/icon.js +168 -159
  93. package/core/inject.js +7 -5
  94. package/core/input.js +257 -248
  95. package/core/insertion_marker_manager.js +655 -624
  96. package/core/internal_constants.js +0 -129
  97. package/core/keyboard_nav/ast_node.js +605 -596
  98. package/core/keyboard_nav/basic_cursor.js +166 -165
  99. package/core/keyboard_nav/cursor.js +99 -97
  100. package/core/keyboard_nav/marker.js +83 -79
  101. package/core/keyboard_nav/tab_navigate_cursor.js +18 -23
  102. package/core/marker_manager.js +153 -141
  103. package/core/menu.js +377 -372
  104. package/core/menuitem.js +223 -217
  105. package/core/metrics_manager.js +403 -390
  106. package/core/mutator.js +468 -437
  107. package/core/names.js +229 -188
  108. package/core/options.js +290 -284
  109. package/core/procedures.js +29 -17
  110. package/core/registry.js +19 -16
  111. package/core/rendered_connection.js +482 -463
  112. package/core/renderers/common/block_rendering.js +9 -3
  113. package/core/renderers/common/constants.js +1119 -1112
  114. package/core/renderers/common/debug.js +14 -0
  115. package/core/renderers/common/debugger.js +338 -316
  116. package/core/renderers/common/drawer.js +380 -370
  117. package/core/renderers/common/i_path_object.js +2 -2
  118. package/core/renderers/common/info.js +626 -618
  119. package/core/renderers/common/marker_svg.js +579 -541
  120. package/core/renderers/common/path_object.js +203 -200
  121. package/core/renderers/common/renderer.js +220 -218
  122. package/core/renderers/geras/constants.js +36 -36
  123. package/core/renderers/geras/drawer.js +155 -147
  124. package/core/renderers/geras/highlight_constants.js +244 -238
  125. package/core/renderers/geras/highlighter.js +231 -179
  126. package/core/renderers/geras/info.js +392 -369
  127. package/core/renderers/geras/measurables/inline_input.js +25 -19
  128. package/core/renderers/geras/measurables/statement_input.js +23 -17
  129. package/core/renderers/geras/path_object.js +106 -121
  130. package/core/renderers/geras/renderer.js +96 -98
  131. package/core/renderers/measurables/base.js +30 -18
  132. package/core/renderers/measurables/bottom_row.js +83 -80
  133. package/core/renderers/measurables/connection.js +22 -15
  134. package/core/renderers/measurables/external_value_input.js +35 -22
  135. package/core/renderers/measurables/field.js +35 -20
  136. package/core/renderers/measurables/hat.js +18 -13
  137. package/core/renderers/measurables/icon.js +24 -17
  138. package/core/renderers/measurables/in_row_spacer.js +15 -13
  139. package/core/renderers/measurables/inline_input.js +43 -33
  140. package/core/renderers/measurables/input_connection.js +41 -28
  141. package/core/renderers/measurables/input_row.js +50 -44
  142. package/core/renderers/measurables/jagged_edge.js +14 -12
  143. package/core/renderers/measurables/next_connection.js +16 -14
  144. package/core/renderers/measurables/output_connection.js +26 -20
  145. package/core/renderers/measurables/previous_connection.js +16 -15
  146. package/core/renderers/measurables/round_corner.js +20 -18
  147. package/core/renderers/measurables/row.js +184 -168
  148. package/core/renderers/measurables/spacer_row.js +38 -23
  149. package/core/renderers/measurables/square_corner.js +18 -16
  150. package/core/renderers/measurables/statement_input.js +23 -20
  151. package/core/renderers/measurables/top_row.js +88 -85
  152. package/core/renderers/minimalist/constants.js +8 -7
  153. package/core/renderers/minimalist/drawer.js +11 -10
  154. package/core/renderers/minimalist/info.js +18 -18
  155. package/core/renderers/minimalist/renderer.js +40 -39
  156. package/core/renderers/thrasos/info.js +258 -248
  157. package/core/renderers/thrasos/renderer.js +20 -20
  158. package/core/renderers/zelos/constants.js +898 -873
  159. package/core/renderers/zelos/drawer.js +186 -169
  160. package/core/renderers/zelos/info.js +502 -479
  161. package/core/renderers/zelos/marker_svg.js +129 -115
  162. package/core/renderers/zelos/measurables/bottom_row.js +31 -30
  163. package/core/renderers/zelos/measurables/inputs.js +22 -21
  164. package/core/renderers/zelos/measurables/row_elements.js +14 -13
  165. package/core/renderers/zelos/measurables/top_row.js +34 -33
  166. package/core/renderers/zelos/path_object.js +181 -180
  167. package/core/renderers/zelos/renderer.js +91 -92
  168. package/core/scrollbar.js +759 -713
  169. package/core/scrollbar_pair.js +250 -245
  170. package/core/serialization/blocks.js +19 -9
  171. package/core/serialization/workspaces.js +3 -2
  172. package/core/shortcut_registry.js +286 -277
  173. package/core/sprites.js +31 -0
  174. package/core/theme.js +135 -141
  175. package/core/theme_manager.js +147 -143
  176. package/core/toolbox/category.js +602 -576
  177. package/core/toolbox/collapsible_category.js +226 -227
  178. package/core/toolbox/separator.js +70 -61
  179. package/core/toolbox/toolbox.js +934 -927
  180. package/core/toolbox/toolbox_item.js +115 -99
  181. package/core/tooltip.js +108 -35
  182. package/core/touch.js +8 -3
  183. package/core/touch_gesture.js +254 -251
  184. package/core/trashcan.js +606 -595
  185. package/core/utils/coordinate.js +97 -95
  186. package/core/utils/dom.js +2 -2
  187. package/core/utils/global.js +2 -0
  188. package/core/utils/rect.js +41 -37
  189. package/core/utils/sentinel.js +25 -0
  190. package/core/utils/size.js +30 -27
  191. package/core/utils/svg.js +18 -16
  192. package/core/variable_map.js +325 -341
  193. package/core/variable_model.js +55 -54
  194. package/core/variables.js +9 -2
  195. package/core/variables_dynamic.js +3 -1
  196. package/core/warning.js +126 -120
  197. package/core/widgetdiv.js +4 -4
  198. package/core/workspace.js +685 -664
  199. package/core/workspace_audio.js +124 -118
  200. package/core/workspace_comment.js +308 -298
  201. package/core/workspace_comment_svg.js +1029 -951
  202. package/core/workspace_drag_surface_svg.js +147 -140
  203. package/core/workspace_dragger.js +70 -71
  204. package/core/workspace_svg.js +2322 -2297
  205. package/core/xml.js +30 -20
  206. package/core/zoom_controls.js +431 -439
  207. package/dart_compressed.js +40 -43
  208. package/dart_compressed.js.map +1 -1
  209. package/generators/dart/colour.js +56 -64
  210. package/generators/dart/lists.js +61 -50
  211. package/generators/dart/math.js +160 -148
  212. package/generators/dart/text.js +83 -61
  213. package/generators/javascript/colour.js +37 -34
  214. package/generators/javascript/lists.js +50 -43
  215. package/generators/javascript/math.js +123 -139
  216. package/generators/javascript/text.js +67 -81
  217. package/generators/lua/colour.js +25 -23
  218. package/generators/lua/lists.js +97 -69
  219. package/generators/lua/logic.js +1 -2
  220. package/generators/lua/math.js +182 -144
  221. package/generators/lua/text.js +116 -99
  222. package/generators/php/colour.js +38 -32
  223. package/generators/php/lists.js +109 -89
  224. package/generators/php/math.js +90 -81
  225. package/generators/php/text.js +63 -61
  226. package/generators/python/colour.js +18 -18
  227. package/generators/python/lists.js +38 -30
  228. package/generators/python/loops.js +12 -8
  229. package/generators/python/math.js +104 -106
  230. package/generators/python/text.js +34 -30
  231. package/javascript_compressed.js +37 -39
  232. package/javascript_compressed.js.map +1 -1
  233. package/lua_compressed.js +39 -42
  234. package/lua_compressed.js.map +1 -1
  235. package/msg/az.js +2 -2
  236. package/msg/be.js +4 -4
  237. package/msg/cs.js +15 -15
  238. package/msg/de.js +1 -1
  239. package/msg/diq.js +1 -1
  240. package/msg/eo.js +1 -1
  241. package/msg/es.js +1 -1
  242. package/msg/fa.js +1 -1
  243. package/msg/fr.js +4 -4
  244. package/msg/he.js +1 -1
  245. package/msg/hr.js +2 -2
  246. package/msg/hy.js +2 -2
  247. package/msg/id.js +12 -12
  248. package/msg/inh.js +14 -14
  249. package/msg/ja.js +7 -7
  250. package/msg/lv.js +29 -29
  251. package/msg/pa.js +3 -3
  252. package/msg/smn.js +436 -0
  253. package/msg/te.js +1 -1
  254. package/msg/yue.js +1 -1
  255. package/msg/zh-hans.js +3 -3
  256. package/msg/zh-hant.js +3 -3
  257. package/package.json +7 -6
  258. package/php_compressed.js +38 -42
  259. package/php_compressed.js.map +1 -1
  260. package/python_compressed.js +26 -25
  261. package/python_compressed.js.map +1 -1
  262. package/blocks/all.js +0 -23
@@ -19,9 +19,12 @@ const debug = goog.require('Blockly.blockRendering.debug');
19
19
  const svgPaths = goog.require('Blockly.utils.svgPaths');
20
20
  /* eslint-disable-next-line no-unused-vars */
21
21
  const {BlockSvg} = goog.requireType('Blockly.BlockSvg');
22
+ const {Connection} = goog.require('Blockly.blockRendering.Connection');
22
23
  /* eslint-disable-next-line no-unused-vars */
23
24
  const {ConstantProvider} = goog.requireType('Blockly.blockRendering.ConstantProvider');
24
25
  /* eslint-disable-next-line no-unused-vars */
26
+ const {ExternalValueInput} = goog.requireType('Blockly.blockRendering.ExternalValueInput');
27
+ /* eslint-disable-next-line no-unused-vars */
25
28
  const {Field} = goog.requireType('Blockly.blockRendering.Field');
26
29
  /* eslint-disable-next-line no-unused-vars */
27
30
  const {Icon} = goog.requireType('Blockly.blockRendering.Icon');
@@ -36,430 +39,437 @@ const {Types} = goog.require('Blockly.blockRendering.Types');
36
39
 
37
40
  /**
38
41
  * An object that draws a block based on the given rendering information.
39
- * @param {!BlockSvg} block The block to render.
40
- * @param {!RenderInfo} info An object containing all
41
- * information needed to render this block.
42
- * @package
43
- * @constructor
44
42
  * @alias Blockly.blockRendering.Drawer
45
43
  */
46
- const Drawer = function(block, info) {
47
- this.block_ = block;
48
- this.info_ = info;
49
- this.topLeft_ = block.getRelativeToSurfaceXY();
50
- this.outlinePath_ = '';
51
- this.inlinePath_ = '';
44
+ class Drawer {
45
+ /**
46
+ * @param {!BlockSvg} block The block to render.
47
+ * @param {!RenderInfo} info An object containing all
48
+ * information needed to render this block.
49
+ * @package
50
+ */
51
+ constructor(block, info) {
52
+ this.block_ = block;
53
+ this.info_ = info;
54
+ this.topLeft_ = block.getRelativeToSurfaceXY();
55
+ this.outlinePath_ = '';
56
+ this.inlinePath_ = '';
57
+
58
+ /**
59
+ * The renderer's constant provider.
60
+ * @type {!ConstantProvider}
61
+ * @protected
62
+ */
63
+ this.constants_ = info.getRenderer().getConstants();
64
+ }
52
65
 
53
66
  /**
54
- * The renderer's constant provider.
55
- * @type {!ConstantProvider}
56
- * @protected
67
+ * Draw the block to the workspace. Here "drawing" means setting SVG path
68
+ * elements and moving fields, icons, and connections on the screen.
69
+ *
70
+ * The pieces of the paths are pushed into arrays of "steps", which are then
71
+ * joined with spaces and set directly on the block. This guarantees that
72
+ * the steps are separated by spaces for improved readability, but isn't
73
+ * required.
74
+ * @package
57
75
  */
58
- this.constants_ = info.getRenderer().getConstants();
59
- };
76
+ draw() {
77
+ this.hideHiddenIcons_();
78
+ this.drawOutline_();
79
+ this.drawInternals_();
60
80
 
61
- /**
62
- * Draw the block to the workspace. Here "drawing" means setting SVG path
63
- * elements and moving fields, icons, and connections on the screen.
64
- *
65
- * The pieces of the paths are pushed into arrays of "steps", which are then
66
- * joined with spaces and set directly on the block. This guarantees that
67
- * the steps are separated by spaces for improved readability, but isn't
68
- * required.
69
- * @package
70
- */
71
- Drawer.prototype.draw = function() {
72
- this.hideHiddenIcons_();
73
- this.drawOutline_();
74
- this.drawInternals_();
75
-
76
- this.block_.pathObject.setPath(this.outlinePath_ + '\n' + this.inlinePath_);
77
- if (this.info_.RTL) {
78
- this.block_.pathObject.flipRTL();
79
- }
80
- if (debug.isDebuggerEnabled()) {
81
- this.block_.renderingDebugger.drawDebug(this.block_, this.info_);
81
+ this.block_.pathObject.setPath(this.outlinePath_ + '\n' + this.inlinePath_);
82
+ if (this.info_.RTL) {
83
+ this.block_.pathObject.flipRTL();
84
+ }
85
+ if (debug.isDebuggerEnabled()) {
86
+ this.block_.renderingDebugger.drawDebug(this.block_, this.info_);
87
+ }
88
+ this.recordSizeOnBlock_();
82
89
  }
83
- this.recordSizeOnBlock_();
84
- };
85
-
86
- /**
87
- * Save sizing information back to the block
88
- * Most of the rendering information can be thrown away at the end of the
89
- * render. Anything that needs to be kept around should be set in this function.
90
- * @protected
91
- */
92
- Drawer.prototype.recordSizeOnBlock_ = function() {
93
- // This is used when the block is reporting its size to anyone else.
94
- // The dark path adds to the size of the block in both X and Y.
95
- this.block_.height = this.info_.height;
96
- this.block_.width = this.info_.widthWithChildren;
97
- };
98
90
 
99
- /**
100
- * Hide icons that were marked as hidden.
101
- * @protected
102
- */
103
- Drawer.prototype.hideHiddenIcons_ = function() {
104
- for (let i = 0, iconInfo; (iconInfo = this.info_.hiddenIcons[i]); i++) {
105
- iconInfo.icon.iconGroup_.setAttribute('display', 'none');
91
+ /**
92
+ * Save sizing information back to the block
93
+ * Most of the rendering information can be thrown away at the end of the
94
+ * render. Anything that needs to be kept around should be set in this
95
+ * function.
96
+ * @protected
97
+ */
98
+ recordSizeOnBlock_() {
99
+ // This is used when the block is reporting its size to anyone else.
100
+ // The dark path adds to the size of the block in both X and Y.
101
+ this.block_.height = this.info_.height;
102
+ this.block_.width = this.info_.widthWithChildren;
106
103
  }
107
- };
108
104
 
109
- /**
110
- * Create the outline of the block. This is a single continuous path.
111
- * @protected
112
- */
113
- Drawer.prototype.drawOutline_ = function() {
114
- this.drawTop_();
115
- for (let r = 1; r < this.info_.rows.length - 1; r++) {
116
- const row = this.info_.rows[r];
117
- if (row.hasJaggedEdge) {
118
- this.drawJaggedEdge_(row);
119
- } else if (row.hasStatement) {
120
- this.drawStatementInput_(row);
121
- } else if (row.hasExternalInput) {
122
- this.drawValueInput_(row);
123
- } else {
124
- this.drawRightSideRow_(row);
105
+ /**
106
+ * Hide icons that were marked as hidden.
107
+ * @protected
108
+ */
109
+ hideHiddenIcons_() {
110
+ for (let i = 0, iconInfo; (iconInfo = this.info_.hiddenIcons[i]); i++) {
111
+ iconInfo.icon.iconGroup_.setAttribute('display', 'none');
125
112
  }
126
113
  }
127
- this.drawBottom_();
128
- this.drawLeft_();
129
- };
130
114
 
131
-
132
- /**
133
- * Add steps for the top corner of the block, taking into account
134
- * details such as hats and rounded corners.
135
- * @protected
136
- */
137
- Drawer.prototype.drawTop_ = function() {
138
- const topRow = this.info_.topRow;
139
- const elements = topRow.elements;
140
-
141
- this.positionPreviousConnection_();
142
- this.outlinePath_ += svgPaths.moveBy(topRow.xPos, this.info_.startY);
143
- for (let i = 0, elem; (elem = elements[i]); i++) {
144
- if (Types.isLeftRoundedCorner(elem)) {
145
- this.outlinePath_ += this.constants_.OUTSIDE_CORNERS.topLeft;
146
- } else if (Types.isRightRoundedCorner(elem)) {
147
- this.outlinePath_ += this.constants_.OUTSIDE_CORNERS.topRight;
148
- } else if (Types.isPreviousConnection(elem)) {
149
- this.outlinePath_ += elem.shape.pathLeft;
150
- } else if (Types.isHat(elem)) {
151
- this.outlinePath_ += this.constants_.START_HAT.path;
152
- } else if (Types.isSpacer(elem)) {
153
- this.outlinePath_ += svgPaths.lineOnAxis('h', elem.width);
115
+ /**
116
+ * Create the outline of the block. This is a single continuous path.
117
+ * @protected
118
+ */
119
+ drawOutline_() {
120
+ this.drawTop_();
121
+ for (let r = 1; r < this.info_.rows.length - 1; r++) {
122
+ const row = this.info_.rows[r];
123
+ if (row.hasJaggedEdge) {
124
+ this.drawJaggedEdge_(row);
125
+ } else if (row.hasStatement) {
126
+ this.drawStatementInput_(row);
127
+ } else if (row.hasExternalInput) {
128
+ this.drawValueInput_(row);
129
+ } else {
130
+ this.drawRightSideRow_(row);
131
+ }
154
132
  }
155
- // No branch for a square corner, because it's a no-op.
133
+ this.drawBottom_();
134
+ this.drawLeft_();
156
135
  }
157
- this.outlinePath_ += svgPaths.lineOnAxis('v', topRow.height);
158
- };
159
-
160
- /**
161
- * Add steps for the jagged edge of a row on a collapsed block.
162
- * @param {!Row} row The row to draw the side of.
163
- * @protected
164
- */
165
- Drawer.prototype.drawJaggedEdge_ = function(row) {
166
- const remainder = row.height - this.constants_.JAGGED_TEETH.height;
167
- this.outlinePath_ +=
168
- this.constants_.JAGGED_TEETH.path + svgPaths.lineOnAxis('v', remainder);
169
- };
170
-
171
- /**
172
- * Add steps for an external value input, rendered as a notch in the side
173
- * of the block.
174
- * @param {!Row} row The row that this input belongs to.
175
- * @protected
176
- */
177
- Drawer.prototype.drawValueInput_ = function(row) {
178
- const input = row.getLastInput();
179
- this.positionExternalValueConnection_(row);
180
-
181
- const pathDown = (typeof input.shape.pathDown === 'function') ?
182
- input.shape.pathDown(input.height) :
183
- input.shape.pathDown;
184
-
185
- this.outlinePath_ += svgPaths.lineOnAxis('H', input.xPos + input.width) +
186
- pathDown + svgPaths.lineOnAxis('v', row.height - input.connectionHeight);
187
- };
188
-
189
136
 
190
- /**
191
- * Add steps for a statement input.
192
- * @param {!Row} row The row that this input belongs to.
193
- * @protected
194
- */
195
- Drawer.prototype.drawStatementInput_ = function(row) {
196
- const input = row.getLastInput();
197
- // Where to start drawing the notch, which is on the right side in LTR.
198
- const x = input.xPos + input.notchOffset + input.shape.width;
137
+ /**
138
+ * Add steps for the top corner of the block, taking into account
139
+ * details such as hats and rounded corners.
140
+ * @protected
141
+ */
142
+ drawTop_() {
143
+ const topRow = this.info_.topRow;
144
+ const elements = topRow.elements;
145
+
146
+ this.positionPreviousConnection_();
147
+ this.outlinePath_ += svgPaths.moveBy(topRow.xPos, this.info_.startY);
148
+ for (let i = 0, elem; (elem = elements[i]); i++) {
149
+ if (Types.isLeftRoundedCorner(elem)) {
150
+ this.outlinePath_ += this.constants_.OUTSIDE_CORNERS.topLeft;
151
+ } else if (Types.isRightRoundedCorner(elem)) {
152
+ this.outlinePath_ += this.constants_.OUTSIDE_CORNERS.topRight;
153
+ } else if (
154
+ Types.isPreviousConnection(elem) && elem instanceof Connection) {
155
+ this.outlinePath_ += elem.shape.pathLeft;
156
+ } else if (Types.isHat(elem)) {
157
+ this.outlinePath_ += this.constants_.START_HAT.path;
158
+ } else if (Types.isSpacer(elem)) {
159
+ this.outlinePath_ += svgPaths.lineOnAxis('h', elem.width);
160
+ }
161
+ // No branch for a square corner, because it's a no-op.
162
+ }
163
+ this.outlinePath_ += svgPaths.lineOnAxis('v', topRow.height);
164
+ }
199
165
 
200
- const innerTopLeftCorner = input.shape.pathRight +
201
- svgPaths.lineOnAxis(
202
- 'h', -(input.notchOffset - this.constants_.INSIDE_CORNERS.width)) +
203
- this.constants_.INSIDE_CORNERS.pathTop;
166
+ /**
167
+ * Add steps for the jagged edge of a row on a collapsed block.
168
+ * @param {!Row} row The row to draw the side of.
169
+ * @protected
170
+ */
171
+ drawJaggedEdge_(row) {
172
+ const remainder = row.height - this.constants_.JAGGED_TEETH.height;
173
+ this.outlinePath_ +=
174
+ this.constants_.JAGGED_TEETH.path + svgPaths.lineOnAxis('v', remainder);
175
+ }
204
176
 
205
- const innerHeight = row.height - (2 * this.constants_.INSIDE_CORNERS.height);
177
+ /**
178
+ * Add steps for an external value input, rendered as a notch in the side
179
+ * of the block.
180
+ * @param {!Row} row The row that this input belongs to.
181
+ * @protected
182
+ */
183
+ drawValueInput_(row) {
184
+ const input =
185
+ /** @type {ExternalValueInput|InlineInput} */ (row.getLastInput());
186
+ this.positionExternalValueConnection_(row);
187
+
188
+ const pathDown = (typeof input.shape.pathDown === 'function') ?
189
+ input.shape.pathDown(input.height) :
190
+ input.shape.pathDown;
191
+
192
+ this.outlinePath_ += svgPaths.lineOnAxis('H', input.xPos + input.width) +
193
+ pathDown +
194
+ svgPaths.lineOnAxis('v', row.height - input.connectionHeight);
195
+ }
206
196
 
207
- this.outlinePath_ += svgPaths.lineOnAxis('H', x) + innerTopLeftCorner +
208
- svgPaths.lineOnAxis('v', innerHeight) +
209
- this.constants_.INSIDE_CORNERS.pathBottom +
210
- svgPaths.lineOnAxis('H', row.xPos + row.width);
197
+ /**
198
+ * Add steps for a statement input.
199
+ * @param {!Row} row The row that this input belongs to.
200
+ * @protected
201
+ */
202
+ drawStatementInput_(row) {
203
+ const input = row.getLastInput();
204
+ // Where to start drawing the notch, which is on the right side in LTR.
205
+ const x = input.xPos + input.notchOffset + input.shape.width;
211
206
 
212
- this.positionStatementInputConnection_(row);
213
- };
207
+ const innerTopLeftCorner = input.shape.pathRight +
208
+ svgPaths.lineOnAxis(
209
+ 'h', -(input.notchOffset - this.constants_.INSIDE_CORNERS.width)) +
210
+ this.constants_.INSIDE_CORNERS.pathTop;
214
211
 
215
- /**
216
- * Add steps for the right side of a row that does not have value or
217
- * statement input connections.
218
- * @param {!Row} row The row to draw the side of.
219
- * @protected
220
- */
221
- Drawer.prototype.drawRightSideRow_ = function(row) {
222
- this.outlinePath_ += svgPaths.lineOnAxis('V', row.yPos + row.height);
223
- };
212
+ const innerHeight =
213
+ row.height - (2 * this.constants_.INSIDE_CORNERS.height);
224
214
 
215
+ this.outlinePath_ += svgPaths.lineOnAxis('H', x) + innerTopLeftCorner +
216
+ svgPaths.lineOnAxis('v', innerHeight) +
217
+ this.constants_.INSIDE_CORNERS.pathBottom +
218
+ svgPaths.lineOnAxis('H', row.xPos + row.width);
225
219
 
226
- /**
227
- * Add steps for the bottom edge of a block, possibly including a notch
228
- * for the next connection.
229
- * @protected
230
- */
231
- Drawer.prototype.drawBottom_ = function() {
232
- const bottomRow = this.info_.bottomRow;
233
- const elems = bottomRow.elements;
234
- this.positionNextConnection_();
235
-
236
- let rightCornerYOffset = 0;
237
- let outlinePath = '';
238
- for (let i = elems.length - 1, elem; (elem = elems[i]); i--) {
239
- if (Types.isNextConnection(elem)) {
240
- outlinePath += elem.shape.pathRight;
241
- } else if (Types.isLeftSquareCorner(elem)) {
242
- outlinePath += svgPaths.lineOnAxis('H', bottomRow.xPos);
243
- } else if (Types.isLeftRoundedCorner(elem)) {
244
- outlinePath += this.constants_.OUTSIDE_CORNERS.bottomLeft;
245
- } else if (Types.isRightRoundedCorner(elem)) {
246
- outlinePath += this.constants_.OUTSIDE_CORNERS.bottomRight;
247
- rightCornerYOffset = this.constants_.OUTSIDE_CORNERS.rightHeight;
248
- } else if (Types.isSpacer(elem)) {
249
- outlinePath += svgPaths.lineOnAxis('h', elem.width * -1);
250
- }
220
+ this.positionStatementInputConnection_(row);
251
221
  }
252
222
 
253
- this.outlinePath_ +=
254
- svgPaths.lineOnAxis('V', bottomRow.baseline - rightCornerYOffset);
255
- this.outlinePath_ += outlinePath;
256
- };
257
-
258
- /**
259
- * Add steps for the left side of the block, which may include an output
260
- * connection
261
- * @protected
262
- */
263
- Drawer.prototype.drawLeft_ = function() {
264
- const outputConnection = this.info_.outputConnection;
265
- this.positionOutputConnection_();
266
-
267
- if (outputConnection) {
268
- const tabBottom =
269
- outputConnection.connectionOffsetY + outputConnection.height;
270
- const pathUp = (typeof outputConnection.shape.pathUp === 'function') ?
271
- outputConnection.shape.pathUp(outputConnection.height) :
272
- outputConnection.shape.pathUp;
273
-
274
- // Draw a line up to the bottom of the tab.
275
- this.outlinePath_ += svgPaths.lineOnAxis('V', tabBottom) + pathUp;
223
+ /**
224
+ * Add steps for the right side of a row that does not have value or
225
+ * statement input connections.
226
+ * @param {!Row} row The row to draw the side of.
227
+ * @protected
228
+ */
229
+ drawRightSideRow_(row) {
230
+ this.outlinePath_ += svgPaths.lineOnAxis('V', row.yPos + row.height);
276
231
  }
277
- // Close off the path. This draws a vertical line up to the start of the
278
- // block's path, which may be either a rounded or a sharp corner.
279
- this.outlinePath_ += 'z';
280
- };
281
232
 
282
- /**
283
- * Draw the internals of the block: inline inputs, fields, and icons. These do
284
- * not depend on the outer path for placement.
285
- * @protected
286
- */
287
- Drawer.prototype.drawInternals_ = function() {
288
- for (let i = 0, row; (row = this.info_.rows[i]); i++) {
289
- for (let j = 0, elem; (elem = row.elements[j]); j++) {
290
- if (Types.isInlineInput(elem)) {
291
- this.drawInlineInput_(
292
- /** @type {!InlineInput} */ (elem));
293
- } else if (Types.isIcon(elem) || Types.isField(elem)) {
294
- this.layoutField_(
295
- /** @type {!Field|!Icon} */
296
- (elem));
233
+ /**
234
+ * Add steps for the bottom edge of a block, possibly including a notch
235
+ * for the next connection.
236
+ * @protected
237
+ */
238
+ drawBottom_() {
239
+ const bottomRow = this.info_.bottomRow;
240
+ const elems = bottomRow.elements;
241
+ this.positionNextConnection_();
242
+
243
+ let rightCornerYOffset = 0;
244
+ let outlinePath = '';
245
+ for (let i = elems.length - 1, elem; (elem = elems[i]); i--) {
246
+ if (Types.isNextConnection(elem) && elem instanceof Connection) {
247
+ outlinePath += elem.shape.pathRight;
248
+ } else if (Types.isLeftSquareCorner(elem)) {
249
+ outlinePath += svgPaths.lineOnAxis('H', bottomRow.xPos);
250
+ } else if (Types.isLeftRoundedCorner(elem)) {
251
+ outlinePath += this.constants_.OUTSIDE_CORNERS.bottomLeft;
252
+ } else if (Types.isRightRoundedCorner(elem)) {
253
+ outlinePath += this.constants_.OUTSIDE_CORNERS.bottomRight;
254
+ rightCornerYOffset = this.constants_.OUTSIDE_CORNERS.rightHeight;
255
+ } else if (Types.isSpacer(elem)) {
256
+ outlinePath += svgPaths.lineOnAxis('h', elem.width * -1);
297
257
  }
298
258
  }
299
- }
300
- };
301
259
 
302
- /**
303
- * Push a field or icon's new position to its SVG root.
304
- * @param {!Icon|!Field} fieldInfo
305
- * The rendering information for the field or icon.
306
- * @protected
307
- */
308
- Drawer.prototype.layoutField_ = function(fieldInfo) {
309
- let svgGroup;
310
- if (Types.isField(fieldInfo)) {
311
- svgGroup = fieldInfo.field.getSvgRoot();
312
- } else if (Types.isIcon(fieldInfo)) {
313
- svgGroup = fieldInfo.icon.iconGroup_;
260
+ this.outlinePath_ +=
261
+ svgPaths.lineOnAxis('V', bottomRow.baseline - rightCornerYOffset);
262
+ this.outlinePath_ += outlinePath;
314
263
  }
315
264
 
316
- const yPos = fieldInfo.centerline - fieldInfo.height / 2;
317
- let xPos = fieldInfo.xPos;
318
- let scale = '';
319
- if (this.info_.RTL) {
320
- xPos = -(xPos + fieldInfo.width);
321
- if (fieldInfo.flipRtl) {
322
- xPos += fieldInfo.width;
323
- scale = 'scale(-1 1)';
265
+ /**
266
+ * Add steps for the left side of the block, which may include an output
267
+ * connection
268
+ * @protected
269
+ */
270
+ drawLeft_() {
271
+ const outputConnection = this.info_.outputConnection;
272
+ this.positionOutputConnection_();
273
+
274
+ if (outputConnection) {
275
+ const tabBottom =
276
+ outputConnection.connectionOffsetY + outputConnection.height;
277
+ const pathUp = (typeof outputConnection.shape.pathUp === 'function') ?
278
+ outputConnection.shape.pathUp(outputConnection.height) :
279
+ outputConnection.shape.pathUp;
280
+
281
+ // Draw a line up to the bottom of the tab.
282
+ this.outlinePath_ += svgPaths.lineOnAxis('V', tabBottom) + pathUp;
324
283
  }
325
- }
326
- if (Types.isIcon(fieldInfo)) {
327
- svgGroup.setAttribute('display', 'block');
328
- svgGroup.setAttribute('transform', 'translate(' + xPos + ',' + yPos + ')');
329
- fieldInfo.icon.computeIconLocation();
330
- } else {
331
- svgGroup.setAttribute(
332
- 'transform', 'translate(' + xPos + ',' + yPos + ')' + scale);
284
+ // Close off the path. This draws a vertical line up to the start of the
285
+ // block's path, which may be either a rounded or a sharp corner.
286
+ this.outlinePath_ += 'z';
333
287
  }
334
288
 
335
- if (this.info_.isInsertionMarker) {
336
- // Fields and icons are invisible on insertion marker. They still have to
337
- // be rendered so that the block can be sized correctly.
338
- svgGroup.setAttribute('display', 'none');
289
+ /**
290
+ * Draw the internals of the block: inline inputs, fields, and icons. These
291
+ * do not depend on the outer path for placement.
292
+ * @protected
293
+ */
294
+ drawInternals_() {
295
+ for (let i = 0, row; (row = this.info_.rows[i]); i++) {
296
+ for (let j = 0, elem; (elem = row.elements[j]); j++) {
297
+ if (Types.isInlineInput(elem)) {
298
+ this.drawInlineInput_(
299
+ /** @type {!InlineInput} */ (elem));
300
+ } else if (Types.isIcon(elem) || Types.isField(elem)) {
301
+ this.layoutField_(
302
+ /** @type {!Field|!Icon} */
303
+ (elem));
304
+ }
305
+ }
306
+ }
339
307
  }
340
- };
341
308
 
342
- /**
343
- * Add steps for an inline input.
344
- * @param {!InlineInput} input The information about the
345
- * input to render.
346
- * @protected
347
- */
348
- Drawer.prototype.drawInlineInput_ = function(input) {
349
- const width = input.width;
350
- const height = input.height;
351
- const yPos = input.centerline - height / 2;
309
+ /**
310
+ * Push a field or icon's new position to its SVG root.
311
+ * @param {!Icon|!Field} fieldInfo
312
+ * The rendering information for the field or icon.
313
+ * @protected
314
+ */
315
+ layoutField_(fieldInfo) {
316
+ let svgGroup;
317
+ if (Types.isField(fieldInfo)) {
318
+ svgGroup = fieldInfo.field.getSvgRoot();
319
+ } else if (Types.isIcon(fieldInfo)) {
320
+ svgGroup = fieldInfo.icon.iconGroup_;
321
+ }
352
322
 
353
- const connectionTop = input.connectionOffsetY;
354
- const connectionBottom = input.connectionHeight + connectionTop;
355
- const connectionRight = input.xPos + input.connectionWidth;
323
+ const yPos = fieldInfo.centerline - fieldInfo.height / 2;
324
+ let xPos = fieldInfo.xPos;
325
+ let scale = '';
326
+ if (this.info_.RTL) {
327
+ xPos = -(xPos + fieldInfo.width);
328
+ if (fieldInfo.flipRtl) {
329
+ xPos += fieldInfo.width;
330
+ scale = 'scale(-1 1)';
331
+ }
332
+ }
333
+ if (Types.isIcon(fieldInfo)) {
334
+ svgGroup.setAttribute('display', 'block');
335
+ svgGroup.setAttribute(
336
+ 'transform', 'translate(' + xPos + ',' + yPos + ')');
337
+ fieldInfo.icon.computeIconLocation();
338
+ } else {
339
+ svgGroup.setAttribute(
340
+ 'transform', 'translate(' + xPos + ',' + yPos + ')' + scale);
341
+ }
356
342
 
357
- this.inlinePath_ += svgPaths.moveTo(connectionRight, yPos) +
358
- svgPaths.lineOnAxis('v', connectionTop) + input.shape.pathDown +
359
- svgPaths.lineOnAxis('v', height - connectionBottom) +
360
- svgPaths.lineOnAxis('h', width - input.connectionWidth) +
361
- svgPaths.lineOnAxis('v', -height) + 'z';
343
+ if (this.info_.isInsertionMarker) {
344
+ // Fields and icons are invisible on insertion marker. They still have to
345
+ // be rendered so that the block can be sized correctly.
346
+ svgGroup.setAttribute('display', 'none');
347
+ }
348
+ }
362
349
 
363
- this.positionInlineInputConnection_(input);
364
- };
350
+ /**
351
+ * Add steps for an inline input.
352
+ * @param {!InlineInput} input The information about the
353
+ * input to render.
354
+ * @protected
355
+ */
356
+ drawInlineInput_(input) {
357
+ const width = input.width;
358
+ const height = input.height;
359
+ const yPos = input.centerline - height / 2;
360
+
361
+ const connectionTop = input.connectionOffsetY;
362
+ const connectionBottom = input.connectionHeight + connectionTop;
363
+ const connectionRight = input.xPos + input.connectionWidth;
364
+
365
+ this.inlinePath_ += svgPaths.moveTo(connectionRight, yPos) +
366
+ svgPaths.lineOnAxis('v', connectionTop) + input.shape.pathDown +
367
+ svgPaths.lineOnAxis('v', height - connectionBottom) +
368
+ svgPaths.lineOnAxis('h', width - input.connectionWidth) +
369
+ svgPaths.lineOnAxis('v', -height) + 'z';
370
+
371
+ this.positionInlineInputConnection_(input);
372
+ }
365
373
 
366
- /**
367
- * Position the connection on an inline value input, taking into account
368
- * RTL and the small gap between the parent block and child block which lets the
369
- * parent block's dark path show through.
370
- * @param {InlineInput} input The information about
371
- * the input that the connection is on.
372
- * @protected
373
- */
374
- Drawer.prototype.positionInlineInputConnection_ = function(input) {
375
- const yPos = input.centerline - input.height / 2;
376
- // Move the connection.
377
- if (input.connectionModel) {
378
- // xPos already contains info about startX
379
- let connX = input.xPos + input.connectionWidth + input.connectionOffsetX;
380
- if (this.info_.RTL) {
381
- connX *= -1;
374
+ /**
375
+ * Position the connection on an inline value input, taking into account
376
+ * RTL and the small gap between the parent block and child block which lets
377
+ * the parent block's dark path show through.
378
+ * @param {InlineInput} input The information about
379
+ * the input that the connection is on.
380
+ * @protected
381
+ */
382
+ positionInlineInputConnection_(input) {
383
+ const yPos = input.centerline - input.height / 2;
384
+ // Move the connection.
385
+ if (input.connectionModel) {
386
+ // xPos already contains info about startX
387
+ let connX = input.xPos + input.connectionWidth + input.connectionOffsetX;
388
+ if (this.info_.RTL) {
389
+ connX *= -1;
390
+ }
391
+ input.connectionModel.setOffsetInBlock(
392
+ connX, yPos + input.connectionOffsetY);
382
393
  }
383
- input.connectionModel.setOffsetInBlock(
384
- connX, yPos + input.connectionOffsetY);
385
394
  }
386
- };
387
395
 
388
- /**
389
- * Position the connection on a statement input, taking into account
390
- * RTL and the small gap between the parent block and child block which lets the
391
- * parent block's dark path show through.
392
- * @param {!Row} row The row that the connection is on.
393
- * @protected
394
- */
395
- Drawer.prototype.positionStatementInputConnection_ = function(row) {
396
- const input = row.getLastInput();
397
- if (input.connectionModel) {
398
- let connX = row.xPos + row.statementEdge + input.notchOffset;
399
- if (this.info_.RTL) {
400
- connX *= -1;
396
+ /**
397
+ * Position the connection on a statement input, taking into account
398
+ * RTL and the small gap between the parent block and child block which lets
399
+ * the parent block's dark path show through.
400
+ * @param {!Row} row The row that the connection is on.
401
+ * @protected
402
+ */
403
+ positionStatementInputConnection_(row) {
404
+ const input = row.getLastInput();
405
+ if (input.connectionModel) {
406
+ let connX = row.xPos + row.statementEdge + input.notchOffset;
407
+ if (this.info_.RTL) {
408
+ connX *= -1;
409
+ }
410
+ input.connectionModel.setOffsetInBlock(connX, row.yPos);
401
411
  }
402
- input.connectionModel.setOffsetInBlock(connX, row.yPos);
403
412
  }
404
- };
405
413
 
406
- /**
407
- * Position the connection on an external value input, taking into account
408
- * RTL and the small gap between the parent block and child block which lets the
409
- * parent block's dark path show through.
410
- * @param {!Row} row The row that the connection is on.
411
- * @protected
412
- */
413
- Drawer.prototype.positionExternalValueConnection_ = function(row) {
414
- const input = row.getLastInput();
415
- if (input.connectionModel) {
416
- let connX = row.xPos + row.width;
417
- if (this.info_.RTL) {
418
- connX *= -1;
414
+ /**
415
+ * Position the connection on an external value input, taking into account
416
+ * RTL and the small gap between the parent block and child block which lets
417
+ * the parent block's dark path show through.
418
+ * @param {!Row} row The row that the connection is on.
419
+ * @protected
420
+ */
421
+ positionExternalValueConnection_(row) {
422
+ const input = row.getLastInput();
423
+ if (input.connectionModel) {
424
+ let connX = row.xPos + row.width;
425
+ if (this.info_.RTL) {
426
+ connX *= -1;
427
+ }
428
+ input.connectionModel.setOffsetInBlock(connX, row.yPos);
419
429
  }
420
- input.connectionModel.setOffsetInBlock(connX, row.yPos);
421
430
  }
422
- };
423
431
 
424
- /**
425
- * Position the previous connection on a block.
426
- * @protected
427
- */
428
- Drawer.prototype.positionPreviousConnection_ = function() {
429
- const topRow = this.info_.topRow;
430
- if (topRow.connection) {
431
- const x = topRow.xPos + topRow.notchOffset;
432
- const connX = (this.info_.RTL ? -x : x);
433
- topRow.connection.connectionModel.setOffsetInBlock(connX, 0);
432
+ /**
433
+ * Position the previous connection on a block.
434
+ * @protected
435
+ */
436
+ positionPreviousConnection_() {
437
+ const topRow = this.info_.topRow;
438
+ if (topRow.connection) {
439
+ const x = topRow.xPos + topRow.notchOffset;
440
+ const connX = (this.info_.RTL ? -x : x);
441
+ topRow.connection.connectionModel.setOffsetInBlock(connX, 0);
442
+ }
434
443
  }
435
- };
436
444
 
437
- /**
438
- * Position the next connection on a block.
439
- * @protected
440
- */
441
- Drawer.prototype.positionNextConnection_ = function() {
442
- const bottomRow = this.info_.bottomRow;
443
-
444
- if (bottomRow.connection) {
445
- const connInfo = bottomRow.connection;
446
- const x = connInfo.xPos; // Already contains info about startX.
447
- const connX = (this.info_.RTL ? -x : x);
448
- connInfo.connectionModel.setOffsetInBlock(connX, bottomRow.baseline);
445
+ /**
446
+ * Position the next connection on a block.
447
+ * @protected
448
+ */
449
+ positionNextConnection_() {
450
+ const bottomRow = this.info_.bottomRow;
451
+
452
+ if (bottomRow.connection) {
453
+ const connInfo = bottomRow.connection;
454
+ const x = connInfo.xPos; // Already contains info about startX.
455
+ const connX = (this.info_.RTL ? -x : x);
456
+ connInfo.connectionModel.setOffsetInBlock(connX, bottomRow.baseline);
457
+ }
449
458
  }
450
- };
451
459
 
452
- /**
453
- * Position the output connection on a block.
454
- * @protected
455
- */
456
- Drawer.prototype.positionOutputConnection_ = function() {
457
- if (this.info_.outputConnection) {
458
- const x = this.info_.startX + this.info_.outputConnection.connectionOffsetX;
459
- const connX = this.info_.RTL ? -x : x;
460
- this.block_.outputConnection.setOffsetInBlock(
461
- connX, this.info_.outputConnection.connectionOffsetY);
460
+ /**
461
+ * Position the output connection on a block.
462
+ * @protected
463
+ */
464
+ positionOutputConnection_() {
465
+ if (this.info_.outputConnection) {
466
+ const x =
467
+ this.info_.startX + this.info_.outputConnection.connectionOffsetX;
468
+ const connX = this.info_.RTL ? -x : x;
469
+ this.block_.outputConnection.setOffsetInBlock(
470
+ connX, this.info_.outputConnection.connectionOffsetY);
471
+ }
462
472
  }
463
- };
473
+ }
464
474
 
465
475
  exports.Drawer = Drawer;