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
@@ -17,15 +17,18 @@
17
17
  goog.module('Blockly.zelos.RenderInfo');
18
18
 
19
19
  const {Align} = goog.require('Blockly.Input');
20
- const object = goog.require('Blockly.utils.object');
21
20
  /* eslint-disable-next-line no-unused-vars */
22
21
  const {BlockSvg} = goog.requireType('Blockly.BlockSvg');
23
22
  const {BottomRow} = goog.require('Blockly.zelos.BottomRow');
24
23
  /* eslint-disable-next-line no-unused-vars */
25
24
  const {ConstantProvider} = goog.requireType('Blockly.zelos.ConstantProvider');
25
+ const {Field} = goog.require('Blockly.blockRendering.Field');
26
26
  const {FieldImage} = goog.require('Blockly.FieldImage');
27
27
  const {FieldLabel} = goog.require('Blockly.FieldLabel');
28
28
  const {FieldTextInput} = goog.require('Blockly.FieldTextInput');
29
+ /* eslint-disable-next-line no-unused-vars */
30
+ const {Input} = goog.requireType('Blockly.Input');
31
+ const {InputConnection} = goog.require('Blockly.blockRendering.InputConnection');
29
32
  const {InRowSpacer} = goog.require('Blockly.blockRendering.InRowSpacer');
30
33
  /* eslint-disable-next-line no-unused-vars */
31
34
  const {Measurable} = goog.requireType('Blockly.blockRendering.Measurable');
@@ -33,6 +36,10 @@ const {RenderInfo: BaseRenderInfo} = goog.require('Blockly.blockRendering.Render
33
36
  /* eslint-disable-next-line no-unused-vars */
34
37
  const {Renderer} = goog.requireType('Blockly.zelos.Renderer');
35
38
  const {RightConnectionShape} = goog.require('Blockly.zelos.RightConnectionShape');
39
+ /* eslint-disable-next-line no-unused-vars */
40
+ const {Row} = goog.require('Blockly.blockRendering.Row');
41
+ /* eslint-disable-next-line no-unused-vars */
42
+ const {SpacerRow} = goog.requireType('Blockly.blockRendering.SpacerRow');
36
43
  const {StatementInput} = goog.require('Blockly.zelos.StatementInput');
37
44
  const {TopRow} = goog.require('Blockly.zelos.TopRow');
38
45
  const {Types} = goog.require('Blockly.blockRendering.Types');
@@ -45,557 +52,573 @@ const {inputTypes} = goog.require('Blockly.inputTypes');
45
52
  * This measure pass does not propagate changes to the block (although fields
46
53
  * may choose to rerender when getSize() is called). However, calling it
47
54
  * repeatedly may be expensive.
48
- *
49
- * @param {!Renderer} renderer The renderer in use.
50
- * @param {!BlockSvg} block The block to measure.
51
- * @constructor
52
- * @package
53
55
  * @extends {BaseRenderInfo}
54
56
  * @alias Blockly.zelos.RenderInfo
55
57
  */
56
- const RenderInfo = function(renderer, block) {
57
- RenderInfo.superClass_.constructor.call(this, renderer, block);
58
-
58
+ class RenderInfo extends BaseRenderInfo {
59
59
  /**
60
- * An object with rendering information about the top row of the block.
61
- * @type {!TopRow}
62
- * @override
60
+ * @param {!Renderer} renderer The renderer in use.
61
+ * @param {!BlockSvg} block The block to measure.
62
+ * @package
63
63
  */
64
- this.topRow = new TopRow(this.constants_);
64
+ constructor(renderer, block) {
65
+ super(renderer, block);
66
+
67
+ /** @type {!ConstantProvider} */
68
+ this.constants_;
69
+
70
+ /**
71
+ * An object with rendering information about the top row of the block.
72
+ * @type {!TopRow}
73
+ * @override
74
+ */
75
+ this.topRow = new TopRow(this.constants_);
76
+
77
+ /**
78
+ * An object with rendering information about the bottom row of the block.
79
+ * @type {!BottomRow}
80
+ * @override
81
+ */
82
+ this.bottomRow = new BottomRow(this.constants_);
83
+
84
+ /**
85
+ * @override
86
+ */
87
+ this.isInline = true;
88
+
89
+ /**
90
+ * Whether the block should be rendered as a multi-line block, either
91
+ * because it's not inline or because it has been collapsed.
92
+ * @type {boolean}
93
+ */
94
+ this.isMultiRow = !block.getInputsInline() || block.isCollapsed();
95
+
96
+ /**
97
+ * Whether or not the block has a statement input in one of its rows.
98
+ * @type {boolean}
99
+ */
100
+ this.hasStatementInput = block.statementInputCount > 0;
101
+
102
+ /**
103
+ * An object with rendering information about the right connection shape.
104
+ * @type {RightConnectionShape}
105
+ */
106
+ this.rightSide = this.outputConnection ?
107
+ new RightConnectionShape(this.constants_) :
108
+ null;
109
+
110
+ /**
111
+ * A map of rows to right aligned dummy inputs within those rows. Used to
112
+ * add padding between left and right aligned inputs.
113
+ * @type {!WeakMap<!Row, !Input>}
114
+ * @private
115
+ */
116
+ this.rightAlignedDummyInputs_ = new WeakMap();
117
+ }
65
118
 
66
119
  /**
67
- * An object with rendering information about the bottom row of the block.
68
- * @type {!BottomRow}
69
- * @override
120
+ * Get the block renderer in use.
121
+ * @return {!Renderer} The block renderer in use.
122
+ * @package
70
123
  */
71
- this.bottomRow = new BottomRow(this.constants_);
124
+ getRenderer() {
125
+ return /** @type {!Renderer} */ (this.renderer_);
126
+ }
72
127
 
73
128
  /**
74
129
  * @override
75
130
  */
76
- this.isInline = true;
131
+ measure() {
132
+ // Modifying parent measure method to add `adjustXPosition_`.
133
+ this.createRows_();
134
+ this.addElemSpacing_();
135
+ this.addRowSpacing_();
136
+ this.adjustXPosition_();
137
+ this.computeBounds_();
138
+ this.alignRowElements_();
139
+ this.finalize_();
140
+ }
77
141
 
78
142
  /**
79
- * Whether the block should be rendered as a multi-line block, either because
80
- * it's not inline or because it has been collapsed.
81
- * @type {boolean}
143
+ * @override
82
144
  */
83
- this.isMultiRow = !block.getInputsInline() || block.isCollapsed();
145
+ shouldStartNewRow_(input, lastInput) {
146
+ // If this is the first input, just add to the existing row.
147
+ // That row is either empty or has some icons in it.
148
+ if (!lastInput) {
149
+ return false;
150
+ }
151
+ // A statement input or an input following one always gets a new row.
152
+ if (input.type === inputTypes.STATEMENT ||
153
+ lastInput.type === inputTypes.STATEMENT) {
154
+ return true;
155
+ }
156
+ // Value and dummy inputs get new row if inputs are not inlined.
157
+ if (input.type === inputTypes.VALUE || input.type === inputTypes.DUMMY) {
158
+ return !this.isInline || this.isMultiRow;
159
+ }
160
+ return false;
161
+ }
84
162
 
85
163
  /**
86
- * Whether or not the block has a statement input in one of its rows.
87
- * @type {boolean}
164
+ * @override
88
165
  */
89
- this.hasStatementInput = block.statementInputCount > 0;
166
+ getDesiredRowWidth_(row) {
167
+ if (row.hasStatement) {
168
+ const rightCornerWidth = this.constants_.INSIDE_CORNERS.rightWidth || 0;
169
+ return this.width - this.startX - rightCornerWidth;
170
+ }
171
+ return super.getDesiredRowWidth_(row);
172
+ }
90
173
 
91
174
  /**
92
- * An object with rendering information about the right connection shape.
93
- * @type {RightConnectionShape}
175
+ * @override
94
176
  */
95
- this.rightSide =
96
- this.outputConnection ? new RightConnectionShape(this.constants_) : null;
97
- };
98
- object.inherits(RenderInfo, BaseRenderInfo);
99
-
100
- /**
101
- * Get the block renderer in use.
102
- * @return {!Renderer} The block renderer in use.
103
- * @package
104
- */
105
- RenderInfo.prototype.getRenderer = function() {
106
- return /** @type {!Renderer} */ (this.renderer_);
107
- };
108
-
109
- /**
110
- * @override
111
- */
112
- RenderInfo.prototype.measure = function() {
113
- // Modifying parent measure method to add `adjustXPosition_`.
114
- this.createRows_();
115
- this.addElemSpacing_();
116
- this.addRowSpacing_();
117
- this.adjustXPosition_();
118
- this.computeBounds_();
119
- this.alignRowElements_();
120
- this.finalize_();
121
- };
122
-
123
- /**
124
- * @override
125
- */
126
- RenderInfo.prototype.shouldStartNewRow_ = function(input, lastInput) {
127
- // If this is the first input, just add to the existing row.
128
- // That row is either empty or has some icons in it.
129
- if (!lastInput) {
130
- return false;
131
- }
132
- // A statement input or an input following one always gets a new row.
133
- if (input.type === inputTypes.STATEMENT ||
134
- lastInput.type === inputTypes.STATEMENT) {
135
- return true;
136
- }
137
- // Value and dummy inputs get new row if inputs are not inlined.
138
- if (input.type === inputTypes.VALUE || input.type === inputTypes.DUMMY) {
139
- return !this.isInline || this.isMultiRow;
140
- }
141
- return false;
142
- };
143
-
144
-
145
- /**
146
- * @override
147
- */
148
- RenderInfo.prototype.getDesiredRowWidth_ = function(row) {
149
- if (row.hasStatement) {
150
- const rightCornerWidth = this.constants_.INSIDE_CORNERS.rightWidth || 0;
151
- return this.width - this.startX - rightCornerWidth;
152
- }
153
- return RenderInfo.superClass_.getDesiredRowWidth_.call(this, row);
154
- };
155
-
156
- /**
157
- * @override
158
- */
159
- RenderInfo.prototype.getInRowSpacing_ = function(prev, next) {
160
- if (!prev || !next) {
161
- // No need for padding at the beginning or end of the row if the
162
- // output shape is dynamic.
163
- if (this.outputConnection && this.outputConnection.isDynamicShape &&
164
- !this.hasStatementInput && !this.bottomRow.hasNextConnection) {
165
- return this.constants_.NO_PADDING;
177
+ getInRowSpacing_(prev, next) {
178
+ if (!prev || !next) {
179
+ // No need for padding at the beginning or end of the row if the
180
+ // output shape is dynamic.
181
+ if (this.outputConnection && this.outputConnection.isDynamicShape &&
182
+ !this.hasStatementInput && !this.bottomRow.hasNextConnection) {
183
+ return this.constants_.NO_PADDING;
184
+ }
166
185
  }
167
- }
168
- if (!prev) {
169
- // Statement input padding.
170
- if (next && Types.isStatementInput(next)) {
171
- return this.constants_.STATEMENT_INPUT_PADDING_LEFT;
186
+ if (!prev) {
187
+ // Statement input padding.
188
+ if (next && Types.isStatementInput(next)) {
189
+ return this.constants_.STATEMENT_INPUT_PADDING_LEFT;
190
+ }
172
191
  }
173
- }
174
- // Spacing between a rounded corner and a previous or next connection.
175
- if (prev && Types.isLeftRoundedCorner(prev) && next) {
176
- if (Types.isPreviousConnection(next) || Types.isNextConnection(next)) {
177
- return next.notchOffset - this.constants_.CORNER_RADIUS;
192
+ // Spacing between a rounded corner and a previous or next connection.
193
+ if (prev && Types.isLeftRoundedCorner(prev) && next) {
194
+ if (Types.isPreviousConnection(next) || Types.isNextConnection(next)) {
195
+ return next.notchOffset - this.constants_.CORNER_RADIUS;
196
+ }
178
197
  }
198
+ // Spacing between a square corner and a hat.
199
+ if (prev && Types.isLeftSquareCorner(prev) && next && Types.isHat(next)) {
200
+ return this.constants_.NO_PADDING;
201
+ }
202
+ return this.constants_.MEDIUM_PADDING;
179
203
  }
180
- // Spacing between a square corner and a hat.
181
- if (prev && Types.isLeftSquareCorner(prev) && next && Types.isHat(next)) {
182
- return this.constants_.NO_PADDING;
183
- }
184
- return this.constants_.MEDIUM_PADDING;
185
- };
186
204
 
187
- /**
188
- * @override
189
- */
190
- RenderInfo.prototype.getSpacerRowHeight_ = function(prev, next) {
191
- // If we have an empty block add a spacer to increase the height.
192
- if (Types.isTopRow(prev) && Types.isBottomRow(next)) {
193
- return this.constants_.EMPTY_BLOCK_SPACER_HEIGHT;
194
- }
195
- const followsStatement = Types.isInputRow(prev) && prev.hasStatement;
196
- const precedesStatement = Types.isInputRow(next) && next.hasStatement;
197
- if (precedesStatement || followsStatement) {
198
- const cornerHeight = this.constants_.INSIDE_CORNERS.rightHeight || 0;
199
- const height = Math.max(this.constants_.NOTCH_HEIGHT, cornerHeight);
200
- return precedesStatement && followsStatement ?
201
- Math.max(height, this.constants_.DUMMY_INPUT_MIN_HEIGHT) :
202
- height;
203
- }
204
- // Top and bottom rows act as a spacer so we don't need any extra padding.
205
- if (Types.isTopRow(prev)) {
206
- if (!prev.hasPreviousConnection &&
207
- (!this.outputConnection || this.hasStatementInput)) {
208
- return Math.abs(
209
- this.constants_.NOTCH_HEIGHT - this.constants_.CORNER_RADIUS);
205
+ /**
206
+ * @override
207
+ */
208
+ getSpacerRowHeight_(prev, next) {
209
+ // If we have an empty block add a spacer to increase the height.
210
+ if (Types.isTopRow(prev) && Types.isBottomRow(next)) {
211
+ return this.constants_.EMPTY_BLOCK_SPACER_HEIGHT;
210
212
  }
211
- return this.constants_.NO_PADDING;
212
- }
213
- if (Types.isBottomRow(next)) {
214
- if (!this.outputConnection) {
215
- const topHeight = Math.max(
216
- this.topRow.minHeight,
217
- Math.max(
218
- this.constants_.NOTCH_HEIGHT,
219
- this.constants_.CORNER_RADIUS)) -
220
- this.constants_.CORNER_RADIUS;
221
- return topHeight;
222
- } else if (!next.hasNextConnection && this.hasStatementInput) {
223
- return Math.abs(
224
- this.constants_.NOTCH_HEIGHT - this.constants_.CORNER_RADIUS);
213
+ const followsStatement = Types.isInputRow(prev) && prev.hasStatement;
214
+ const precedesStatement = Types.isInputRow(next) && next.hasStatement;
215
+ if (precedesStatement || followsStatement) {
216
+ const cornerHeight = this.constants_.INSIDE_CORNERS.rightHeight || 0;
217
+ const height = Math.max(this.constants_.NOTCH_HEIGHT, cornerHeight);
218
+ return precedesStatement && followsStatement ?
219
+ Math.max(height, this.constants_.DUMMY_INPUT_MIN_HEIGHT) :
220
+ height;
225
221
  }
226
- return this.constants_.NO_PADDING;
227
- }
228
- return this.constants_.MEDIUM_PADDING;
229
- };
230
-
231
- /**
232
- * @override
233
- */
234
- RenderInfo.prototype.getSpacerRowWidth_ = function(prev, next) {
235
- const width = this.width - this.startX;
236
- if ((Types.isInputRow(prev) && prev.hasStatement) ||
237
- (Types.isInputRow(next) && next.hasStatement)) {
238
- return Math.max(width, this.constants_.STATEMENT_INPUT_SPACER_MIN_WIDTH);
222
+ // Top and bottom rows act as a spacer so we don't need any extra padding.
223
+ if (Types.isTopRow(prev)) {
224
+ const topRow = /** @type {!TopRow} */ (prev);
225
+ if (!topRow.hasPreviousConnection &&
226
+ (!this.outputConnection || this.hasStatementInput)) {
227
+ return Math.abs(
228
+ this.constants_.NOTCH_HEIGHT - this.constants_.CORNER_RADIUS);
229
+ }
230
+ return this.constants_.NO_PADDING;
231
+ }
232
+ if (Types.isBottomRow(next)) {
233
+ const bottomRow = /** @type {!BottomRow} */ (next);
234
+ if (!this.outputConnection) {
235
+ const topHeight = Math.max(
236
+ this.topRow.minHeight,
237
+ Math.max(
238
+ this.constants_.NOTCH_HEIGHT,
239
+ this.constants_.CORNER_RADIUS)) -
240
+ this.constants_.CORNER_RADIUS;
241
+ return topHeight;
242
+ } else if (!bottomRow.hasNextConnection && this.hasStatementInput) {
243
+ return Math.abs(
244
+ this.constants_.NOTCH_HEIGHT - this.constants_.CORNER_RADIUS);
245
+ }
246
+ return this.constants_.NO_PADDING;
247
+ }
248
+ return this.constants_.MEDIUM_PADDING;
239
249
  }
240
- return width;
241
- };
242
250
 
243
- /**
244
- * @override
245
- */
246
- RenderInfo.prototype.getElemCenterline_ = function(row, elem) {
247
- if (row.hasStatement && !Types.isSpacer(elem) &&
248
- !Types.isStatementInput(elem)) {
249
- return row.yPos + this.constants_.EMPTY_STATEMENT_INPUT_HEIGHT / 2;
250
- }
251
- if (Types.isInlineInput(elem)) {
252
- const connectedBlock = elem.connectedBlock;
253
- if (connectedBlock && connectedBlock.outputConnection &&
254
- connectedBlock.nextConnection) {
255
- return row.yPos + connectedBlock.height / 2;
251
+ /**
252
+ * @override
253
+ */
254
+ getSpacerRowWidth_(prev, next) {
255
+ const width = this.width - this.startX;
256
+ if ((Types.isInputRow(prev) && prev.hasStatement) ||
257
+ (Types.isInputRow(next) && next.hasStatement)) {
258
+ return Math.max(width, this.constants_.STATEMENT_INPUT_SPACER_MIN_WIDTH);
256
259
  }
260
+ return width;
257
261
  }
258
- return RenderInfo.superClass_.getElemCenterline_.call(this, row, elem);
259
- };
260
262
 
261
- /**
262
- * @override
263
- */
264
- RenderInfo.prototype.addInput_ = function(input, activeRow) {
265
- // If we have two dummy inputs on the same row, one aligned left and the other
266
- // right, keep track of the right aligned dummy input so we can add padding
267
- // later.
268
- if (input.type === inputTypes.DUMMY && activeRow.hasDummyInput &&
269
- activeRow.align === Align.LEFT && input.align === Align.RIGHT) {
270
- activeRow.rightAlignedDummyInput = input;
271
- } else if (input.type === inputTypes.STATEMENT) {
272
- // Handle statements without next connections correctly.
273
- activeRow.elements.push(new StatementInput(this.constants_, input));
274
- activeRow.hasStatement = true;
275
-
276
- if (activeRow.align === null) {
277
- activeRow.align = input.align;
263
+ /**
264
+ * @override
265
+ */
266
+ getElemCenterline_(row, elem) {
267
+ if (row.hasStatement && !Types.isSpacer(elem) &&
268
+ !Types.isStatementInput(elem)) {
269
+ return row.yPos + this.constants_.EMPTY_STATEMENT_INPUT_HEIGHT / 2;
278
270
  }
279
- return;
271
+ if (Types.isInlineInput(elem) && elem instanceof InputConnection) {
272
+ const connectedBlock = elem.connectedBlock;
273
+ if (connectedBlock && connectedBlock.outputConnection &&
274
+ connectedBlock.nextConnection) {
275
+ return row.yPos + connectedBlock.height / 2;
276
+ }
277
+ }
278
+ return super.getElemCenterline_(row, elem);
280
279
  }
281
- RenderInfo.superClass_.addInput_.call(this, input, activeRow);
282
- };
283
280
 
284
- /**
285
- * @override
286
- */
287
- RenderInfo.prototype.addAlignmentPadding_ = function(row, missingSpace) {
288
- if (row.rightAlignedDummyInput) {
289
- let alignmentDivider;
290
- for (let i = 0; i < row.elements.length; i++) {
291
- const elem = row.elements[i];
292
- if (Types.isSpacer(elem)) {
293
- alignmentDivider = elem;
294
- }
295
- if (Types.isField(elem) &&
296
- elem.parentInput === row.rightAlignedDummyInput) {
297
- break;
281
+ /**
282
+ * @override
283
+ */
284
+ addInput_(input, activeRow) {
285
+ // If we have two dummy inputs on the same row, one aligned left and the
286
+ // other right, keep track of the right aligned dummy input so we can add
287
+ // padding later.
288
+ if (input.type === inputTypes.DUMMY && activeRow.hasDummyInput &&
289
+ activeRow.align === Align.LEFT && input.align === Align.RIGHT) {
290
+ this.rightAlignedDummyInputs_.set(activeRow, input);
291
+ } else if (input.type === inputTypes.STATEMENT) {
292
+ // Handle statements without next connections correctly.
293
+ activeRow.elements.push(new StatementInput(this.constants_, input));
294
+ activeRow.hasStatement = true;
295
+
296
+ if (activeRow.align === null) {
297
+ activeRow.align = input.align;
298
298
  }
299
- }
300
- if (alignmentDivider) {
301
- alignmentDivider.width += missingSpace;
302
- row.width += missingSpace;
303
299
  return;
304
300
  }
301
+ super.addInput_(input, activeRow);
305
302
  }
306
- RenderInfo.superClass_.addAlignmentPadding_.call(this, row, missingSpace);
307
- };
308
303
 
309
- /**
310
- * Adjust the x position of fields to bump all non-label fields in the first row
311
- * past the notch position. This must be called before ``computeBounds`` is
312
- * called.
313
- * @protected
314
- */
315
- RenderInfo.prototype.adjustXPosition_ = function() {
316
- const notchTotalWidth =
317
- this.constants_.NOTCH_OFFSET_LEFT + this.constants_.NOTCH_WIDTH;
318
- let minXPos = notchTotalWidth;
319
- // Run through every input row on the block and only apply bump logic to the
320
- // first input row (if the block has prev connection) and every input row that
321
- // has a prev and next notch.
322
- for (let i = 2; i < this.rows.length - 1; i += 2) {
323
- const prevSpacer = this.rows[i - 1];
324
- const row = this.rows[i];
325
- const nextSpacer = this.rows[i + 1];
326
-
327
- const hasPrevNotch = i === 2 ? !!this.topRow.hasPreviousConnection :
328
- !!prevSpacer.followsStatement;
329
- const hasNextNotch = i + 2 >= this.rows.length - 1 ?
330
- !!this.bottomRow.hasNextConnection :
331
- !!nextSpacer.precedesStatement;
332
-
333
- if (Types.isInputRow(row) && row.hasStatement) {
334
- row.measure();
335
- minXPos = row.width - row.getLastInput().width + notchTotalWidth;
336
- } else if (
337
- hasPrevNotch && (i === 2 || hasNextNotch) && Types.isInputRow(row) &&
338
- !row.hasStatement) {
339
- let xCursor = row.xPos;
340
- let prevInRowSpacer = null;
341
- for (let j = 0; j < row.elements.length; j++) {
342
- const elem = row.elements[j];
304
+ /**
305
+ * @override
306
+ */
307
+ addAlignmentPadding_(row, missingSpace) {
308
+ if (this.rightAlignedDummyInputs_.get(row)) {
309
+ let alignmentDivider;
310
+ for (let i = 0; i < row.elements.length; i++) {
311
+ const elem = row.elements[i];
343
312
  if (Types.isSpacer(elem)) {
344
- prevInRowSpacer = elem;
313
+ alignmentDivider = elem;
345
314
  }
346
- if (prevInRowSpacer && (Types.isField(elem) || Types.isInput(elem))) {
347
- if (xCursor < minXPos &&
348
- !(Types.isField(elem) &&
349
- (elem.field instanceof FieldLabel ||
350
- elem.field instanceof FieldImage))) {
351
- const difference = minXPos - xCursor;
352
- prevInRowSpacer.width += difference;
353
- }
315
+ if (Types.isField(elem) && elem instanceof Field &&
316
+ elem.parentInput === this.rightAlignedDummyInputs_.get(row)) {
317
+ break;
354
318
  }
355
- xCursor += elem.width;
319
+ }
320
+ if (alignmentDivider) {
321
+ alignmentDivider.width += missingSpace;
322
+ row.width += missingSpace;
323
+ return;
356
324
  }
357
325
  }
326
+ super.addAlignmentPadding_(row, missingSpace);
358
327
  }
359
- };
360
328
 
361
- /**
362
- * Finalize the output connection info. In particular, set the height of the
363
- * output connection to match that of the block. For the right side, add a
364
- * right connection shape element and have it match the dimensions of the
365
- * output connection.
366
- * @protected
367
- */
368
- RenderInfo.prototype.finalizeOutputConnection_ = function() {
369
- // Dynamic output connections depend on the height of the block.
370
- if (!this.outputConnection || !this.outputConnection.isDynamicShape) {
371
- return;
372
- }
373
- let yCursor = 0;
374
- // Determine the block height.
375
- for (let i = 0; i < this.rows.length; i++) {
376
- const row = this.rows[i];
377
- row.yPos = yCursor;
378
- yCursor += row.height;
379
- }
380
- this.height = yCursor;
381
-
382
- // Adjust the height of the output connection.
383
- const blockHeight = this.bottomRow.hasNextConnection ?
384
- this.height - this.bottomRow.descenderHeight :
385
- this.height;
386
- const connectionHeight = this.outputConnection.shape.height(blockHeight);
387
- const connectionWidth = this.outputConnection.shape.width(blockHeight);
388
-
389
- this.outputConnection.height = connectionHeight;
390
- this.outputConnection.width = connectionWidth;
391
- this.outputConnection.startX = connectionWidth;
392
- this.outputConnection.connectionOffsetY =
393
- this.outputConnection.shape.connectionOffsetY(connectionHeight);
394
- this.outputConnection.connectionOffsetX =
395
- this.outputConnection.shape.connectionOffsetX(connectionWidth);
396
-
397
- // Add the right connection measurable.
398
- // Don't add it if we have a value-to-statement or a value-to-stack block.
399
- let rightConnectionWidth = 0;
400
- if (!this.hasStatementInput && !this.bottomRow.hasNextConnection) {
401
- rightConnectionWidth = connectionWidth;
402
- this.rightSide.height = connectionHeight;
403
- this.rightSide.width = rightConnectionWidth;
404
- this.rightSide.centerline = connectionHeight / 2;
405
- this.rightSide.xPos = this.width + rightConnectionWidth;
329
+ /**
330
+ * Adjust the x position of fields to bump all non-label fields in the first
331
+ * row past the notch position. This must be called before ``computeBounds``
332
+ * is called.
333
+ * @protected
334
+ */
335
+ adjustXPosition_() {
336
+ const notchTotalWidth =
337
+ this.constants_.NOTCH_OFFSET_LEFT + this.constants_.NOTCH_WIDTH;
338
+ let minXPos = notchTotalWidth;
339
+ // Run through every input row on the block and only apply bump logic to the
340
+ // first input row (if the block has prev connection) and every input row
341
+ // that has a prev and next notch.
342
+ for (let i = 2; i < this.rows.length - 1; i += 2) {
343
+ const prevSpacer = /** @type {!SpacerRow} */ (this.rows[i - 1]);
344
+ const row = this.rows[i];
345
+ const nextSpacer = /** @type {!SpacerRow} */ (this.rows[i + 1]);
346
+
347
+ const hasPrevNotch = i === 2 ? !!this.topRow.hasPreviousConnection :
348
+ !!prevSpacer.followsStatement;
349
+ const hasNextNotch = i + 2 >= this.rows.length - 1 ?
350
+ !!this.bottomRow.hasNextConnection :
351
+ !!nextSpacer.precedesStatement;
352
+
353
+ if (Types.isInputRow(row) && row.hasStatement) {
354
+ row.measure();
355
+ minXPos = row.width - row.getLastInput().width + notchTotalWidth;
356
+ } else if (
357
+ hasPrevNotch && (i === 2 || hasNextNotch) && Types.isInputRow(row) &&
358
+ !row.hasStatement) {
359
+ let xCursor = row.xPos;
360
+ let prevInRowSpacer = null;
361
+ for (let j = 0; j < row.elements.length; j++) {
362
+ const elem = row.elements[j];
363
+ if (Types.isSpacer(elem)) {
364
+ prevInRowSpacer = elem;
365
+ }
366
+ if (prevInRowSpacer && (Types.isField(elem) || Types.isInput(elem))) {
367
+ if (xCursor < minXPos &&
368
+ !(Types.isField(elem) && elem instanceof Field &&
369
+ (elem.field instanceof FieldLabel ||
370
+ elem.field instanceof FieldImage))) {
371
+ const difference = minXPos - xCursor;
372
+ prevInRowSpacer.width += difference;
373
+ }
374
+ }
375
+ xCursor += elem.width;
376
+ }
377
+ }
378
+ }
406
379
  }
407
- this.startX = connectionWidth;
408
- this.width += connectionWidth + rightConnectionWidth;
409
- this.widthWithChildren += connectionWidth + rightConnectionWidth;
410
- };
411
380
 
412
- /**
413
- * Finalize horizontal alignment of elements on the block. In particular,
414
- * reduce the implicit spacing created by the left and right output connection
415
- * shapes by adding setting negative spacing onto the leftmost and rightmost
416
- * spacers.
417
- * @protected
418
- */
419
- RenderInfo.prototype.finalizeHorizontalAlignment_ = function() {
420
- if (!this.outputConnection || this.hasStatementInput ||
421
- this.bottomRow.hasNextConnection) {
422
- return;
423
- }
424
- let totalNegativeSpacing = 0;
425
- for (let i = 0; i < this.rows.length; i++) {
426
- const row = this.rows[i];
427
- if (!Types.isInputRow(row)) {
428
- continue;
381
+ /**
382
+ * Finalize the output connection info. In particular, set the height of the
383
+ * output connection to match that of the block. For the right side, add a
384
+ * right connection shape element and have it match the dimensions of the
385
+ * output connection.
386
+ * @protected
387
+ */
388
+ finalizeOutputConnection_() {
389
+ // Dynamic output connections depend on the height of the block.
390
+ if (!this.outputConnection || !this.outputConnection.isDynamicShape) {
391
+ return;
392
+ }
393
+ let yCursor = 0;
394
+ // Determine the block height.
395
+ for (let i = 0; i < this.rows.length; i++) {
396
+ const row = this.rows[i];
397
+ row.yPos = yCursor;
398
+ yCursor += row.height;
429
399
  }
430
- const firstElem = row.elements[1];
431
- const lastElem = row.elements[row.elements.length - 2];
432
- let leftNegPadding = this.getNegativeSpacing_(firstElem);
433
- let rightNegPadding = this.getNegativeSpacing_(lastElem);
434
- totalNegativeSpacing = leftNegPadding + rightNegPadding;
435
- const minBlockWidth =
436
- this.constants_.MIN_BLOCK_WIDTH + this.outputConnection.width * 2;
437
- if (this.width - totalNegativeSpacing < minBlockWidth) {
438
- // Maintain a minimum block width, split negative spacing between left
439
- // and right edge.
440
- totalNegativeSpacing = this.width - minBlockWidth;
441
- leftNegPadding = totalNegativeSpacing / 2;
442
- rightNegPadding = totalNegativeSpacing / 2;
400
+ this.height = yCursor;
401
+
402
+ // Adjust the height of the output connection.
403
+ const blockHeight = this.bottomRow.hasNextConnection ?
404
+ this.height - this.bottomRow.descenderHeight :
405
+ this.height;
406
+ const connectionHeight = this.outputConnection.shape.height(blockHeight);
407
+ const connectionWidth = this.outputConnection.shape.width(blockHeight);
408
+
409
+ this.outputConnection.height = connectionHeight;
410
+ this.outputConnection.width = connectionWidth;
411
+ this.outputConnection.startX = connectionWidth;
412
+ this.outputConnection.connectionOffsetY =
413
+ this.outputConnection.shape.connectionOffsetY(connectionHeight);
414
+ this.outputConnection.connectionOffsetX =
415
+ this.outputConnection.shape.connectionOffsetX(connectionWidth);
416
+
417
+ // Add the right connection measurable.
418
+ // Don't add it if we have a value-to-statement or a value-to-stack block.
419
+ let rightConnectionWidth = 0;
420
+ if (!this.hasStatementInput && !this.bottomRow.hasNextConnection) {
421
+ rightConnectionWidth = connectionWidth;
422
+ this.rightSide.height = connectionHeight;
423
+ this.rightSide.width = rightConnectionWidth;
424
+ this.rightSide.centerline = connectionHeight / 2;
425
+ this.rightSide.xPos = this.width + rightConnectionWidth;
443
426
  }
444
- // Add a negative spacer on the start and end of the block.
445
- row.elements.unshift(new InRowSpacer(this.constants_, -leftNegPadding));
446
- row.elements.push(new InRowSpacer(this.constants_, -rightNegPadding));
427
+ this.startX = connectionWidth;
428
+ this.width += connectionWidth + rightConnectionWidth;
429
+ this.widthWithChildren += connectionWidth + rightConnectionWidth;
447
430
  }
448
- if (totalNegativeSpacing) {
449
- this.width -= totalNegativeSpacing;
450
- this.widthWithChildren -= totalNegativeSpacing;
451
- this.rightSide.xPos -= totalNegativeSpacing;
431
+
432
+ /**
433
+ * Finalize horizontal alignment of elements on the block. In particular,
434
+ * reduce the implicit spacing created by the left and right output connection
435
+ * shapes by adding setting negative spacing onto the leftmost and rightmost
436
+ * spacers.
437
+ * @protected
438
+ */
439
+ finalizeHorizontalAlignment_() {
440
+ if (!this.outputConnection || this.hasStatementInput ||
441
+ this.bottomRow.hasNextConnection) {
442
+ return;
443
+ }
444
+ let totalNegativeSpacing = 0;
452
445
  for (let i = 0; i < this.rows.length; i++) {
453
446
  const row = this.rows[i];
454
- if (Types.isTopOrBottomRow(row)) {
455
- row.elements[1].width -= totalNegativeSpacing;
456
- row.elements[1].widthWithConnectedBlocks -= totalNegativeSpacing;
447
+ if (!Types.isInputRow(row)) {
448
+ continue;
457
449
  }
458
- row.width -= totalNegativeSpacing;
459
- row.widthWithConnectedBlocks -= totalNegativeSpacing;
450
+ const firstElem = row.elements[1];
451
+ const lastElem = row.elements[row.elements.length - 2];
452
+ let leftNegPadding = this.getNegativeSpacing_(firstElem);
453
+ let rightNegPadding = this.getNegativeSpacing_(lastElem);
454
+ totalNegativeSpacing = leftNegPadding + rightNegPadding;
455
+ const minBlockWidth =
456
+ this.constants_.MIN_BLOCK_WIDTH + this.outputConnection.width * 2;
457
+ if (this.width - totalNegativeSpacing < minBlockWidth) {
458
+ // Maintain a minimum block width, split negative spacing between left
459
+ // and right edge.
460
+ totalNegativeSpacing = this.width - minBlockWidth;
461
+ leftNegPadding = totalNegativeSpacing / 2;
462
+ rightNegPadding = totalNegativeSpacing / 2;
463
+ }
464
+ // Add a negative spacer on the start and end of the block.
465
+ row.elements.unshift(new InRowSpacer(this.constants_, -leftNegPadding));
466
+ row.elements.push(new InRowSpacer(this.constants_, -rightNegPadding));
460
467
  }
461
- }
462
- };
463
-
464
- /**
465
- * Calculate the spacing to reduce the left and right edges by based on the
466
- * outer and inner connection shape.
467
- * @param {Measurable} elem The first or last element on
468
- * a block.
469
- * @return {number} The amount of spacing to reduce the first or last spacer.
470
- * @protected
471
- */
472
- RenderInfo.prototype.getNegativeSpacing_ = function(elem) {
473
- if (!elem) {
474
- return 0;
475
- }
476
- const connectionWidth = this.outputConnection.width;
477
- const outerShape = this.outputConnection.shape.type;
478
- const constants =
479
- /** @type {!ConstantProvider} */ (this.constants_);
480
- if (this.isMultiRow && this.inputRows.length > 1) {
481
- switch (outerShape) {
482
- case constants.SHAPES.ROUND: {
483
- // Special case for multi-row round reporter blocks.
484
- const maxWidth = this.constants_.MAX_DYNAMIC_CONNECTION_SHAPE_WIDTH;
485
- const width = this.height / 2 > maxWidth ? maxWidth : this.height / 2;
486
- const topPadding = this.constants_.SMALL_PADDING;
487
- const roundPadding =
488
- width * (1 - Math.sin(Math.acos((width - topPadding) / width)));
489
- return connectionWidth - roundPadding;
468
+ if (totalNegativeSpacing) {
469
+ this.width -= totalNegativeSpacing;
470
+ this.widthWithChildren -= totalNegativeSpacing;
471
+ this.rightSide.xPos -= totalNegativeSpacing;
472
+ for (let i = 0; i < this.rows.length; i++) {
473
+ const row = this.rows[i];
474
+ if (Types.isTopOrBottomRow(row)) {
475
+ row.elements[1].width -= totalNegativeSpacing;
476
+ }
477
+ row.width -= totalNegativeSpacing;
478
+ row.widthWithConnectedBlocks -= totalNegativeSpacing;
490
479
  }
491
- default:
492
- return 0;
493
480
  }
494
481
  }
495
- if (Types.isInlineInput(elem)) {
496
- const connectedBlock = elem.connectedBlock;
497
- const innerShape = connectedBlock ?
498
- connectedBlock.pathObject.outputShapeType :
499
- elem.shape.type;
500
- // Special case for value to stack / value to statement blocks.
501
- if (connectedBlock && connectedBlock.outputConnection &&
502
- (connectedBlock.statementInputCount || connectedBlock.nextConnection)) {
482
+
483
+ /**
484
+ * Calculate the spacing to reduce the left and right edges by based on the
485
+ * outer and inner connection shape.
486
+ * @param {Measurable} elem The first or last element on
487
+ * a block.
488
+ * @return {number} The amount of spacing to reduce the first or last spacer.
489
+ * @protected
490
+ */
491
+ getNegativeSpacing_(elem) {
492
+ if (!elem) {
503
493
  return 0;
504
494
  }
505
- // Special case for hexagonal output.
506
- if (outerShape === constants.SHAPES.HEXAGONAL &&
507
- outerShape !== innerShape) {
508
- return 0;
495
+ const connectionWidth = this.outputConnection.width;
496
+ const outerShape = this.outputConnection.shape.type;
497
+ const constants =
498
+ /** @type {!ConstantProvider} */ (this.constants_);
499
+ if (this.isMultiRow && this.inputRows.length > 1) {
500
+ switch (outerShape) {
501
+ case constants.SHAPES.ROUND: {
502
+ // Special case for multi-row round reporter blocks.
503
+ const maxWidth = this.constants_.MAX_DYNAMIC_CONNECTION_SHAPE_WIDTH;
504
+ const width = this.height / 2 > maxWidth ? maxWidth : this.height / 2;
505
+ const topPadding = this.constants_.SMALL_PADDING;
506
+ const roundPadding =
507
+ width * (1 - Math.sin(Math.acos((width - topPadding) / width)));
508
+ return connectionWidth - roundPadding;
509
+ }
510
+ default:
511
+ return 0;
512
+ }
509
513
  }
510
- return connectionWidth -
511
- this.constants_.SHAPE_IN_SHAPE_PADDING[outerShape][innerShape];
512
- } else if (Types.isField(elem)) {
513
- // Special case for text inputs.
514
- if (outerShape === constants.SHAPES.ROUND &&
515
- elem.field instanceof FieldTextInput) {
516
- return connectionWidth - (2.75 * constants.GRID_UNIT);
514
+ if (Types.isInlineInput(elem) && elem instanceof InputConnection) {
515
+ const connectedBlock = elem.connectedBlock;
516
+ const innerShape = connectedBlock ?
517
+ connectedBlock.pathObject.outputShapeType :
518
+ elem.shape.type;
519
+ // Special case for value to stack / value to statement blocks.
520
+ if (connectedBlock && connectedBlock.outputConnection &&
521
+ (connectedBlock.statementInputCount ||
522
+ connectedBlock.nextConnection)) {
523
+ return 0;
524
+ }
525
+ // Special case for hexagonal output.
526
+ if (outerShape === constants.SHAPES.HEXAGONAL &&
527
+ outerShape !== innerShape) {
528
+ return 0;
529
+ }
530
+ return connectionWidth -
531
+ this.constants_.SHAPE_IN_SHAPE_PADDING[outerShape][innerShape];
532
+ } else if (Types.isField(elem) && elem instanceof Field) {
533
+ // Special case for text inputs.
534
+ if (outerShape === constants.SHAPES.ROUND &&
535
+ elem.field instanceof FieldTextInput) {
536
+ return connectionWidth - (2.75 * constants.GRID_UNIT);
537
+ }
538
+ return connectionWidth -
539
+ this.constants_.SHAPE_IN_SHAPE_PADDING[outerShape][0];
540
+ } else if (Types.isIcon(elem)) {
541
+ return this.constants_.SMALL_PADDING;
517
542
  }
518
- return connectionWidth -
519
- this.constants_.SHAPE_IN_SHAPE_PADDING[outerShape][0];
520
- } else if (Types.isIcon(elem)) {
521
- return this.constants_.SMALL_PADDING;
543
+ return 0;
522
544
  }
523
- return 0;
524
- };
525
545
 
526
- /**
527
- * Finalize vertical alignment of rows on a block. In particular, reduce the
528
- * implicit spacing when a non-shadow block is connected to any of an input
529
- * row's inline inputs.
530
- * @protected
531
- */
532
- RenderInfo.prototype.finalizeVerticalAlignment_ = function() {
533
- if (this.outputConnection) {
534
- return;
535
- }
536
- // Run through every input row on the block and only apply tight nesting logic
537
- // to input rows that have a prev and next notch.
538
- for (let i = 2; i < this.rows.length - 1; i += 2) {
539
- const prevSpacer = this.rows[i - 1];
540
- const row = this.rows[i];
541
- const nextSpacer = this.rows[i + 1];
542
-
543
- const firstRow = i === 2;
544
- const hasPrevNotch = firstRow ? !!this.topRow.hasPreviousConnection :
545
- !!prevSpacer.followsStatement;
546
- const hasNextNotch = i + 2 >= this.rows.length - 1 ?
547
- !!this.bottomRow.hasNextConnection :
548
- !!nextSpacer.precedesStatement;
549
-
550
- if (hasPrevNotch) {
551
- const hasSingleTextOrImageField = row.elements.length === 3 &&
552
- (row.elements[1].field instanceof FieldLabel ||
553
- row.elements[1].field instanceof FieldImage);
554
- if (!firstRow && hasSingleTextOrImageField) {
555
- // Remove some padding if we have a single image or text field.
556
- prevSpacer.height -= this.constants_.SMALL_PADDING;
557
- nextSpacer.height -= this.constants_.SMALL_PADDING;
558
- row.height -= this.constants_.MEDIUM_PADDING;
559
- } else if (!firstRow && !hasNextNotch) {
560
- // Add a small padding so the notch doesn't clash with inputs/fields.
561
- prevSpacer.height += this.constants_.SMALL_PADDING;
562
- } else if (hasNextNotch) {
563
- // Determine if the input row has non-shadow connected blocks.
564
- let hasNonShadowConnectedBlocks = false;
565
- const minVerticalTightNestingHeight = 40;
566
- for (let j = 0; j < row.elements.length; j++) {
567
- const elem = row.elements[j];
568
- if (Types.isInlineInput(elem) && elem.connectedBlock &&
569
- !elem.connectedBlock.isShadow() &&
570
- elem.connectedBlock.getHeightWidth().height >=
571
- minVerticalTightNestingHeight) {
572
- hasNonShadowConnectedBlocks = true;
573
- break;
574
- }
575
- }
576
- // Apply tight-nesting if we have both a prev and next notch and the
577
- // block has non-shadow connected blocks.
578
- if (hasNonShadowConnectedBlocks) {
546
+ /**
547
+ * Finalize vertical alignment of rows on a block. In particular, reduce the
548
+ * implicit spacing when a non-shadow block is connected to any of an input
549
+ * row's inline inputs.
550
+ * @protected
551
+ */
552
+ finalizeVerticalAlignment_() {
553
+ if (this.outputConnection) {
554
+ return;
555
+ }
556
+ // Run through every input row on the block and only apply tight nesting
557
+ // logic to input rows that have a prev and next notch.
558
+ for (let i = 2; i < this.rows.length - 1; i += 2) {
559
+ const prevSpacer = /** @type {!SpacerRow} */ (this.rows[i - 1]);
560
+ const row = this.rows[i];
561
+ const nextSpacer = /** @type {!SpacerRow} */ (this.rows[i + 1]);
562
+
563
+ const firstRow = i === 2;
564
+ const hasPrevNotch = firstRow ? !!this.topRow.hasPreviousConnection :
565
+ !!prevSpacer.followsStatement;
566
+ const hasNextNotch = i + 2 >= this.rows.length - 1 ?
567
+ !!this.bottomRow.hasNextConnection :
568
+ !!nextSpacer.precedesStatement;
569
+
570
+ if (hasPrevNotch) {
571
+ const elem = row.elements[1];
572
+ const hasSingleTextOrImageField = row.elements.length === 3 &&
573
+ elem instanceof Field &&
574
+ (elem.field instanceof FieldLabel ||
575
+ elem.field instanceof FieldImage);
576
+ if (!firstRow && hasSingleTextOrImageField) {
577
+ // Remove some padding if we have a single image or text field.
579
578
  prevSpacer.height -= this.constants_.SMALL_PADDING;
580
579
  nextSpacer.height -= this.constants_.SMALL_PADDING;
580
+ row.height -= this.constants_.MEDIUM_PADDING;
581
+ } else if (!firstRow && !hasNextNotch) {
582
+ // Add a small padding so the notch doesn't clash with inputs/fields.
583
+ prevSpacer.height += this.constants_.SMALL_PADDING;
584
+ } else if (hasNextNotch) {
585
+ // Determine if the input row has non-shadow connected blocks.
586
+ let hasNonShadowConnectedBlocks = false;
587
+ const minVerticalTightNestingHeight = 40;
588
+ for (let j = 0; j < row.elements.length; j++) {
589
+ const elem = row.elements[j];
590
+ if (elem instanceof InputConnection && Types.isInlineInput(elem) &&
591
+ elem.connectedBlock && !elem.connectedBlock.isShadow() &&
592
+ elem.connectedBlock.getHeightWidth().height >=
593
+ minVerticalTightNestingHeight) {
594
+ hasNonShadowConnectedBlocks = true;
595
+ break;
596
+ }
597
+ }
598
+ // Apply tight-nesting if we have both a prev and next notch and the
599
+ // block has non-shadow connected blocks.
600
+ if (hasNonShadowConnectedBlocks) {
601
+ prevSpacer.height -= this.constants_.SMALL_PADDING;
602
+ nextSpacer.height -= this.constants_.SMALL_PADDING;
603
+ }
581
604
  }
582
605
  }
583
606
  }
584
607
  }
585
- };
586
608
 
587
- /**
588
- * @override
589
- */
590
- RenderInfo.prototype.finalize_ = function() {
591
- this.finalizeOutputConnection_();
592
- this.finalizeHorizontalAlignment_();
593
- this.finalizeVerticalAlignment_();
594
- RenderInfo.superClass_.finalize_.call(this);
595
-
596
- if (this.rightSide) {
597
- this.widthWithChildren += this.rightSide.width;
609
+ /**
610
+ * @override
611
+ */
612
+ finalize_() {
613
+ this.finalizeOutputConnection_();
614
+ this.finalizeHorizontalAlignment_();
615
+ this.finalizeVerticalAlignment_();
616
+ super.finalize_();
617
+
618
+ if (this.rightSide) {
619
+ this.widthWithChildren += this.rightSide.width;
620
+ }
598
621
  }
599
- };
622
+ }
600
623
 
601
624
  exports.RenderInfo = RenderInfo;