blockly 7.20211209.4 → 8.0.1
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.
- package/blockly.d.ts +18963 -18432
- package/blockly.min.js +5 -4
- package/blockly_compressed.js +4 -3
- package/blockly_compressed.js.map +1 -1
- package/blocks/blocks.js +47 -0
- package/blocks/colour.js +13 -3
- package/blocks/lists.js +22 -13
- package/blocks/logic.js +13 -3
- package/blocks/loops.js +24 -11
- package/blocks/math.js +12 -3
- package/blocks/procedures.js +45 -32
- package/blocks/text.js +22 -13
- package/blocks/variables.js +14 -3
- package/blocks/variables_dynamic.js +13 -3
- package/blocks_compressed.js +1 -1
- package/blocks_compressed.js.map +1 -1
- package/core/block.js +1869 -1814
- package/core/block_drag_surface.js +201 -200
- package/core/block_dragger.js +377 -373
- package/core/block_svg.js +1593 -1479
- package/core/blockly.js +8 -22
- package/core/blocks.js +9 -2
- package/core/browser_events.js +22 -5
- package/core/bubble.js +841 -797
- package/core/bubble_dragger.js +213 -206
- package/core/bump_objects.js +2 -2
- package/core/clipboard.js +9 -9
- package/core/comment.js +353 -332
- package/core/common.js +46 -17
- package/core/component_manager.js +181 -174
- package/core/config.js +87 -0
- package/core/connection.js +595 -584
- package/core/connection_checker.js +242 -244
- package/core/connection_db.js +235 -230
- package/core/contextmenu.js +9 -6
- package/core/contextmenu_items.js +1 -2
- package/core/contextmenu_registry.js +93 -89
- package/core/css.js +474 -474
- package/core/delete_area.js +45 -42
- package/core/drag_target.js +57 -56
- package/core/dropdowndiv.js +153 -163
- package/core/events/events.js +2 -2
- package/core/events/events_abstract.js +89 -77
- package/core/events/events_block_base.js +37 -36
- package/core/events/events_block_change.js +130 -124
- package/core/events/events_block_create.js +73 -71
- package/core/events/events_block_delete.js +84 -82
- package/core/events/events_block_drag.js +50 -49
- package/core/events/events_block_move.js +147 -140
- package/core/events/events_bubble_open.js +51 -50
- package/core/events/events_click.js +48 -44
- package/core/events/events_comment_base.js +72 -69
- package/core/events/events_comment_change.js +63 -61
- package/core/events/events_comment_create.js +44 -42
- package/core/events/events_comment_delete.js +42 -40
- package/core/events/events_comment_move.js +106 -104
- package/core/events/events_marker_move.js +65 -64
- package/core/events/events_selected.js +46 -45
- package/core/events/events_theme_change.js +36 -35
- package/core/events/events_toolbox_item_select.js +46 -45
- package/core/events/events_trashcan_open.js +37 -36
- package/core/events/events_ui.js +47 -46
- package/core/events/events_ui_base.js +30 -29
- package/core/events/events_var_base.js +37 -36
- package/core/events/events_var_create.js +50 -48
- package/core/events/events_var_delete.js +50 -48
- package/core/events/events_var_rename.js +51 -49
- package/core/events/events_viewport.js +66 -65
- package/core/events/utils.js +29 -14
- package/core/events/workspace_events.js +49 -55
- package/core/extensions.js +4 -3
- package/core/field.js +1061 -997
- package/core/field_angle.js +462 -442
- package/core/field_checkbox.js +194 -182
- package/core/field_colour.js +519 -505
- package/core/field_dropdown.js +617 -598
- package/core/field_image.js +229 -220
- package/core/field_label.js +102 -91
- package/core/field_label_serializable.js +42 -41
- package/core/field_multilineinput.js +372 -358
- package/core/field_number.js +272 -253
- package/core/field_textinput.js +499 -467
- package/core/field_variable.js +458 -420
- package/core/flyout_base.js +1005 -952
- package/core/flyout_button.js +277 -260
- package/core/flyout_horizontal.js +304 -302
- package/core/flyout_metrics_manager.js +64 -64
- package/core/flyout_vertical.js +306 -300
- package/core/generator.js +459 -446
- package/core/gesture.js +829 -813
- package/core/grid.js +166 -163
- package/core/icon.js +168 -159
- package/core/inject.js +7 -5
- package/core/input.js +257 -248
- package/core/insertion_marker_manager.js +655 -624
- package/core/internal_constants.js +0 -129
- package/core/keyboard_nav/ast_node.js +605 -596
- package/core/keyboard_nav/basic_cursor.js +166 -165
- package/core/keyboard_nav/cursor.js +99 -97
- package/core/keyboard_nav/marker.js +83 -79
- package/core/keyboard_nav/tab_navigate_cursor.js +18 -23
- package/core/marker_manager.js +153 -141
- package/core/menu.js +377 -372
- package/core/menuitem.js +223 -217
- package/core/metrics_manager.js +403 -390
- package/core/mutator.js +468 -437
- package/core/names.js +229 -188
- package/core/options.js +290 -284
- package/core/procedures.js +29 -17
- package/core/registry.js +19 -16
- package/core/rendered_connection.js +482 -463
- package/core/renderers/common/block_rendering.js +9 -3
- package/core/renderers/common/constants.js +1119 -1112
- package/core/renderers/common/debug.js +14 -0
- package/core/renderers/common/debugger.js +338 -316
- package/core/renderers/common/drawer.js +380 -370
- package/core/renderers/common/i_path_object.js +2 -2
- package/core/renderers/common/info.js +626 -618
- package/core/renderers/common/marker_svg.js +579 -541
- package/core/renderers/common/path_object.js +203 -200
- package/core/renderers/common/renderer.js +220 -218
- package/core/renderers/geras/constants.js +36 -36
- package/core/renderers/geras/drawer.js +155 -147
- package/core/renderers/geras/highlight_constants.js +244 -238
- package/core/renderers/geras/highlighter.js +231 -179
- package/core/renderers/geras/info.js +392 -369
- package/core/renderers/geras/measurables/inline_input.js +25 -19
- package/core/renderers/geras/measurables/statement_input.js +23 -17
- package/core/renderers/geras/path_object.js +106 -121
- package/core/renderers/geras/renderer.js +96 -98
- package/core/renderers/measurables/base.js +30 -18
- package/core/renderers/measurables/bottom_row.js +83 -80
- package/core/renderers/measurables/connection.js +22 -15
- package/core/renderers/measurables/external_value_input.js +35 -22
- package/core/renderers/measurables/field.js +35 -20
- package/core/renderers/measurables/hat.js +18 -13
- package/core/renderers/measurables/icon.js +24 -17
- package/core/renderers/measurables/in_row_spacer.js +15 -13
- package/core/renderers/measurables/inline_input.js +43 -33
- package/core/renderers/measurables/input_connection.js +41 -28
- package/core/renderers/measurables/input_row.js +50 -44
- package/core/renderers/measurables/jagged_edge.js +14 -12
- package/core/renderers/measurables/next_connection.js +16 -14
- package/core/renderers/measurables/output_connection.js +26 -20
- package/core/renderers/measurables/previous_connection.js +16 -15
- package/core/renderers/measurables/round_corner.js +20 -18
- package/core/renderers/measurables/row.js +184 -168
- package/core/renderers/measurables/spacer_row.js +38 -23
- package/core/renderers/measurables/square_corner.js +18 -16
- package/core/renderers/measurables/statement_input.js +23 -20
- package/core/renderers/measurables/top_row.js +88 -85
- package/core/renderers/minimalist/constants.js +8 -7
- package/core/renderers/minimalist/drawer.js +11 -10
- package/core/renderers/minimalist/info.js +18 -18
- package/core/renderers/minimalist/renderer.js +40 -39
- package/core/renderers/thrasos/info.js +258 -248
- package/core/renderers/thrasos/renderer.js +20 -20
- package/core/renderers/zelos/constants.js +898 -873
- package/core/renderers/zelos/drawer.js +186 -169
- package/core/renderers/zelos/info.js +502 -479
- package/core/renderers/zelos/marker_svg.js +129 -115
- package/core/renderers/zelos/measurables/bottom_row.js +31 -30
- package/core/renderers/zelos/measurables/inputs.js +22 -21
- package/core/renderers/zelos/measurables/row_elements.js +14 -13
- package/core/renderers/zelos/measurables/top_row.js +34 -33
- package/core/renderers/zelos/path_object.js +181 -180
- package/core/renderers/zelos/renderer.js +91 -92
- package/core/scrollbar.js +759 -713
- package/core/scrollbar_pair.js +250 -245
- package/core/serialization/blocks.js +26 -10
- package/core/serialization/workspaces.js +3 -2
- package/core/shortcut_registry.js +286 -277
- package/core/sprites.js +31 -0
- package/core/theme.js +135 -141
- package/core/theme_manager.js +147 -143
- package/core/toolbox/category.js +602 -576
- package/core/toolbox/collapsible_category.js +226 -227
- package/core/toolbox/separator.js +70 -61
- package/core/toolbox/toolbox.js +934 -927
- package/core/toolbox/toolbox_item.js +115 -99
- package/core/tooltip.js +108 -35
- package/core/touch.js +8 -3
- package/core/touch_gesture.js +254 -251
- package/core/trashcan.js +606 -595
- package/core/utils/coordinate.js +97 -95
- package/core/utils/dom.js +2 -2
- package/core/utils/global.js +2 -0
- package/core/utils/rect.js +41 -37
- package/core/utils/sentinel.js +25 -0
- package/core/utils/size.js +30 -27
- package/core/utils/svg.js +18 -16
- package/core/variable_map.js +325 -341
- package/core/variable_model.js +55 -54
- package/core/variables.js +9 -2
- package/core/variables_dynamic.js +3 -1
- package/core/warning.js +126 -120
- package/core/widgetdiv.js +4 -4
- package/core/workspace.js +685 -664
- package/core/workspace_audio.js +124 -118
- package/core/workspace_comment.js +308 -298
- package/core/workspace_comment_svg.js +1029 -951
- package/core/workspace_drag_surface_svg.js +147 -140
- package/core/workspace_dragger.js +70 -71
- package/core/workspace_svg.js +2322 -2297
- package/core/xml.js +30 -20
- package/core/zoom_controls.js +431 -439
- package/generators/dart/colour.js +56 -64
- package/generators/dart/lists.js +61 -50
- package/generators/dart/math.js +160 -148
- package/generators/dart/text.js +83 -61
- package/generators/javascript/colour.js +37 -34
- package/generators/javascript/lists.js +50 -43
- package/generators/javascript/math.js +123 -139
- package/generators/javascript/text.js +67 -81
- package/generators/lua/colour.js +25 -23
- package/generators/lua/lists.js +97 -69
- package/generators/lua/logic.js +1 -2
- package/generators/lua/math.js +182 -144
- package/generators/lua/text.js +116 -99
- package/generators/php/colour.js +38 -32
- package/generators/php/lists.js +109 -89
- package/generators/php/math.js +90 -81
- package/generators/php/text.js +63 -61
- package/generators/python/colour.js +18 -18
- package/generators/python/lists.js +38 -30
- package/generators/python/loops.js +12 -8
- package/generators/python/math.js +104 -106
- package/generators/python/text.js +34 -30
- package/msg/smn.js +436 -0
- package/package.json +7 -6
- package/blocks/all.js +0 -23
package/core/mutator.js
CHANGED
|
@@ -17,14 +17,12 @@
|
|
|
17
17
|
*/
|
|
18
18
|
goog.module('Blockly.Mutator');
|
|
19
19
|
|
|
20
|
-
/* eslint-disable-next-line no-unused-vars */
|
|
21
|
-
const Abstract = goog.requireType('Blockly.Events.Abstract');
|
|
22
20
|
const dom = goog.require('Blockly.utils.dom');
|
|
23
21
|
const eventUtils = goog.require('Blockly.Events.utils');
|
|
24
|
-
const internalConstants = goog.require('Blockly.internalConstants');
|
|
25
|
-
const object = goog.require('Blockly.utils.object');
|
|
26
22
|
const toolbox = goog.require('Blockly.utils.toolbox');
|
|
27
23
|
const xml = goog.require('Blockly.utils.xml');
|
|
24
|
+
/* eslint-disable-next-line no-unused-vars */
|
|
25
|
+
const {Abstract} = goog.requireType('Blockly.Events.Abstract');
|
|
28
26
|
const {BlockChange} = goog.require('Blockly.Events.BlockChange');
|
|
29
27
|
/* eslint-disable-next-line no-unused-vars */
|
|
30
28
|
const {BlockSvg} = goog.requireType('Blockly.BlockSvg');
|
|
@@ -33,6 +31,7 @@ const {BlocklyOptions} = goog.requireType('Blockly.BlocklyOptions');
|
|
|
33
31
|
/* eslint-disable-next-line no-unused-vars */
|
|
34
32
|
const {Block} = goog.requireType('Blockly.Block');
|
|
35
33
|
const {Bubble} = goog.require('Blockly.Bubble');
|
|
34
|
+
const {config} = goog.require('Blockly.config');
|
|
36
35
|
/* eslint-disable-next-line no-unused-vars */
|
|
37
36
|
const {Connection} = goog.requireType('Blockly.Connection');
|
|
38
37
|
/* eslint-disable-next-line no-unused-vars */
|
|
@@ -41,504 +40,536 @@ const {Icon} = goog.require('Blockly.Icon');
|
|
|
41
40
|
const {Options} = goog.require('Blockly.Options');
|
|
42
41
|
const {Svg} = goog.require('Blockly.utils.Svg');
|
|
43
42
|
const {WorkspaceSvg} = goog.require('Blockly.WorkspaceSvg');
|
|
44
|
-
/* eslint-disable-next-line no-unused-vars */
|
|
45
|
-
const {Workspace} = goog.requireType('Blockly.Workspace');
|
|
46
43
|
/** @suppress {extraRequire} */
|
|
47
44
|
goog.require('Blockly.Events.BubbleOpen');
|
|
48
45
|
|
|
49
46
|
|
|
50
47
|
/**
|
|
51
48
|
* Class for a mutator dialog.
|
|
52
|
-
* @param {!Array<string>} quarkNames List of names of sub-blocks for flyout.
|
|
53
49
|
* @extends {Icon}
|
|
54
|
-
* @constructor
|
|
55
50
|
* @alias Blockly.Mutator
|
|
56
51
|
*/
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
* Width of workspace.
|
|
72
|
-
* @private
|
|
73
|
-
*/
|
|
74
|
-
Mutator.prototype.workspaceWidth_ = 0;
|
|
52
|
+
class Mutator extends Icon {
|
|
53
|
+
/**
|
|
54
|
+
* @param {!Array<string>} quarkNames List of names of sub-blocks for flyout.
|
|
55
|
+
*/
|
|
56
|
+
constructor(quarkNames) {
|
|
57
|
+
super(null);
|
|
58
|
+
this.quarkNames_ = quarkNames;
|
|
59
|
+
|
|
60
|
+
/**
|
|
61
|
+
* Workspace in the mutator's bubble.
|
|
62
|
+
* @type {?WorkspaceSvg}
|
|
63
|
+
* @private
|
|
64
|
+
*/
|
|
65
|
+
this.workspace_ = null;
|
|
75
66
|
|
|
76
|
-
/**
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
67
|
+
/**
|
|
68
|
+
* Width of workspace.
|
|
69
|
+
* @type {number}
|
|
70
|
+
* @private
|
|
71
|
+
*/
|
|
72
|
+
this.workspaceWidth_ = 0;
|
|
81
73
|
|
|
82
|
-
/**
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
this.block_ = block;
|
|
89
|
-
};
|
|
74
|
+
/**
|
|
75
|
+
* Height of workspace.
|
|
76
|
+
* @type {number}
|
|
77
|
+
* @private
|
|
78
|
+
*/
|
|
79
|
+
this.workspaceHeight_ = 0;
|
|
90
80
|
|
|
91
|
-
/**
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
return this.workspace_;
|
|
99
|
-
};
|
|
81
|
+
/**
|
|
82
|
+
* The SVG element that is the parent of the mutator workspace, or null if
|
|
83
|
+
* not created.
|
|
84
|
+
* @type {?SVGSVGElement}
|
|
85
|
+
* @private
|
|
86
|
+
*/
|
|
87
|
+
this.svgDialog_ = null;
|
|
100
88
|
|
|
101
|
-
/**
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
dom.createSvgElement(
|
|
109
|
-
Svg.RECT, {
|
|
110
|
-
'class': 'blocklyIconShape',
|
|
111
|
-
'rx': '4',
|
|
112
|
-
'ry': '4',
|
|
113
|
-
'height': '16',
|
|
114
|
-
'width': '16',
|
|
115
|
-
},
|
|
116
|
-
group);
|
|
117
|
-
// Gear teeth.
|
|
118
|
-
dom.createSvgElement(
|
|
119
|
-
Svg.PATH, {
|
|
120
|
-
'class': 'blocklyIconSymbol',
|
|
121
|
-
'd': 'm4.203,7.296 0,1.368 -0.92,0.677 -0.11,0.41 0.9,1.559 0.41,' +
|
|
122
|
-
'0.11 1.043,-0.457 1.187,0.683 0.127,1.134 0.3,0.3 1.8,0 0.3,' +
|
|
123
|
-
'-0.299 0.127,-1.138 1.185,-0.682 1.046,0.458 0.409,-0.11 0.9,' +
|
|
124
|
-
'-1.559 -0.11,-0.41 -0.92,-0.677 0,-1.366 0.92,-0.677 0.11,' +
|
|
125
|
-
'-0.41 -0.9,-1.559 -0.409,-0.109 -1.046,0.458 -1.185,-0.682 ' +
|
|
126
|
-
'-0.127,-1.138 -0.3,-0.299 -1.8,0 -0.3,0.3 -0.126,1.135 -1.187,' +
|
|
127
|
-
'0.682 -1.043,-0.457 -0.41,0.11 -0.899,1.559 0.108,0.409z',
|
|
128
|
-
},
|
|
129
|
-
group);
|
|
130
|
-
// Axle hole.
|
|
131
|
-
dom.createSvgElement(
|
|
132
|
-
Svg.CIRCLE,
|
|
133
|
-
{'class': 'blocklyIconShape', 'r': '2.7', 'cx': '8', 'cy': '8'}, group);
|
|
134
|
-
};
|
|
89
|
+
/**
|
|
90
|
+
* The root block of the mutator workspace, created by decomposing the
|
|
91
|
+
* source block.
|
|
92
|
+
* @type {?BlockSvg}
|
|
93
|
+
* @private
|
|
94
|
+
*/
|
|
95
|
+
this.rootBlock_ = null;
|
|
135
96
|
|
|
136
|
-
/**
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
Mutator.prototype.iconClick_ = function(e) {
|
|
144
|
-
if (this.block_.isEditable()) {
|
|
145
|
-
Icon.prototype.iconClick_.call(this, e);
|
|
97
|
+
/**
|
|
98
|
+
* Function registered on the main workspace to update the mutator contents
|
|
99
|
+
* when the main workspace changes.
|
|
100
|
+
* @type {?Function}
|
|
101
|
+
* @private
|
|
102
|
+
*/
|
|
103
|
+
this.sourceListener_ = null;
|
|
146
104
|
}
|
|
147
|
-
};
|
|
148
105
|
|
|
149
|
-
/**
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
<svg>
|
|
157
|
-
[Workspace]
|
|
158
|
-
</svg>
|
|
159
|
-
*/
|
|
160
|
-
this.svgDialog_ = dom.createSvgElement(
|
|
161
|
-
Svg.SVG, {'x': Bubble.BORDER_WIDTH, 'y': Bubble.BORDER_WIDTH}, null);
|
|
162
|
-
// Convert the list of names into a list of XML objects for the flyout.
|
|
163
|
-
let quarkXml;
|
|
164
|
-
if (this.quarkNames_.length) {
|
|
165
|
-
quarkXml = xml.createElement('xml');
|
|
166
|
-
for (let i = 0, quarkName; (quarkName = this.quarkNames_[i]); i++) {
|
|
167
|
-
const element = xml.createElement('block');
|
|
168
|
-
element.setAttribute('type', quarkName);
|
|
169
|
-
quarkXml.appendChild(element);
|
|
170
|
-
}
|
|
171
|
-
} else {
|
|
172
|
-
quarkXml = null;
|
|
173
|
-
}
|
|
174
|
-
const workspaceOptions = new Options(
|
|
175
|
-
/** @type {!BlocklyOptions} */
|
|
176
|
-
({
|
|
177
|
-
// If you want to enable disabling, also remove the
|
|
178
|
-
// event filter from workspaceChanged_ .
|
|
179
|
-
'disable': false,
|
|
180
|
-
'parentWorkspace': this.block_.workspace,
|
|
181
|
-
'media': this.block_.workspace.options.pathToMedia,
|
|
182
|
-
'rtl': this.block_.RTL,
|
|
183
|
-
'horizontalLayout': false,
|
|
184
|
-
'renderer': this.block_.workspace.options.renderer,
|
|
185
|
-
'rendererOverrides': this.block_.workspace.options.rendererOverrides,
|
|
186
|
-
}));
|
|
187
|
-
workspaceOptions.toolboxPosition =
|
|
188
|
-
this.block_.RTL ? toolbox.Position.RIGHT : toolbox.Position.LEFT;
|
|
189
|
-
const hasFlyout = !!quarkXml;
|
|
190
|
-
if (hasFlyout) {
|
|
191
|
-
workspaceOptions.languageTree = toolbox.convertToolboxDefToJson(quarkXml);
|
|
106
|
+
/**
|
|
107
|
+
* Set the block this mutator is associated with.
|
|
108
|
+
* @param {!BlockSvg} block The block associated with this mutator.
|
|
109
|
+
* @package
|
|
110
|
+
*/
|
|
111
|
+
setBlock(block) {
|
|
112
|
+
this.block_ = block;
|
|
192
113
|
}
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
const background = this.workspace_.createDom('blocklyMutatorBackground');
|
|
203
|
-
|
|
204
|
-
if (flyoutSvg) {
|
|
205
|
-
// Insert the flyout after the <rect> but before the block canvas so that
|
|
206
|
-
// the flyout is underneath in z-order. This makes blocks layering during
|
|
207
|
-
// dragging work properly.
|
|
208
|
-
background.insertBefore(flyoutSvg, this.workspace_.svgBlockCanvas_);
|
|
114
|
+
|
|
115
|
+
/**
|
|
116
|
+
* Returns the workspace inside this mutator icon's bubble.
|
|
117
|
+
* @return {?WorkspaceSvg} The workspace inside this mutator icon's
|
|
118
|
+
* bubble or null if the mutator isn't open.
|
|
119
|
+
* @package
|
|
120
|
+
*/
|
|
121
|
+
getWorkspace() {
|
|
122
|
+
return this.workspace_;
|
|
209
123
|
}
|
|
210
|
-
this.svgDialog_.appendChild(background);
|
|
211
124
|
|
|
212
|
-
|
|
213
|
-
|
|
125
|
+
/**
|
|
126
|
+
* Draw the mutator icon.
|
|
127
|
+
* @param {!Element} group The icon group.
|
|
128
|
+
* @protected
|
|
129
|
+
*/
|
|
130
|
+
drawIcon_(group) {
|
|
131
|
+
// Square with rounded corners.
|
|
132
|
+
dom.createSvgElement(
|
|
133
|
+
Svg.RECT, {
|
|
134
|
+
'class': 'blocklyIconShape',
|
|
135
|
+
'rx': '4',
|
|
136
|
+
'ry': '4',
|
|
137
|
+
'height': '16',
|
|
138
|
+
'width': '16',
|
|
139
|
+
},
|
|
140
|
+
group);
|
|
141
|
+
// Gear teeth.
|
|
142
|
+
dom.createSvgElement(
|
|
143
|
+
Svg.PATH, {
|
|
144
|
+
'class': 'blocklyIconSymbol',
|
|
145
|
+
'd': 'm4.203,7.296 0,1.368 -0.92,0.677 -0.11,0.41 0.9,1.559 0.41,' +
|
|
146
|
+
'0.11 1.043,-0.457 1.187,0.683 0.127,1.134 0.3,0.3 1.8,0 0.3,' +
|
|
147
|
+
'-0.299 0.127,-1.138 1.185,-0.682 1.046,0.458 0.409,-0.11 0.9,' +
|
|
148
|
+
'-1.559 -0.11,-0.41 -0.92,-0.677 0,-1.366 0.92,-0.677 0.11,' +
|
|
149
|
+
'-0.41 -0.9,-1.559 -0.409,-0.109 -1.046,0.458 -1.185,-0.682 ' +
|
|
150
|
+
'-0.127,-1.138 -0.3,-0.299 -1.8,0 -0.3,0.3 -0.126,1.135 -1.187,' +
|
|
151
|
+
'0.682 -1.043,-0.457 -0.41,0.11 -0.899,1.559 0.108,0.409z',
|
|
152
|
+
},
|
|
153
|
+
group);
|
|
154
|
+
// Axle hole.
|
|
155
|
+
dom.createSvgElement(
|
|
156
|
+
Svg.CIRCLE,
|
|
157
|
+
{'class': 'blocklyIconShape', 'r': '2.7', 'cx': '8', 'cy': '8'}, group);
|
|
158
|
+
}
|
|
214
159
|
|
|
215
|
-
/**
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
160
|
+
/**
|
|
161
|
+
* Clicking on the icon toggles if the mutator bubble is visible.
|
|
162
|
+
* Disable if block is uneditable.
|
|
163
|
+
* @param {!Event} e Mouse click event.
|
|
164
|
+
* @protected
|
|
165
|
+
* @override
|
|
166
|
+
*/
|
|
167
|
+
iconClick_(e) {
|
|
221
168
|
if (this.block_.isEditable()) {
|
|
222
|
-
|
|
223
|
-
dom.removeClass(
|
|
224
|
-
/** @type {!Element} */ (this.iconGroup_),
|
|
225
|
-
'blocklyIconGroupReadonly');
|
|
226
|
-
}
|
|
227
|
-
} else {
|
|
228
|
-
// Close any mutator bubble. Icon is not clickable.
|
|
229
|
-
this.setVisible(false);
|
|
230
|
-
if (this.iconGroup_) {
|
|
231
|
-
dom.addClass(
|
|
232
|
-
/** @type {!Element} */ (this.iconGroup_),
|
|
233
|
-
'blocklyIconGroupReadonly');
|
|
234
|
-
}
|
|
169
|
+
Icon.prototype.iconClick_.call(this, e);
|
|
235
170
|
}
|
|
236
171
|
}
|
|
237
|
-
};
|
|
238
172
|
|
|
239
|
-
/**
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
173
|
+
/**
|
|
174
|
+
* Create the editor for the mutator's bubble.
|
|
175
|
+
* @return {!SVGElement} The top-level node of the editor.
|
|
176
|
+
* @private
|
|
177
|
+
*/
|
|
178
|
+
createEditor_() {
|
|
179
|
+
/* Create the editor. Here's the markup that will be generated:
|
|
180
|
+
<svg>
|
|
181
|
+
[Workspace]
|
|
182
|
+
</svg>
|
|
183
|
+
*/
|
|
184
|
+
this.svgDialog_ = dom.createSvgElement(
|
|
185
|
+
Svg.SVG, {'x': Bubble.BORDER_WIDTH, 'y': Bubble.BORDER_WIDTH}, null);
|
|
186
|
+
// Convert the list of names into a list of XML objects for the flyout.
|
|
187
|
+
let quarkXml;
|
|
188
|
+
if (this.quarkNames_.length) {
|
|
189
|
+
quarkXml = xml.createElement('xml');
|
|
190
|
+
for (let i = 0, quarkName; (quarkName = this.quarkNames_[i]); i++) {
|
|
191
|
+
const element = xml.createElement('block');
|
|
192
|
+
element.setAttribute('type', quarkName);
|
|
193
|
+
quarkXml.appendChild(element);
|
|
194
|
+
}
|
|
195
|
+
} else {
|
|
196
|
+
quarkXml = null;
|
|
197
|
+
}
|
|
198
|
+
const workspaceOptions = new Options(
|
|
199
|
+
/** @type {!BlocklyOptions} */
|
|
200
|
+
({
|
|
201
|
+
// If you want to enable disabling, also remove the
|
|
202
|
+
// event filter from workspaceChanged_ .
|
|
203
|
+
'disable': false,
|
|
204
|
+
'parentWorkspace': this.block_.workspace,
|
|
205
|
+
'media': this.block_.workspace.options.pathToMedia,
|
|
206
|
+
'rtl': this.block_.RTL,
|
|
207
|
+
'horizontalLayout': false,
|
|
208
|
+
'renderer': this.block_.workspace.options.renderer,
|
|
209
|
+
'rendererOverrides': this.block_.workspace.options.rendererOverrides,
|
|
210
|
+
}));
|
|
211
|
+
workspaceOptions.toolboxPosition =
|
|
212
|
+
this.block_.RTL ? toolbox.Position.RIGHT : toolbox.Position.LEFT;
|
|
213
|
+
const hasFlyout = !!quarkXml;
|
|
214
|
+
if (hasFlyout) {
|
|
215
|
+
workspaceOptions.languageTree = toolbox.convertToolboxDefToJson(quarkXml);
|
|
216
|
+
}
|
|
217
|
+
this.workspace_ = new WorkspaceSvg(workspaceOptions);
|
|
218
|
+
this.workspace_.isMutator = true;
|
|
219
|
+
this.workspace_.addChangeListener(eventUtils.disableOrphans);
|
|
220
|
+
|
|
221
|
+
// Mutator flyouts go inside the mutator workspace's <g> rather than in
|
|
222
|
+
// a top level SVG. Instead of handling scale themselves, mutators
|
|
223
|
+
// inherit scale from the parent workspace.
|
|
224
|
+
// To fix this, scale needs to be applied at a different level in the DOM.
|
|
225
|
+
const flyoutSvg = hasFlyout ? this.workspace_.addFlyout(Svg.G) : null;
|
|
226
|
+
const background = this.workspace_.createDom('blocklyMutatorBackground');
|
|
227
|
+
|
|
228
|
+
if (flyoutSvg) {
|
|
229
|
+
// Insert the flyout after the <rect> but before the block canvas so that
|
|
230
|
+
// the flyout is underneath in z-order. This makes blocks layering during
|
|
231
|
+
// dragging work properly.
|
|
232
|
+
background.insertBefore(flyoutSvg, this.workspace_.svgBlockCanvas_);
|
|
233
|
+
}
|
|
234
|
+
this.svgDialog_.appendChild(background);
|
|
273
235
|
|
|
274
|
-
|
|
275
|
-
// Scroll the workspace to always left-align.
|
|
276
|
-
const translation = 'translate(' + this.workspaceWidth_ + ',0)';
|
|
277
|
-
this.workspace_.getCanvas().setAttribute('transform', translation);
|
|
236
|
+
return this.svgDialog_;
|
|
278
237
|
}
|
|
279
|
-
this.workspace_.resize();
|
|
280
|
-
};
|
|
281
238
|
|
|
282
|
-
/**
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
239
|
+
/**
|
|
240
|
+
* Add or remove the UI indicating if this icon may be clicked or not.
|
|
241
|
+
*/
|
|
242
|
+
updateEditable() {
|
|
243
|
+
super.updateEditable();
|
|
244
|
+
if (!this.block_.isInFlyout) {
|
|
245
|
+
if (this.block_.isEditable()) {
|
|
246
|
+
if (this.iconGroup_) {
|
|
247
|
+
dom.removeClass(
|
|
248
|
+
/** @type {!Element} */ (this.iconGroup_),
|
|
249
|
+
'blocklyIconGroupReadonly');
|
|
250
|
+
}
|
|
251
|
+
} else {
|
|
252
|
+
// Close any mutator bubble. Icon is not clickable.
|
|
253
|
+
this.setVisible(false);
|
|
254
|
+
if (this.iconGroup_) {
|
|
255
|
+
dom.addClass(
|
|
256
|
+
/** @type {!Element} */ (this.iconGroup_),
|
|
257
|
+
'blocklyIconGroupReadonly');
|
|
258
|
+
}
|
|
259
|
+
}
|
|
260
|
+
}
|
|
289
261
|
}
|
|
290
|
-
};
|
|
291
262
|
|
|
292
|
-
/**
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
eventUtils.fire(new (eventUtils.get(eventUtils.BUBBLE_OPEN))(
|
|
302
|
-
this.block_, visible, 'mutator'));
|
|
303
|
-
if (visible) {
|
|
304
|
-
// Create the bubble.
|
|
305
|
-
this.bubble_ = new Bubble(
|
|
306
|
-
/** @type {!WorkspaceSvg} */ (this.block_.workspace),
|
|
307
|
-
this.createEditor_(), this.block_.pathObject.svgPath,
|
|
308
|
-
/** @type {!Coordinate} */ (this.iconXY_), null, null);
|
|
309
|
-
// Expose this mutator's block's ID on its top-level SVG group.
|
|
310
|
-
this.bubble_.setSvgId(this.block_.id);
|
|
311
|
-
this.bubble_.registerMoveEvent(this.onBubbleMove_.bind(this));
|
|
312
|
-
const tree = this.workspace_.options.languageTree;
|
|
263
|
+
/**
|
|
264
|
+
* Resize the bubble to match the size of the workspace.
|
|
265
|
+
* @private
|
|
266
|
+
*/
|
|
267
|
+
resizeBubble_() {
|
|
268
|
+
const doubleBorderWidth = 2 * Bubble.BORDER_WIDTH;
|
|
269
|
+
const workspaceSize = this.workspace_.getCanvas().getBBox();
|
|
270
|
+
let width = workspaceSize.width + workspaceSize.x;
|
|
271
|
+
let height = workspaceSize.height + doubleBorderWidth * 3;
|
|
313
272
|
const flyout = this.workspace_.getFlyout();
|
|
314
|
-
if (tree) {
|
|
315
|
-
flyout.init(this.workspace_);
|
|
316
|
-
flyout.show(tree);
|
|
317
|
-
}
|
|
318
|
-
|
|
319
|
-
this.rootBlock_ = this.block_.decompose(this.workspace_);
|
|
320
|
-
const blocks = this.rootBlock_.getDescendants(false);
|
|
321
|
-
for (let i = 0, child; (child = blocks[i]); i++) {
|
|
322
|
-
child.render();
|
|
323
|
-
}
|
|
324
|
-
// The root block should not be draggable or deletable.
|
|
325
|
-
this.rootBlock_.setMovable(false);
|
|
326
|
-
this.rootBlock_.setDeletable(false);
|
|
327
|
-
let margin;
|
|
328
|
-
let x;
|
|
329
273
|
if (flyout) {
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
x = margin;
|
|
274
|
+
const flyoutScrollMetrics =
|
|
275
|
+
flyout.getWorkspace().getMetricsManager().getScrollMetrics();
|
|
276
|
+
height = Math.max(height, flyoutScrollMetrics.height + 20);
|
|
277
|
+
width += flyout.getWidth();
|
|
335
278
|
}
|
|
336
279
|
if (this.block_.RTL) {
|
|
337
|
-
|
|
280
|
+
width = -workspaceSize.x;
|
|
338
281
|
}
|
|
339
|
-
|
|
340
|
-
//
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
this.
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
282
|
+
width += doubleBorderWidth * 3;
|
|
283
|
+
// Only resize if the size difference is significant. Eliminates
|
|
284
|
+
// shuddering.
|
|
285
|
+
if (Math.abs(this.workspaceWidth_ - width) > doubleBorderWidth ||
|
|
286
|
+
Math.abs(this.workspaceHeight_ - height) > doubleBorderWidth) {
|
|
287
|
+
// Record some layout information for workspace metrics.
|
|
288
|
+
this.workspaceWidth_ = width;
|
|
289
|
+
this.workspaceHeight_ = height;
|
|
290
|
+
// Resize the bubble.
|
|
291
|
+
this.bubble_.setBubbleSize(
|
|
292
|
+
width + doubleBorderWidth, height + doubleBorderWidth);
|
|
293
|
+
this.svgDialog_.setAttribute('width', this.workspaceWidth_);
|
|
294
|
+
this.svgDialog_.setAttribute('height', this.workspaceHeight_);
|
|
295
|
+
this.workspace_.setCachedParentSvgSize(
|
|
296
|
+
this.workspaceWidth_, this.workspaceHeight_);
|
|
350
297
|
}
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
this.applyColour();
|
|
357
|
-
} else {
|
|
358
|
-
// Dispose of the bubble.
|
|
359
|
-
this.svgDialog_ = null;
|
|
360
|
-
this.workspace_.dispose();
|
|
361
|
-
this.workspace_ = null;
|
|
362
|
-
this.rootBlock_ = null;
|
|
363
|
-
this.bubble_.dispose();
|
|
364
|
-
this.bubble_ = null;
|
|
365
|
-
this.workspaceWidth_ = 0;
|
|
366
|
-
this.workspaceHeight_ = 0;
|
|
367
|
-
if (this.sourceListener_) {
|
|
368
|
-
this.block_.workspace.removeChangeListener(this.sourceListener_);
|
|
369
|
-
this.sourceListener_ = null;
|
|
298
|
+
|
|
299
|
+
if (this.block_.RTL) {
|
|
300
|
+
// Scroll the workspace to always left-align.
|
|
301
|
+
const translation = 'translate(' + this.workspaceWidth_ + ',0)';
|
|
302
|
+
this.workspace_.getCanvas().setAttribute('transform', translation);
|
|
370
303
|
}
|
|
304
|
+
this.workspace_.resize();
|
|
371
305
|
}
|
|
372
|
-
};
|
|
373
306
|
|
|
374
|
-
/**
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
e.type === eventUtils.CREATE)) {
|
|
383
|
-
this.updateWorkspace_();
|
|
307
|
+
/**
|
|
308
|
+
* A method handler for when the bubble is moved.
|
|
309
|
+
* @private
|
|
310
|
+
*/
|
|
311
|
+
onBubbleMove_() {
|
|
312
|
+
if (this.workspace_) {
|
|
313
|
+
this.workspace_.recordDragTargets();
|
|
314
|
+
}
|
|
384
315
|
}
|
|
385
|
-
};
|
|
386
316
|
|
|
387
|
-
/**
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
317
|
+
/**
|
|
318
|
+
* Show or hide the mutator bubble.
|
|
319
|
+
* @param {boolean} visible True if the bubble should be visible.
|
|
320
|
+
*/
|
|
321
|
+
setVisible(visible) {
|
|
322
|
+
if (visible === this.isVisible()) {
|
|
323
|
+
// No change.
|
|
324
|
+
return;
|
|
325
|
+
}
|
|
326
|
+
eventUtils.fire(new (eventUtils.get(eventUtils.BUBBLE_OPEN))(
|
|
327
|
+
this.block_, visible, 'mutator'));
|
|
328
|
+
if (visible) {
|
|
329
|
+
// Create the bubble.
|
|
330
|
+
this.bubble_ = new Bubble(
|
|
331
|
+
/** @type {!WorkspaceSvg} */ (this.block_.workspace),
|
|
332
|
+
this.createEditor_(), this.block_.pathObject.svgPath,
|
|
333
|
+
/** @type {!Coordinate} */ (this.iconXY_), null, null);
|
|
334
|
+
// Expose this mutator's block's ID on its top-level SVG group.
|
|
335
|
+
this.bubble_.setSvgId(this.block_.id);
|
|
336
|
+
this.bubble_.registerMoveEvent(this.onBubbleMove_.bind(this));
|
|
337
|
+
const tree = this.workspace_.options.languageTree;
|
|
338
|
+
const flyout = this.workspace_.getFlyout();
|
|
339
|
+
if (tree) {
|
|
340
|
+
flyout.init(this.workspace_);
|
|
341
|
+
flyout.show(tree);
|
|
342
|
+
}
|
|
399
343
|
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
344
|
+
this.rootBlock_ = this.block_.decompose(this.workspace_);
|
|
345
|
+
const blocks = this.rootBlock_.getDescendants(false);
|
|
346
|
+
for (let i = 0, child; (child = blocks[i]); i++) {
|
|
347
|
+
child.render();
|
|
403
348
|
}
|
|
404
|
-
//
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
349
|
+
// The root block should not be draggable or deletable.
|
|
350
|
+
this.rootBlock_.setMovable(false);
|
|
351
|
+
this.rootBlock_.setDeletable(false);
|
|
352
|
+
let margin;
|
|
353
|
+
let x;
|
|
354
|
+
if (flyout) {
|
|
355
|
+
margin = flyout.CORNER_RADIUS * 2;
|
|
356
|
+
x = this.rootBlock_.RTL ? flyout.getWidth() + margin : margin;
|
|
357
|
+
} else {
|
|
358
|
+
margin = 16;
|
|
359
|
+
x = margin;
|
|
360
|
+
}
|
|
361
|
+
if (this.block_.RTL) {
|
|
362
|
+
x = -x;
|
|
363
|
+
}
|
|
364
|
+
this.rootBlock_.moveBy(x, margin);
|
|
365
|
+
// Save the initial connections, then listen for further changes.
|
|
366
|
+
if (this.block_.saveConnections) {
|
|
367
|
+
const thisRootBlock = this.rootBlock_;
|
|
368
|
+
this.block_.saveConnections(thisRootBlock);
|
|
369
|
+
this.sourceListener_ = () => {
|
|
370
|
+
if (this.block_) {
|
|
371
|
+
this.block_.saveConnections(thisRootBlock);
|
|
372
|
+
}
|
|
373
|
+
};
|
|
374
|
+
this.block_.workspace.addChangeListener(this.sourceListener_);
|
|
375
|
+
}
|
|
376
|
+
this.resizeBubble_();
|
|
377
|
+
// When the mutator's workspace changes, update the source block.
|
|
378
|
+
this.workspace_.addChangeListener(this.workspaceChanged_.bind(this));
|
|
379
|
+
// Update the source block immediately after the bubble becomes visible.
|
|
380
|
+
this.updateWorkspace_();
|
|
381
|
+
this.applyColour();
|
|
382
|
+
} else {
|
|
383
|
+
// Dispose of the bubble.
|
|
384
|
+
this.svgDialog_ = null;
|
|
385
|
+
this.workspace_.dispose();
|
|
386
|
+
this.workspace_ = null;
|
|
387
|
+
this.rootBlock_ = null;
|
|
388
|
+
this.bubble_.dispose();
|
|
389
|
+
this.bubble_ = null;
|
|
390
|
+
this.workspaceWidth_ = 0;
|
|
391
|
+
this.workspaceHeight_ = 0;
|
|
392
|
+
if (this.sourceListener_) {
|
|
393
|
+
this.block_.workspace.removeChangeListener(this.sourceListener_);
|
|
394
|
+
this.sourceListener_ = null;
|
|
416
395
|
}
|
|
417
396
|
}
|
|
418
397
|
}
|
|
419
398
|
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
// Allow the source block to rebuild itself.
|
|
432
|
-
block.compose(this.rootBlock_);
|
|
433
|
-
// Restore rendering and show the changes.
|
|
434
|
-
block.rendered = savedRendered;
|
|
435
|
-
// Mutation may have added some elements that need initializing.
|
|
436
|
-
block.initSvg();
|
|
437
|
-
|
|
438
|
-
if (block.rendered) {
|
|
439
|
-
block.render();
|
|
440
|
-
}
|
|
441
|
-
|
|
442
|
-
const newExtraState = BlockChange.getExtraBlockState_(block);
|
|
443
|
-
if (oldExtraState !== newExtraState) {
|
|
444
|
-
eventUtils.fire(new (eventUtils.get(eventUtils.BLOCK_CHANGE))(
|
|
445
|
-
block, 'mutation', null, oldExtraState, newExtraState));
|
|
446
|
-
// Ensure that any bump is part of this mutation's event group.
|
|
447
|
-
const group = eventUtils.getGroup();
|
|
448
|
-
setTimeout(function() {
|
|
449
|
-
eventUtils.setGroup(group);
|
|
450
|
-
block.bumpNeighbours();
|
|
451
|
-
eventUtils.setGroup(false);
|
|
452
|
-
}, internalConstants.BUMP_DELAY);
|
|
399
|
+
/**
|
|
400
|
+
* Fired whenever a change is made to the mutator's workspace.
|
|
401
|
+
* @param {!Abstract} e Custom data for event.
|
|
402
|
+
* @private
|
|
403
|
+
*/
|
|
404
|
+
workspaceChanged_(e) {
|
|
405
|
+
if (!(e.isUiEvent ||
|
|
406
|
+
(e.type === eventUtils.CHANGE &&
|
|
407
|
+
/** @type {!BlockChange} */ (e).element === 'disabled') ||
|
|
408
|
+
e.type === eventUtils.CREATE)) {
|
|
409
|
+
this.updateWorkspace_();
|
|
453
410
|
}
|
|
411
|
+
}
|
|
454
412
|
|
|
455
|
-
|
|
456
|
-
|
|
413
|
+
/**
|
|
414
|
+
* Updates the source block when the mutator's blocks are changed.
|
|
415
|
+
* Bump down any block that's too high.
|
|
416
|
+
* @private
|
|
417
|
+
*/
|
|
418
|
+
updateWorkspace_() {
|
|
457
419
|
if (!this.workspace_.isDragging()) {
|
|
458
|
-
this.
|
|
420
|
+
const blocks = this.workspace_.getTopBlocks(false);
|
|
421
|
+
const MARGIN = 20;
|
|
422
|
+
|
|
423
|
+
for (let b = 0, block; (block = blocks[b]); b++) {
|
|
424
|
+
const blockXY = block.getRelativeToSurfaceXY();
|
|
425
|
+
|
|
426
|
+
// Bump any block that's above the top back inside.
|
|
427
|
+
if (blockXY.y < MARGIN) {
|
|
428
|
+
block.moveBy(0, MARGIN - blockXY.y);
|
|
429
|
+
}
|
|
430
|
+
// Bump any block overlapping the flyout back inside.
|
|
431
|
+
if (block.RTL) {
|
|
432
|
+
let right = -MARGIN;
|
|
433
|
+
const flyout = this.workspace_.getFlyout();
|
|
434
|
+
if (flyout) {
|
|
435
|
+
right -= flyout.getWidth();
|
|
436
|
+
}
|
|
437
|
+
if (blockXY.x > right) {
|
|
438
|
+
block.moveBy(right - blockXY.x, 0);
|
|
439
|
+
}
|
|
440
|
+
} else if (blockXY.x < MARGIN) {
|
|
441
|
+
block.moveBy(MARGIN - blockXY.x, 0);
|
|
442
|
+
}
|
|
443
|
+
}
|
|
459
444
|
}
|
|
460
|
-
eventUtils.setGroup(false);
|
|
461
|
-
}
|
|
462
|
-
};
|
|
463
445
|
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
};
|
|
446
|
+
// When the mutator's workspace changes, update the source block.
|
|
447
|
+
if (this.rootBlock_.workspace === this.workspace_) {
|
|
448
|
+
const existingGroup = eventUtils.getGroup();
|
|
449
|
+
if (!existingGroup) {
|
|
450
|
+
eventUtils.setGroup(true);
|
|
451
|
+
}
|
|
452
|
+
const block = /** @type {!BlockSvg} */ (this.block_);
|
|
453
|
+
const oldExtraState = BlockChange.getExtraBlockState_(block);
|
|
454
|
+
|
|
455
|
+
// Switch off rendering while the source block is rebuilt.
|
|
456
|
+
const savedRendered = block.rendered;
|
|
457
|
+
// TODO(#4288): We should not be setting the rendered property to false.
|
|
458
|
+
block.rendered = false;
|
|
459
|
+
|
|
460
|
+
// Allow the source block to rebuild itself.
|
|
461
|
+
block.compose(this.rootBlock_);
|
|
462
|
+
// Restore rendering and show the changes.
|
|
463
|
+
block.rendered = savedRendered;
|
|
464
|
+
// Mutation may have added some elements that need initializing.
|
|
465
|
+
block.initSvg();
|
|
466
|
+
|
|
467
|
+
if (block.rendered) {
|
|
468
|
+
block.render();
|
|
469
|
+
}
|
|
471
470
|
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
471
|
+
const newExtraState = BlockChange.getExtraBlockState_(block);
|
|
472
|
+
if (oldExtraState !== newExtraState) {
|
|
473
|
+
eventUtils.fire(new (eventUtils.get(eventUtils.BLOCK_CHANGE))(
|
|
474
|
+
block, 'mutation', null, oldExtraState, newExtraState));
|
|
475
|
+
// Ensure that any bump is part of this mutation's event group.
|
|
476
|
+
const mutationGroup = eventUtils.getGroup();
|
|
477
|
+
setTimeout(function() {
|
|
478
|
+
const oldGroup = eventUtils.getGroup();
|
|
479
|
+
eventUtils.setGroup(mutationGroup);
|
|
480
|
+
block.bumpNeighbours();
|
|
481
|
+
eventUtils.setGroup(oldGroup);
|
|
482
|
+
}, config.bumpDelay);
|
|
483
|
+
}
|
|
478
484
|
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
485
|
+
// Don't update the bubble until the drag has ended, to avoid moving
|
|
486
|
+
// blocks under the cursor.
|
|
487
|
+
if (!this.workspace_.isDragging()) {
|
|
488
|
+
this.resizeBubble_();
|
|
489
|
+
}
|
|
490
|
+
eventUtils.setGroup(existingGroup);
|
|
483
491
|
}
|
|
492
|
+
}
|
|
484
493
|
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
494
|
+
/**
|
|
495
|
+
* Dispose of this mutator.
|
|
496
|
+
*/
|
|
497
|
+
dispose() {
|
|
498
|
+
this.block_.mutator = null;
|
|
499
|
+
Icon.prototype.dispose.call(this);
|
|
500
|
+
}
|
|
501
|
+
|
|
502
|
+
/**
|
|
503
|
+
* Update the styles on all blocks in the mutator.
|
|
504
|
+
* @public
|
|
505
|
+
*/
|
|
506
|
+
updateBlockStyle() {
|
|
507
|
+
const ws = this.workspace_;
|
|
508
|
+
|
|
509
|
+
if (ws && ws.getAllBlocks(false)) {
|
|
510
|
+
const workspaceBlocks = ws.getAllBlocks(false);
|
|
511
|
+
for (let i = 0, block; (block = workspaceBlocks[i]); i++) {
|
|
489
512
|
block.setStyle(block.getStyleName());
|
|
490
513
|
}
|
|
514
|
+
|
|
515
|
+
const flyout = ws.getFlyout();
|
|
516
|
+
if (flyout) {
|
|
517
|
+
const flyoutBlocks = flyout.workspace_.getAllBlocks(false);
|
|
518
|
+
for (let i = 0, block; (block = flyoutBlocks[i]); i++) {
|
|
519
|
+
block.setStyle(block.getStyleName());
|
|
520
|
+
}
|
|
521
|
+
}
|
|
491
522
|
}
|
|
492
523
|
}
|
|
493
|
-
};
|
|
494
524
|
|
|
495
|
-
/**
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
525
|
+
/**
|
|
526
|
+
* Reconnect an block to a mutated input.
|
|
527
|
+
* @param {Connection} connectionChild Connection on child block.
|
|
528
|
+
* @param {!Block} block Parent block.
|
|
529
|
+
* @param {string} inputName Name of input on parent block.
|
|
530
|
+
* @return {boolean} True iff a reconnection was made, false otherwise.
|
|
531
|
+
*/
|
|
532
|
+
static reconnect(connectionChild, block, inputName) {
|
|
533
|
+
if (!connectionChild || !connectionChild.getSourceBlock().workspace) {
|
|
534
|
+
return false; // No connection or block has been deleted.
|
|
535
|
+
}
|
|
536
|
+
const connectionParent = block.getInput(inputName).connection;
|
|
537
|
+
const currentParent = connectionChild.targetBlock();
|
|
538
|
+
if ((!currentParent || currentParent === block) &&
|
|
539
|
+
connectionParent.targetConnection !== connectionChild) {
|
|
540
|
+
if (connectionParent.isConnected()) {
|
|
541
|
+
// There's already something connected here. Get rid of it.
|
|
542
|
+
connectionParent.disconnect();
|
|
543
|
+
}
|
|
544
|
+
connectionParent.connect(connectionChild);
|
|
545
|
+
return true;
|
|
513
546
|
}
|
|
514
|
-
|
|
515
|
-
return true;
|
|
547
|
+
return false;
|
|
516
548
|
}
|
|
517
|
-
return false;
|
|
518
|
-
};
|
|
519
549
|
|
|
520
|
-
/**
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
550
|
+
/**
|
|
551
|
+
* Get the parent workspace of a workspace that is inside a mutator, taking
|
|
552
|
+
* into account whether it is a flyout.
|
|
553
|
+
* @param {WorkspaceSvg} workspace The workspace that is inside a mutator.
|
|
554
|
+
* @return {?WorkspaceSvg} The mutator's parent workspace or null.
|
|
555
|
+
* @public
|
|
556
|
+
*/
|
|
557
|
+
static findParentWs(workspace) {
|
|
558
|
+
let outerWs = null;
|
|
559
|
+
if (workspace && workspace.options) {
|
|
560
|
+
const parent = workspace.options.parentWorkspace;
|
|
561
|
+
// If we were in a flyout in a mutator, need to go up two levels to find
|
|
562
|
+
// the actual parent.
|
|
563
|
+
if (workspace.isFlyout) {
|
|
564
|
+
if (parent && parent.options) {
|
|
565
|
+
outerWs = parent.options.parentWorkspace;
|
|
566
|
+
}
|
|
567
|
+
} else if (parent) {
|
|
568
|
+
outerWs = parent;
|
|
536
569
|
}
|
|
537
|
-
} else if (parent) {
|
|
538
|
-
outerWs = parent;
|
|
539
570
|
}
|
|
571
|
+
return outerWs;
|
|
540
572
|
}
|
|
541
|
-
|
|
542
|
-
};
|
|
573
|
+
}
|
|
543
574
|
|
|
544
575
|
exports.Mutator = Mutator;
|