blockly 7.20211209.2 → 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.
- package/blockly.d.ts +18963 -18432
- package/blockly.min.js +852 -844
- package/blockly_compressed.js +669 -664
- 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 +41 -27
- package/blocks/text.js +22 -13
- package/blocks/variables.js +14 -3
- package/blocks/variables_dynamic.js +13 -3
- package/blocks_compressed.js +146 -141
- 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 +19 -9
- 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/dart_compressed.js +40 -43
- package/dart_compressed.js.map +1 -1
- 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/javascript_compressed.js +37 -39
- package/javascript_compressed.js.map +1 -1
- package/lua_compressed.js +39 -42
- package/lua_compressed.js.map +1 -1
- package/msg/az.js +2 -2
- package/msg/be.js +4 -4
- package/msg/cs.js +15 -15
- package/msg/de.js +1 -1
- package/msg/diq.js +1 -1
- package/msg/eo.js +1 -1
- package/msg/es.js +1 -1
- package/msg/fa.js +1 -1
- package/msg/fr.js +4 -4
- package/msg/he.js +1 -1
- package/msg/hr.js +2 -2
- package/msg/hy.js +2 -2
- package/msg/id.js +12 -12
- package/msg/inh.js +14 -14
- package/msg/ja.js +7 -7
- package/msg/lv.js +29 -29
- package/msg/pa.js +3 -3
- package/msg/smn.js +436 -0
- package/msg/te.js +1 -1
- package/msg/yue.js +1 -1
- package/msg/zh-hans.js +3 -3
- package/msg/zh-hant.js +3 -3
- package/package.json +7 -6
- package/php_compressed.js +38 -42
- package/php_compressed.js.map +1 -1
- package/python_compressed.js +26 -25
- package/python_compressed.js.map +1 -1
- package/blocks/all.js +0 -23
package/core/toolbox/toolbox.js
CHANGED
|
@@ -22,7 +22,6 @@ const browserEvents = goog.require('Blockly.browserEvents');
|
|
|
22
22
|
const common = goog.require('Blockly.common');
|
|
23
23
|
const dom = goog.require('Blockly.utils.dom');
|
|
24
24
|
const eventUtils = goog.require('Blockly.Events.utils');
|
|
25
|
-
const object = goog.require('Blockly.utils.object');
|
|
26
25
|
const registry = goog.require('Blockly.registry');
|
|
27
26
|
const toolbox = goog.require('Blockly.utils.toolbox');
|
|
28
27
|
const {BlockSvg} = goog.require('Blockly.BlockSvg');
|
|
@@ -63,9 +62,6 @@ goog.require('Blockly.Events.ToolboxItemSelect');
|
|
|
63
62
|
/**
|
|
64
63
|
* Class for a Toolbox.
|
|
65
64
|
* Creates the toolbox's DOM.
|
|
66
|
-
* @param {!WorkspaceSvg} workspace The workspace in which to create new
|
|
67
|
-
* blocks.
|
|
68
|
-
* @constructor
|
|
69
65
|
* @implements {IAutoHideable}
|
|
70
66
|
* @implements {IKeyboardAccessible}
|
|
71
67
|
* @implements {IStyleable}
|
|
@@ -73,1079 +69,1090 @@ goog.require('Blockly.Events.ToolboxItemSelect');
|
|
|
73
69
|
* @extends {DeleteArea}
|
|
74
70
|
* @alias Blockly.Toolbox
|
|
75
71
|
*/
|
|
76
|
-
|
|
77
|
-
Toolbox.superClass_.constructor.call(this);
|
|
72
|
+
class Toolbox extends DeleteArea {
|
|
78
73
|
/**
|
|
79
|
-
* The workspace
|
|
80
|
-
*
|
|
81
|
-
* @protected
|
|
74
|
+
* @param {!WorkspaceSvg} workspace The workspace in which to create new
|
|
75
|
+
* blocks.
|
|
82
76
|
*/
|
|
83
|
-
|
|
77
|
+
constructor(workspace) {
|
|
78
|
+
super();
|
|
79
|
+
|
|
80
|
+
/**
|
|
81
|
+
* The workspace this toolbox is on.
|
|
82
|
+
* @type {!WorkspaceSvg}
|
|
83
|
+
* @protected
|
|
84
|
+
*/
|
|
85
|
+
this.workspace_ = workspace;
|
|
86
|
+
|
|
87
|
+
/**
|
|
88
|
+
* The unique id for this component that is used to register with the
|
|
89
|
+
* ComponentManager.
|
|
90
|
+
* @type {string}
|
|
91
|
+
*/
|
|
92
|
+
this.id = 'toolbox';
|
|
93
|
+
|
|
94
|
+
/**
|
|
95
|
+
* The JSON describing the contents of this toolbox.
|
|
96
|
+
* @type {!toolbox.ToolboxInfo}
|
|
97
|
+
* @protected
|
|
98
|
+
*/
|
|
99
|
+
this.toolboxDef_ = workspace.options.languageTree || {'contents': []};
|
|
100
|
+
|
|
101
|
+
/**
|
|
102
|
+
* Whether the toolbox should be laid out horizontally.
|
|
103
|
+
* @type {boolean}
|
|
104
|
+
* @private
|
|
105
|
+
*/
|
|
106
|
+
this.horizontalLayout_ = workspace.options.horizontalLayout;
|
|
107
|
+
|
|
108
|
+
/**
|
|
109
|
+
* The html container for the toolbox.
|
|
110
|
+
* @type {?HTMLDivElement}
|
|
111
|
+
*/
|
|
112
|
+
this.HtmlDiv = null;
|
|
113
|
+
|
|
114
|
+
/**
|
|
115
|
+
* The html container for the contents of a toolbox.
|
|
116
|
+
* @type {?HTMLDivElement}
|
|
117
|
+
* @protected
|
|
118
|
+
*/
|
|
119
|
+
this.contentsDiv_ = null;
|
|
120
|
+
|
|
121
|
+
/**
|
|
122
|
+
* Whether the Toolbox is visible.
|
|
123
|
+
* @type {boolean}
|
|
124
|
+
* @protected
|
|
125
|
+
*/
|
|
126
|
+
this.isVisible_ = false;
|
|
127
|
+
|
|
128
|
+
/**
|
|
129
|
+
* The list of items in the toolbox.
|
|
130
|
+
* @type {!Array<!IToolboxItem>}
|
|
131
|
+
* @protected
|
|
132
|
+
*/
|
|
133
|
+
this.contents_ = [];
|
|
134
|
+
|
|
135
|
+
/**
|
|
136
|
+
* The width of the toolbox.
|
|
137
|
+
* @type {number}
|
|
138
|
+
* @protected
|
|
139
|
+
*/
|
|
140
|
+
this.width_ = 0;
|
|
141
|
+
|
|
142
|
+
/**
|
|
143
|
+
* The height of the toolbox.
|
|
144
|
+
* @type {number}
|
|
145
|
+
* @protected
|
|
146
|
+
*/
|
|
147
|
+
this.height_ = 0;
|
|
148
|
+
|
|
149
|
+
/**
|
|
150
|
+
* Is RTL vs LTR.
|
|
151
|
+
* @type {boolean}
|
|
152
|
+
*/
|
|
153
|
+
this.RTL = workspace.options.RTL;
|
|
154
|
+
|
|
155
|
+
/**
|
|
156
|
+
* The flyout for the toolbox.
|
|
157
|
+
* @type {?IFlyout}
|
|
158
|
+
* @private
|
|
159
|
+
*/
|
|
160
|
+
this.flyout_ = null;
|
|
161
|
+
|
|
162
|
+
/**
|
|
163
|
+
* A map from toolbox item IDs to toolbox items.
|
|
164
|
+
* @type {!Object<string, !IToolboxItem>}
|
|
165
|
+
* @protected
|
|
166
|
+
*/
|
|
167
|
+
this.contentMap_ = Object.create(null);
|
|
168
|
+
|
|
169
|
+
/**
|
|
170
|
+
* Position of the toolbox and flyout relative to the workspace.
|
|
171
|
+
* @type {!toolbox.Position}
|
|
172
|
+
*/
|
|
173
|
+
this.toolboxPosition = workspace.options.toolboxPosition;
|
|
174
|
+
|
|
175
|
+
/**
|
|
176
|
+
* The currently selected item.
|
|
177
|
+
* @type {?ISelectableToolboxItem}
|
|
178
|
+
* @protected
|
|
179
|
+
*/
|
|
180
|
+
this.selectedItem_ = null;
|
|
181
|
+
|
|
182
|
+
/**
|
|
183
|
+
* The previously selected item.
|
|
184
|
+
* @type {?ISelectableToolboxItem}
|
|
185
|
+
* @protected
|
|
186
|
+
*/
|
|
187
|
+
this.previouslySelectedItem_ = null;
|
|
188
|
+
|
|
189
|
+
/**
|
|
190
|
+
* Array holding info needed to unbind event handlers.
|
|
191
|
+
* Used for disposing.
|
|
192
|
+
* Ex: [[node, name, func], [node, name, func]].
|
|
193
|
+
* @type {!Array<!browserEvents.Data>}
|
|
194
|
+
* @protected
|
|
195
|
+
*/
|
|
196
|
+
this.boundEvents_ = [];
|
|
197
|
+
}
|
|
84
198
|
|
|
85
199
|
/**
|
|
86
|
-
*
|
|
87
|
-
*
|
|
88
|
-
*
|
|
200
|
+
* Handles the given keyboard shortcut.
|
|
201
|
+
* @param {!ShortcutRegistry.KeyboardShortcut} _shortcut The shortcut to be
|
|
202
|
+
* handled.
|
|
203
|
+
* @return {boolean} True if the shortcut has been handled, false otherwise.
|
|
204
|
+
* @public
|
|
89
205
|
*/
|
|
90
|
-
|
|
206
|
+
onShortcut(_shortcut) {
|
|
207
|
+
return false;
|
|
208
|
+
}
|
|
91
209
|
|
|
92
210
|
/**
|
|
93
|
-
*
|
|
94
|
-
* @
|
|
95
|
-
* @protected
|
|
211
|
+
* Initializes the toolbox
|
|
212
|
+
* @public
|
|
96
213
|
*/
|
|
97
|
-
|
|
214
|
+
init() {
|
|
215
|
+
const workspace = this.workspace_;
|
|
216
|
+
const svg = workspace.getParentSvg();
|
|
217
|
+
|
|
218
|
+
this.flyout_ = this.createFlyout_();
|
|
219
|
+
|
|
220
|
+
this.HtmlDiv = this.createDom_(this.workspace_);
|
|
221
|
+
dom.insertAfter(this.flyout_.createDom('svg'), svg);
|
|
222
|
+
this.setVisible(true);
|
|
223
|
+
this.flyout_.init(workspace);
|
|
224
|
+
|
|
225
|
+
this.render(this.toolboxDef_);
|
|
226
|
+
const themeManager = workspace.getThemeManager();
|
|
227
|
+
themeManager.subscribe(
|
|
228
|
+
this.HtmlDiv, 'toolboxBackgroundColour', 'background-color');
|
|
229
|
+
themeManager.subscribe(this.HtmlDiv, 'toolboxForegroundColour', 'color');
|
|
230
|
+
this.workspace_.getComponentManager().addComponent({
|
|
231
|
+
component: this,
|
|
232
|
+
weight: 1,
|
|
233
|
+
capabilities: [
|
|
234
|
+
ComponentManager.Capability.AUTOHIDEABLE,
|
|
235
|
+
ComponentManager.Capability.DELETE_AREA,
|
|
236
|
+
ComponentManager.Capability.DRAG_TARGET,
|
|
237
|
+
],
|
|
238
|
+
});
|
|
239
|
+
}
|
|
98
240
|
|
|
99
241
|
/**
|
|
100
|
-
*
|
|
101
|
-
* @
|
|
102
|
-
* @
|
|
242
|
+
* Creates the DOM for the toolbox.
|
|
243
|
+
* @param {!WorkspaceSvg} workspace The workspace this toolbox is on.
|
|
244
|
+
* @return {!HTMLDivElement} The HTML container for the toolbox.
|
|
245
|
+
* @protected
|
|
103
246
|
*/
|
|
104
|
-
|
|
247
|
+
createDom_(workspace) {
|
|
248
|
+
const svg = workspace.getParentSvg();
|
|
105
249
|
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
250
|
+
const container = this.createContainer_();
|
|
251
|
+
|
|
252
|
+
this.contentsDiv_ = this.createContentsContainer_();
|
|
253
|
+
this.contentsDiv_.tabIndex = 0;
|
|
254
|
+
aria.setRole(this.contentsDiv_, aria.Role.TREE);
|
|
255
|
+
container.appendChild(this.contentsDiv_);
|
|
256
|
+
|
|
257
|
+
svg.parentNode.insertBefore(container, svg);
|
|
258
|
+
|
|
259
|
+
this.attachEvents_(container, this.contentsDiv_);
|
|
260
|
+
return container;
|
|
261
|
+
}
|
|
111
262
|
|
|
112
263
|
/**
|
|
113
|
-
*
|
|
114
|
-
* @
|
|
264
|
+
* Creates the container div for the toolbox.
|
|
265
|
+
* @return {!HTMLDivElement} The HTML container for the toolbox.
|
|
115
266
|
* @protected
|
|
116
267
|
*/
|
|
117
|
-
|
|
268
|
+
createContainer_() {
|
|
269
|
+
const toolboxContainer =
|
|
270
|
+
/** @type {!HTMLDivElement} */ (document.createElement('div'));
|
|
271
|
+
toolboxContainer.setAttribute('layout', this.isHorizontal() ? 'h' : 'v');
|
|
272
|
+
dom.addClass(toolboxContainer, 'blocklyToolboxDiv');
|
|
273
|
+
dom.addClass(toolboxContainer, 'blocklyNonSelectable');
|
|
274
|
+
toolboxContainer.setAttribute('dir', this.RTL ? 'RTL' : 'LTR');
|
|
275
|
+
return toolboxContainer;
|
|
276
|
+
}
|
|
118
277
|
|
|
119
278
|
/**
|
|
120
|
-
*
|
|
121
|
-
* @
|
|
279
|
+
* Creates the container for all the contents in the toolbox.
|
|
280
|
+
* @return {!HTMLDivElement} The HTML container for the toolbox contents.
|
|
122
281
|
* @protected
|
|
123
282
|
*/
|
|
124
|
-
|
|
283
|
+
createContentsContainer_() {
|
|
284
|
+
const contentsContainer =
|
|
285
|
+
/** @type {!HTMLDivElement} */ (document.createElement('div'));
|
|
286
|
+
dom.addClass(contentsContainer, 'blocklyToolboxContents');
|
|
287
|
+
if (this.isHorizontal()) {
|
|
288
|
+
contentsContainer.style.flexDirection = 'row';
|
|
289
|
+
}
|
|
290
|
+
return contentsContainer;
|
|
291
|
+
}
|
|
125
292
|
|
|
126
293
|
/**
|
|
127
|
-
*
|
|
128
|
-
* @
|
|
294
|
+
* Adds event listeners to the toolbox container div.
|
|
295
|
+
* @param {!HTMLDivElement} container The HTML container for the toolbox.
|
|
296
|
+
* @param {!HTMLDivElement} contentsContainer The HTML container for the
|
|
297
|
+
* contents of the toolbox.
|
|
129
298
|
* @protected
|
|
130
299
|
*/
|
|
131
|
-
|
|
300
|
+
attachEvents_(container, contentsContainer) {
|
|
301
|
+
// Clicking on toolbox closes popups.
|
|
302
|
+
const clickEvent = browserEvents.conditionalBind(
|
|
303
|
+
container, 'click', this, this.onClick_,
|
|
304
|
+
/* opt_noCaptureIdentifier */ false,
|
|
305
|
+
/* opt_noPreventDefault */ true);
|
|
306
|
+
this.boundEvents_.push(clickEvent);
|
|
307
|
+
|
|
308
|
+
const keyDownEvent = browserEvents.conditionalBind(
|
|
309
|
+
contentsContainer, 'keydown', this, this.onKeyDown_,
|
|
310
|
+
/* opt_noCaptureIdentifier */ false,
|
|
311
|
+
/* opt_noPreventDefault */ true);
|
|
312
|
+
this.boundEvents_.push(keyDownEvent);
|
|
313
|
+
}
|
|
132
314
|
|
|
133
315
|
/**
|
|
134
|
-
*
|
|
135
|
-
* @
|
|
316
|
+
* Handles on click events for when the toolbox or toolbox items are clicked.
|
|
317
|
+
* @param {!Event} e Click event to handle.
|
|
136
318
|
* @protected
|
|
137
319
|
*/
|
|
138
|
-
|
|
320
|
+
onClick_(e) {
|
|
321
|
+
if (browserEvents.isRightButton(e) || e.target === this.HtmlDiv) {
|
|
322
|
+
// Close flyout.
|
|
323
|
+
/** @type {!WorkspaceSvg} */ (common.getMainWorkspace()).hideChaff(false);
|
|
324
|
+
} else {
|
|
325
|
+
const targetElement = e.target;
|
|
326
|
+
const itemId = targetElement.getAttribute('id');
|
|
327
|
+
if (itemId) {
|
|
328
|
+
const item = this.getToolboxItemById(itemId);
|
|
329
|
+
if (item.isSelectable()) {
|
|
330
|
+
this.setSelectedItem(item);
|
|
331
|
+
item.onClick(e);
|
|
332
|
+
}
|
|
333
|
+
}
|
|
334
|
+
// Just close popups.
|
|
335
|
+
/** @type {!WorkspaceSvg} */ (common.getMainWorkspace()).hideChaff(true);
|
|
336
|
+
}
|
|
337
|
+
Touch.clearTouchIdentifier(); // Don't block future drags.
|
|
338
|
+
}
|
|
139
339
|
|
|
140
340
|
/**
|
|
141
|
-
*
|
|
142
|
-
* @
|
|
341
|
+
* Handles key down events for the toolbox.
|
|
342
|
+
* @param {!KeyboardEvent} e The key down event.
|
|
143
343
|
* @protected
|
|
144
344
|
*/
|
|
145
|
-
|
|
345
|
+
onKeyDown_(e) {
|
|
346
|
+
let handled = false;
|
|
347
|
+
switch (e.keyCode) {
|
|
348
|
+
case KeyCodes.DOWN:
|
|
349
|
+
handled = this.selectNext_();
|
|
350
|
+
break;
|
|
351
|
+
case KeyCodes.UP:
|
|
352
|
+
handled = this.selectPrevious_();
|
|
353
|
+
break;
|
|
354
|
+
case KeyCodes.LEFT:
|
|
355
|
+
handled = this.selectParent_();
|
|
356
|
+
break;
|
|
357
|
+
case KeyCodes.RIGHT:
|
|
358
|
+
handled = this.selectChild_();
|
|
359
|
+
break;
|
|
360
|
+
case KeyCodes.ENTER:
|
|
361
|
+
case KeyCodes.SPACE:
|
|
362
|
+
if (this.selectedItem_ && this.selectedItem_.isCollapsible()) {
|
|
363
|
+
const collapsibleItem =
|
|
364
|
+
/** @type {!ICollapsibleToolboxItem} */ (this.selectedItem_);
|
|
365
|
+
collapsibleItem.toggleExpanded();
|
|
366
|
+
handled = true;
|
|
367
|
+
}
|
|
368
|
+
break;
|
|
369
|
+
default:
|
|
370
|
+
handled = false;
|
|
371
|
+
break;
|
|
372
|
+
}
|
|
373
|
+
if (!handled && this.selectedItem_ && this.selectedItem_.onKeyDown) {
|
|
374
|
+
handled = this.selectedItem_.onKeyDown(e);
|
|
375
|
+
}
|
|
376
|
+
|
|
377
|
+
if (handled) {
|
|
378
|
+
e.preventDefault();
|
|
379
|
+
}
|
|
380
|
+
}
|
|
146
381
|
|
|
147
382
|
/**
|
|
148
|
-
*
|
|
149
|
-
* @
|
|
383
|
+
* Creates the flyout based on the toolbox layout.
|
|
384
|
+
* @return {!IFlyout} The flyout for the toolbox.
|
|
385
|
+
* @throws {Error} If missing a require for `Blockly.HorizontalFlyout`,
|
|
386
|
+
* `Blockly.VerticalFlyout`, and no flyout plugin is specified.
|
|
387
|
+
* @protected
|
|
150
388
|
*/
|
|
151
|
-
|
|
389
|
+
createFlyout_() {
|
|
390
|
+
const workspace = this.workspace_;
|
|
391
|
+
// TODO (#4247): Look into adding a makeFlyout method to Blockly Options.
|
|
392
|
+
const workspaceOptions = new Options(
|
|
393
|
+
/** @type {!BlocklyOptions} */
|
|
394
|
+
({
|
|
395
|
+
'parentWorkspace': workspace,
|
|
396
|
+
'rtl': workspace.RTL,
|
|
397
|
+
'oneBasedIndex': workspace.options.oneBasedIndex,
|
|
398
|
+
'horizontalLayout': workspace.horizontalLayout,
|
|
399
|
+
'renderer': workspace.options.renderer,
|
|
400
|
+
'rendererOverrides': workspace.options.rendererOverrides,
|
|
401
|
+
'move': {
|
|
402
|
+
'scrollbars': true,
|
|
403
|
+
},
|
|
404
|
+
}));
|
|
405
|
+
// Options takes in either 'end' or 'start'. This has already been parsed to
|
|
406
|
+
// be either 0 or 1, so set it after.
|
|
407
|
+
workspaceOptions.toolboxPosition = workspace.options.toolboxPosition;
|
|
408
|
+
let FlyoutClass = null;
|
|
409
|
+
if (workspace.horizontalLayout) {
|
|
410
|
+
FlyoutClass = registry.getClassFromOptions(
|
|
411
|
+
registry.Type.FLYOUTS_HORIZONTAL_TOOLBOX, workspace.options, true);
|
|
412
|
+
} else {
|
|
413
|
+
FlyoutClass = registry.getClassFromOptions(
|
|
414
|
+
registry.Type.FLYOUTS_VERTICAL_TOOLBOX, workspace.options, true);
|
|
415
|
+
}
|
|
416
|
+
return new FlyoutClass(workspaceOptions);
|
|
417
|
+
}
|
|
152
418
|
|
|
153
419
|
/**
|
|
154
|
-
*
|
|
155
|
-
* @
|
|
156
|
-
*
|
|
420
|
+
* Fills the toolbox with new toolbox items and removes any old contents.
|
|
421
|
+
* @param {!toolbox.ToolboxInfo} toolboxDef Object holding information
|
|
422
|
+
* for creating a toolbox.
|
|
423
|
+
* @package
|
|
157
424
|
*/
|
|
158
|
-
|
|
425
|
+
render(toolboxDef) {
|
|
426
|
+
this.toolboxDef_ = toolboxDef;
|
|
427
|
+
for (let i = 0; i < this.contents_.length; i++) {
|
|
428
|
+
const toolboxItem = this.contents_[i];
|
|
429
|
+
if (toolboxItem) {
|
|
430
|
+
toolboxItem.dispose();
|
|
431
|
+
}
|
|
432
|
+
}
|
|
433
|
+
this.contents_ = [];
|
|
434
|
+
this.contentMap_ = Object.create(null);
|
|
435
|
+
this.renderContents_(toolboxDef['contents']);
|
|
436
|
+
this.position();
|
|
437
|
+
this.handleToolboxItemResize();
|
|
438
|
+
}
|
|
159
439
|
|
|
160
440
|
/**
|
|
161
|
-
*
|
|
162
|
-
* @
|
|
441
|
+
* Adds all the toolbox items to the toolbox.
|
|
442
|
+
* @param {!Array<!toolbox.ToolboxItemInfo>} toolboxDef Array
|
|
443
|
+
* holding objects containing information on the contents of the toolbox.
|
|
163
444
|
* @protected
|
|
164
445
|
*/
|
|
165
|
-
|
|
446
|
+
renderContents_(toolboxDef) {
|
|
447
|
+
// This is for performance reasons. By using document fragment we only have
|
|
448
|
+
// to add to the DOM once.
|
|
449
|
+
const fragment = document.createDocumentFragment();
|
|
450
|
+
for (let i = 0; i < toolboxDef.length; i++) {
|
|
451
|
+
const toolboxItemDef = toolboxDef[i];
|
|
452
|
+
this.createToolboxItem_(toolboxItemDef, fragment);
|
|
453
|
+
}
|
|
454
|
+
this.contentsDiv_.appendChild(fragment);
|
|
455
|
+
}
|
|
166
456
|
|
|
167
457
|
/**
|
|
168
|
-
*
|
|
169
|
-
* @
|
|
458
|
+
* Creates and renders the toolbox item.
|
|
459
|
+
* @param {!toolbox.ToolboxItemInfo} toolboxItemDef Any information
|
|
460
|
+
* that can be used to create an item in the toolbox.
|
|
461
|
+
* @param {!DocumentFragment} fragment The document fragment to add the child
|
|
462
|
+
* toolbox elements to.
|
|
463
|
+
* @private
|
|
170
464
|
*/
|
|
171
|
-
|
|
465
|
+
createToolboxItem_(toolboxItemDef, fragment) {
|
|
466
|
+
let registryName = toolboxItemDef['kind'];
|
|
467
|
+
|
|
468
|
+
// Categories that are collapsible are created using a class registered
|
|
469
|
+
// under a different name.
|
|
470
|
+
if (registryName.toUpperCase() === 'CATEGORY' &&
|
|
471
|
+
toolbox.isCategoryCollapsible(
|
|
472
|
+
/** @type {!toolbox.CategoryInfo} */ (toolboxItemDef))) {
|
|
473
|
+
registryName = CollapsibleToolboxCategory.registrationName;
|
|
474
|
+
}
|
|
475
|
+
|
|
476
|
+
const ToolboxItemClass = registry.getClass(
|
|
477
|
+
registry.Type.TOOLBOX_ITEM, registryName.toLowerCase());
|
|
478
|
+
if (ToolboxItemClass) {
|
|
479
|
+
const toolboxItem = new ToolboxItemClass(toolboxItemDef, this);
|
|
480
|
+
toolboxItem.init();
|
|
481
|
+
this.addToolboxItem_(toolboxItem);
|
|
482
|
+
const toolboxItemDom = toolboxItem.getDiv();
|
|
483
|
+
if (toolboxItemDom) {
|
|
484
|
+
fragment.appendChild(toolboxItemDom);
|
|
485
|
+
}
|
|
486
|
+
// Adds the ID to the HTML element that can receive a click.
|
|
487
|
+
// This is used in onClick_ to find the toolboxItem that was clicked.
|
|
488
|
+
if (toolboxItem.getClickTarget()) {
|
|
489
|
+
toolboxItem.getClickTarget().setAttribute('id', toolboxItem.getId());
|
|
490
|
+
}
|
|
491
|
+
}
|
|
492
|
+
}
|
|
172
493
|
|
|
173
494
|
/**
|
|
174
|
-
*
|
|
175
|
-
* @
|
|
495
|
+
* Adds an item to the toolbox.
|
|
496
|
+
* @param {!IToolboxItem} toolboxItem The item in the toolbox.
|
|
176
497
|
* @protected
|
|
177
498
|
*/
|
|
178
|
-
|
|
499
|
+
addToolboxItem_(toolboxItem) {
|
|
500
|
+
this.contents_.push(toolboxItem);
|
|
501
|
+
this.contentMap_[toolboxItem.getId()] = toolboxItem;
|
|
502
|
+
if (toolboxItem.isCollapsible()) {
|
|
503
|
+
const collapsibleItem = /** @type {ICollapsibleToolboxItem} */
|
|
504
|
+
(toolboxItem);
|
|
505
|
+
const childToolboxItems = collapsibleItem.getChildToolboxItems();
|
|
506
|
+
for (let i = 0; i < childToolboxItems.length; i++) {
|
|
507
|
+
const child = childToolboxItems[i];
|
|
508
|
+
this.addToolboxItem_(child);
|
|
509
|
+
}
|
|
510
|
+
}
|
|
511
|
+
}
|
|
179
512
|
|
|
180
513
|
/**
|
|
181
|
-
*
|
|
182
|
-
* @
|
|
183
|
-
* @
|
|
514
|
+
* Gets the items in the toolbox.
|
|
515
|
+
* @return {!Array<!IToolboxItem>} The list of items in the toolbox.
|
|
516
|
+
* @public
|
|
184
517
|
*/
|
|
185
|
-
|
|
518
|
+
getToolboxItems() {
|
|
519
|
+
return this.contents_;
|
|
520
|
+
}
|
|
186
521
|
|
|
187
522
|
/**
|
|
188
|
-
*
|
|
189
|
-
*
|
|
190
|
-
*
|
|
191
|
-
* @type {!Array<!browserEvents.Data>}
|
|
192
|
-
* @protected
|
|
523
|
+
* Adds a style on the toolbox. Usually used to change the cursor.
|
|
524
|
+
* @param {string} style The name of the class to add.
|
|
525
|
+
* @package
|
|
193
526
|
*/
|
|
194
|
-
|
|
195
|
-
};
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
/**
|
|
199
|
-
* Handles the given keyboard shortcut.
|
|
200
|
-
* @param {!ShortcutRegistry.KeyboardShortcut} _shortcut The shortcut to be
|
|
201
|
-
* handled.
|
|
202
|
-
* @return {boolean} True if the shortcut has been handled, false otherwise.
|
|
203
|
-
* @public
|
|
204
|
-
*/
|
|
205
|
-
Toolbox.prototype.onShortcut = function(_shortcut) {
|
|
206
|
-
return false;
|
|
207
|
-
};
|
|
208
|
-
|
|
209
|
-
/**
|
|
210
|
-
* Initializes the toolbox
|
|
211
|
-
* @public
|
|
212
|
-
*/
|
|
213
|
-
Toolbox.prototype.init = function() {
|
|
214
|
-
const workspace = this.workspace_;
|
|
215
|
-
const svg = workspace.getParentSvg();
|
|
216
|
-
|
|
217
|
-
this.flyout_ = this.createFlyout_();
|
|
218
|
-
|
|
219
|
-
this.HtmlDiv = this.createDom_(this.workspace_);
|
|
220
|
-
dom.insertAfter(this.flyout_.createDom('svg'), svg);
|
|
221
|
-
this.setVisible(true);
|
|
222
|
-
this.flyout_.init(workspace);
|
|
223
|
-
|
|
224
|
-
this.render(this.toolboxDef_);
|
|
225
|
-
const themeManager = workspace.getThemeManager();
|
|
226
|
-
themeManager.subscribe(
|
|
227
|
-
this.HtmlDiv, 'toolboxBackgroundColour', 'background-color');
|
|
228
|
-
themeManager.subscribe(this.HtmlDiv, 'toolboxForegroundColour', 'color');
|
|
229
|
-
this.workspace_.getComponentManager().addComponent({
|
|
230
|
-
component: this,
|
|
231
|
-
weight: 1,
|
|
232
|
-
capabilities: [
|
|
233
|
-
ComponentManager.Capability.AUTOHIDEABLE,
|
|
234
|
-
ComponentManager.Capability.DELETE_AREA,
|
|
235
|
-
ComponentManager.Capability.DRAG_TARGET,
|
|
236
|
-
],
|
|
237
|
-
});
|
|
238
|
-
};
|
|
239
|
-
|
|
240
|
-
/**
|
|
241
|
-
* Creates the DOM for the toolbox.
|
|
242
|
-
* @param {!WorkspaceSvg} workspace The workspace this toolbox is on.
|
|
243
|
-
* @return {!Element} The HTML container for the toolbox.
|
|
244
|
-
* @protected
|
|
245
|
-
*/
|
|
246
|
-
Toolbox.prototype.createDom_ = function(workspace) {
|
|
247
|
-
const svg = workspace.getParentSvg();
|
|
248
|
-
|
|
249
|
-
const container = this.createContainer_();
|
|
527
|
+
addStyle(style) {
|
|
528
|
+
dom.addClass(/** @type {!Element} */ (this.HtmlDiv), style);
|
|
529
|
+
}
|
|
250
530
|
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
531
|
+
/**
|
|
532
|
+
* Removes a style from the toolbox. Usually used to change the cursor.
|
|
533
|
+
* @param {string} style The name of the class to remove.
|
|
534
|
+
* @package
|
|
535
|
+
*/
|
|
536
|
+
removeStyle(style) {
|
|
537
|
+
dom.removeClass(/** @type {!Element} */ (this.HtmlDiv), style);
|
|
538
|
+
}
|
|
255
539
|
|
|
256
|
-
|
|
540
|
+
/**
|
|
541
|
+
* Returns the bounding rectangle of the drag target area in pixel units
|
|
542
|
+
* relative to viewport.
|
|
543
|
+
* @return {?Rect} The component's bounding box. Null if drag
|
|
544
|
+
* target area should be ignored.
|
|
545
|
+
*/
|
|
546
|
+
getClientRect() {
|
|
547
|
+
if (!this.HtmlDiv || !this.isVisible_) {
|
|
548
|
+
return null;
|
|
549
|
+
}
|
|
257
550
|
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
551
|
+
// BIG_NUM is offscreen padding so that blocks dragged beyond the toolbox
|
|
552
|
+
// area are still deleted. Must be smaller than Infinity, but larger than
|
|
553
|
+
// the largest screen size.
|
|
554
|
+
const BIG_NUM = 10000000;
|
|
555
|
+
const toolboxRect = this.HtmlDiv.getBoundingClientRect();
|
|
261
556
|
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
*/
|
|
267
|
-
Toolbox.prototype.createContainer_ = function() {
|
|
268
|
-
const toolboxContainer = document.createElement('div');
|
|
269
|
-
toolboxContainer.setAttribute('layout', this.isHorizontal() ? 'h' : 'v');
|
|
270
|
-
dom.addClass(toolboxContainer, 'blocklyToolboxDiv');
|
|
271
|
-
dom.addClass(toolboxContainer, 'blocklyNonSelectable');
|
|
272
|
-
toolboxContainer.setAttribute('dir', this.RTL ? 'RTL' : 'LTR');
|
|
273
|
-
return toolboxContainer;
|
|
274
|
-
};
|
|
557
|
+
const top = toolboxRect.top;
|
|
558
|
+
const bottom = top + toolboxRect.height;
|
|
559
|
+
const left = toolboxRect.left;
|
|
560
|
+
const right = left + toolboxRect.width;
|
|
275
561
|
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
562
|
+
// Assumes that the toolbox is on the SVG edge. If this changes
|
|
563
|
+
// (e.g. toolboxes in mutators) then this code will need to be more complex.
|
|
564
|
+
if (this.toolboxPosition === toolbox.Position.TOP) {
|
|
565
|
+
return new Rect(-BIG_NUM, bottom, -BIG_NUM, BIG_NUM);
|
|
566
|
+
} else if (this.toolboxPosition === toolbox.Position.BOTTOM) {
|
|
567
|
+
return new Rect(top, BIG_NUM, -BIG_NUM, BIG_NUM);
|
|
568
|
+
} else if (this.toolboxPosition === toolbox.Position.LEFT) {
|
|
569
|
+
return new Rect(-BIG_NUM, BIG_NUM, -BIG_NUM, right);
|
|
570
|
+
} else { // Right
|
|
571
|
+
return new Rect(-BIG_NUM, BIG_NUM, left, BIG_NUM);
|
|
572
|
+
}
|
|
286
573
|
}
|
|
287
|
-
return contentsContainer;
|
|
288
|
-
};
|
|
289
|
-
|
|
290
|
-
/**
|
|
291
|
-
* Adds event listeners to the toolbox container div.
|
|
292
|
-
* @param {!Element} container The HTML container for the toolbox.
|
|
293
|
-
* @param {!Element} contentsContainer The HTML container for the contents
|
|
294
|
-
* of the toolbox.
|
|
295
|
-
* @protected
|
|
296
|
-
*/
|
|
297
|
-
Toolbox.prototype.attachEvents_ = function(container, contentsContainer) {
|
|
298
|
-
// Clicking on toolbox closes popups.
|
|
299
|
-
const clickEvent = browserEvents.conditionalBind(
|
|
300
|
-
container, 'click', this, this.onClick_,
|
|
301
|
-
/* opt_noCaptureIdentifier */ false,
|
|
302
|
-
/* opt_noPreventDefault */ true);
|
|
303
|
-
this.boundEvents_.push(clickEvent);
|
|
304
|
-
|
|
305
|
-
const keyDownEvent = browserEvents.conditionalBind(
|
|
306
|
-
contentsContainer, 'keydown', this, this.onKeyDown_,
|
|
307
|
-
/* opt_noCaptureIdentifier */ false,
|
|
308
|
-
/* opt_noPreventDefault */ true);
|
|
309
|
-
this.boundEvents_.push(keyDownEvent);
|
|
310
|
-
};
|
|
311
574
|
|
|
312
|
-
/**
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
575
|
+
/**
|
|
576
|
+
* Returns whether the provided block or bubble would be deleted if dropped on
|
|
577
|
+
* this area.
|
|
578
|
+
* This method should check if the element is deletable and is always called
|
|
579
|
+
* before onDragEnter/onDragOver/onDragExit.
|
|
580
|
+
* @param {!IDraggable} element The block or bubble currently being
|
|
581
|
+
* dragged.
|
|
582
|
+
* @param {boolean} _couldConnect Whether the element could could connect to
|
|
583
|
+
* another.
|
|
584
|
+
* @return {boolean} Whether the element provided would be deleted if dropped
|
|
585
|
+
* on this area.
|
|
586
|
+
* @override
|
|
587
|
+
*/
|
|
588
|
+
wouldDelete(element, _couldConnect) {
|
|
589
|
+
if (element instanceof BlockSvg) {
|
|
590
|
+
const block = /** @type {BlockSvg} */ (element);
|
|
591
|
+
// Prefer dragging to the toolbox over connecting to other blocks.
|
|
592
|
+
this.updateWouldDelete_(!block.getParent() && block.isDeletable());
|
|
593
|
+
} else {
|
|
594
|
+
this.updateWouldDelete_(element.isDeletable());
|
|
330
595
|
}
|
|
331
|
-
|
|
332
|
-
common.getMainWorkspace().hideChaff(true);
|
|
596
|
+
return this.wouldDelete_;
|
|
333
597
|
}
|
|
334
|
-
Touch.clearTouchIdentifier(); // Don't block future drags.
|
|
335
|
-
};
|
|
336
598
|
|
|
337
|
-
/**
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
case KeyCodes.DOWN:
|
|
346
|
-
handled = this.selectNext_();
|
|
347
|
-
break;
|
|
348
|
-
case KeyCodes.UP:
|
|
349
|
-
handled = this.selectPrevious_();
|
|
350
|
-
break;
|
|
351
|
-
case KeyCodes.LEFT:
|
|
352
|
-
handled = this.selectParent_();
|
|
353
|
-
break;
|
|
354
|
-
case KeyCodes.RIGHT:
|
|
355
|
-
handled = this.selectChild_();
|
|
356
|
-
break;
|
|
357
|
-
case KeyCodes.ENTER:
|
|
358
|
-
case KeyCodes.SPACE:
|
|
359
|
-
if (this.selectedItem_ && this.selectedItem_.isCollapsible()) {
|
|
360
|
-
const collapsibleItem =
|
|
361
|
-
/** @type {!ICollapsibleToolboxItem} */ (this.selectedItem_);
|
|
362
|
-
collapsibleItem.toggleExpanded();
|
|
363
|
-
handled = true;
|
|
364
|
-
}
|
|
365
|
-
break;
|
|
366
|
-
default:
|
|
367
|
-
handled = false;
|
|
368
|
-
break;
|
|
369
|
-
}
|
|
370
|
-
if (!handled && this.selectedItem_ && this.selectedItem_.onKeyDown) {
|
|
371
|
-
handled = this.selectedItem_.onKeyDown(e);
|
|
599
|
+
/**
|
|
600
|
+
* Handles when a cursor with a block or bubble enters this drag target.
|
|
601
|
+
* @param {!IDraggable} _dragElement The block or bubble currently being
|
|
602
|
+
* dragged.
|
|
603
|
+
* @override
|
|
604
|
+
*/
|
|
605
|
+
onDragEnter(_dragElement) {
|
|
606
|
+
this.updateCursorDeleteStyle_(true);
|
|
372
607
|
}
|
|
373
608
|
|
|
374
|
-
|
|
375
|
-
|
|
609
|
+
/**
|
|
610
|
+
* Handles when a cursor with a block or bubble exits this drag target.
|
|
611
|
+
* @param {!IDraggable} _dragElement The block or bubble currently being
|
|
612
|
+
* dragged.
|
|
613
|
+
* @override
|
|
614
|
+
*/
|
|
615
|
+
onDragExit(_dragElement) {
|
|
616
|
+
this.updateCursorDeleteStyle_(false);
|
|
376
617
|
}
|
|
377
|
-
};
|
|
378
618
|
|
|
379
|
-
/**
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
// TODO (#4247): Look into adding a makeFlyout method to Blockly Options.
|
|
389
|
-
const workspaceOptions = new Options(
|
|
390
|
-
/** @type {!BlocklyOptions} */
|
|
391
|
-
({
|
|
392
|
-
'parentWorkspace': workspace,
|
|
393
|
-
'rtl': workspace.RTL,
|
|
394
|
-
'oneBasedIndex': workspace.options.oneBasedIndex,
|
|
395
|
-
'horizontalLayout': workspace.horizontalLayout,
|
|
396
|
-
'renderer': workspace.options.renderer,
|
|
397
|
-
'rendererOverrides': workspace.options.rendererOverrides,
|
|
398
|
-
'move': {
|
|
399
|
-
'scrollbars': true,
|
|
400
|
-
},
|
|
401
|
-
}));
|
|
402
|
-
// Options takes in either 'end' or 'start'. This has already been parsed to
|
|
403
|
-
// be either 0 or 1, so set it after.
|
|
404
|
-
workspaceOptions.toolboxPosition = workspace.options.toolboxPosition;
|
|
405
|
-
let FlyoutClass = null;
|
|
406
|
-
if (workspace.horizontalLayout) {
|
|
407
|
-
FlyoutClass = registry.getClassFromOptions(
|
|
408
|
-
registry.Type.FLYOUTS_HORIZONTAL_TOOLBOX, workspace.options, true);
|
|
409
|
-
} else {
|
|
410
|
-
FlyoutClass = registry.getClassFromOptions(
|
|
411
|
-
registry.Type.FLYOUTS_VERTICAL_TOOLBOX, workspace.options, true);
|
|
619
|
+
/**
|
|
620
|
+
* Handles when a block or bubble is dropped on this component.
|
|
621
|
+
* Should not handle delete here.
|
|
622
|
+
* @param {!IDraggable} _dragElement The block or bubble currently being
|
|
623
|
+
* dragged.
|
|
624
|
+
* @override
|
|
625
|
+
*/
|
|
626
|
+
onDrop(_dragElement) {
|
|
627
|
+
this.updateCursorDeleteStyle_(false);
|
|
412
628
|
}
|
|
413
|
-
return new FlyoutClass(workspaceOptions);
|
|
414
|
-
};
|
|
415
629
|
|
|
416
|
-
/**
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
const toolboxItem = this.contents_[i];
|
|
426
|
-
if (toolboxItem) {
|
|
427
|
-
toolboxItem.dispose();
|
|
630
|
+
/**
|
|
631
|
+
* Updates the internal wouldDelete_ state.
|
|
632
|
+
* @param {boolean} wouldDelete The new value for the wouldDelete state.
|
|
633
|
+
* @protected
|
|
634
|
+
* @override
|
|
635
|
+
*/
|
|
636
|
+
updateWouldDelete_(wouldDelete) {
|
|
637
|
+
if (wouldDelete === this.wouldDelete_) {
|
|
638
|
+
return;
|
|
428
639
|
}
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
/**
|
|
438
|
-
* Adds all the toolbox items to the toolbox.
|
|
439
|
-
* @param {!Array<!toolbox.ToolboxItemInfo>} toolboxDef Array
|
|
440
|
-
* holding objects containing information on the contents of the toolbox.
|
|
441
|
-
* @protected
|
|
442
|
-
*/
|
|
443
|
-
Toolbox.prototype.renderContents_ = function(toolboxDef) {
|
|
444
|
-
// This is for performance reasons. By using document fragment we only have to
|
|
445
|
-
// add to the DOM once.
|
|
446
|
-
const fragment = document.createDocumentFragment();
|
|
447
|
-
for (let i = 0; i < toolboxDef.length; i++) {
|
|
448
|
-
const toolboxItemDef = toolboxDef[i];
|
|
449
|
-
this.createToolboxItem_(toolboxItemDef, fragment);
|
|
450
|
-
}
|
|
451
|
-
this.contentsDiv_.appendChild(fragment);
|
|
452
|
-
};
|
|
453
|
-
|
|
454
|
-
/**
|
|
455
|
-
* Creates and renders the toolbox item.
|
|
456
|
-
* @param {!toolbox.ToolboxItemInfo} toolboxItemDef Any information
|
|
457
|
-
* that can be used to create an item in the toolbox.
|
|
458
|
-
* @param {!DocumentFragment} fragment The document fragment to add the child
|
|
459
|
-
* toolbox elements to.
|
|
460
|
-
* @private
|
|
461
|
-
*/
|
|
462
|
-
Toolbox.prototype.createToolboxItem_ = function(toolboxItemDef, fragment) {
|
|
463
|
-
let registryName = toolboxItemDef['kind'];
|
|
464
|
-
|
|
465
|
-
// Categories that are collapsible are created using a class registered under
|
|
466
|
-
// a different name.
|
|
467
|
-
if (registryName.toUpperCase() === 'CATEGORY' &&
|
|
468
|
-
toolbox.isCategoryCollapsible(
|
|
469
|
-
/** @type {!toolbox.CategoryInfo} */ (toolboxItemDef))) {
|
|
470
|
-
registryName = CollapsibleToolboxCategory.registrationName;
|
|
640
|
+
// This logic handles updating the deleteStyle properly if the delete state
|
|
641
|
+
// changes while the block is over the Toolbox. This could happen if the
|
|
642
|
+
// implementation of wouldDeleteBlock depends on the couldConnect parameter
|
|
643
|
+
// or if the isDeletable property of the block currently being dragged
|
|
644
|
+
// changes during the drag.
|
|
645
|
+
this.updateCursorDeleteStyle_(false);
|
|
646
|
+
this.wouldDelete_ = wouldDelete;
|
|
647
|
+
this.updateCursorDeleteStyle_(true);
|
|
471
648
|
}
|
|
472
649
|
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
650
|
+
/**
|
|
651
|
+
* Adds or removes the CSS style of the cursor over the toolbox based whether
|
|
652
|
+
* the block or bubble over it is expected to be deleted if dropped (using the
|
|
653
|
+
* internal this.wouldDelete_ property).
|
|
654
|
+
* @param {boolean} addStyle Whether the style should be added or removed.
|
|
655
|
+
* @protected
|
|
656
|
+
*/
|
|
657
|
+
updateCursorDeleteStyle_(addStyle) {
|
|
658
|
+
const style =
|
|
659
|
+
this.wouldDelete_ ? 'blocklyToolboxDelete' : 'blocklyToolboxGrab';
|
|
660
|
+
if (addStyle) {
|
|
661
|
+
this.addStyle(style);
|
|
662
|
+
} else {
|
|
663
|
+
this.removeStyle(style);
|
|
487
664
|
}
|
|
488
665
|
}
|
|
489
|
-
};
|
|
490
666
|
|
|
491
|
-
/**
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
const collapsibleItem = /** @type {ICollapsibleToolboxItem} */
|
|
501
|
-
(toolboxItem);
|
|
502
|
-
const childToolboxItems = collapsibleItem.getChildToolboxItems();
|
|
503
|
-
for (let i = 0; i < childToolboxItems.length; i++) {
|
|
504
|
-
const child = childToolboxItems[i];
|
|
505
|
-
this.addToolboxItem_(child);
|
|
506
|
-
}
|
|
667
|
+
/**
|
|
668
|
+
* Gets the toolbox item with the given ID.
|
|
669
|
+
* @param {string} id The ID of the toolbox item.
|
|
670
|
+
* @return {?IToolboxItem} The toolbox item with the given ID, or null
|
|
671
|
+
* if no item exists.
|
|
672
|
+
* @public
|
|
673
|
+
*/
|
|
674
|
+
getToolboxItemById(id) {
|
|
675
|
+
return this.contentMap_[id] || null;
|
|
507
676
|
}
|
|
508
|
-
};
|
|
509
|
-
|
|
510
|
-
/**
|
|
511
|
-
* Gets the items in the toolbox.
|
|
512
|
-
* @return {!Array<!IToolboxItem>} The list of items in the toolbox.
|
|
513
|
-
* @public
|
|
514
|
-
*/
|
|
515
|
-
Toolbox.prototype.getToolboxItems = function() {
|
|
516
|
-
return this.contents_;
|
|
517
|
-
};
|
|
518
677
|
|
|
519
|
-
/**
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
};
|
|
527
|
-
|
|
528
|
-
/**
|
|
529
|
-
* Removes a style from the toolbox. Usually used to change the cursor.
|
|
530
|
-
* @param {string} style The name of the class to remove.
|
|
531
|
-
* @package
|
|
532
|
-
*/
|
|
533
|
-
Toolbox.prototype.removeStyle = function(style) {
|
|
534
|
-
dom.removeClass(/** @type {!Element} */ (this.HtmlDiv), style);
|
|
535
|
-
};
|
|
536
|
-
|
|
537
|
-
/**
|
|
538
|
-
* Returns the bounding rectangle of the drag target area in pixel units
|
|
539
|
-
* relative to viewport.
|
|
540
|
-
* @return {?Rect} The component's bounding box. Null if drag
|
|
541
|
-
* target area should be ignored.
|
|
542
|
-
*/
|
|
543
|
-
Toolbox.prototype.getClientRect = function() {
|
|
544
|
-
if (!this.HtmlDiv || !this.isVisible_) {
|
|
545
|
-
return null;
|
|
678
|
+
/**
|
|
679
|
+
* Gets the width of the toolbox.
|
|
680
|
+
* @return {number} The width of the toolbox.
|
|
681
|
+
* @public
|
|
682
|
+
*/
|
|
683
|
+
getWidth() {
|
|
684
|
+
return this.width_;
|
|
546
685
|
}
|
|
547
686
|
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
const bottom = top + toolboxRect.height;
|
|
556
|
-
const left = toolboxRect.left;
|
|
557
|
-
const right = left + toolboxRect.width;
|
|
558
|
-
|
|
559
|
-
// Assumes that the toolbox is on the SVG edge. If this changes
|
|
560
|
-
// (e.g. toolboxes in mutators) then this code will need to be more complex.
|
|
561
|
-
if (this.toolboxPosition === toolbox.Position.TOP) {
|
|
562
|
-
return new Rect(-BIG_NUM, bottom, -BIG_NUM, BIG_NUM);
|
|
563
|
-
} else if (this.toolboxPosition === toolbox.Position.BOTTOM) {
|
|
564
|
-
return new Rect(top, BIG_NUM, -BIG_NUM, BIG_NUM);
|
|
565
|
-
} else if (this.toolboxPosition === toolbox.Position.LEFT) {
|
|
566
|
-
return new Rect(-BIG_NUM, BIG_NUM, -BIG_NUM, right);
|
|
567
|
-
} else { // Right
|
|
568
|
-
return new Rect(-BIG_NUM, BIG_NUM, left, BIG_NUM);
|
|
687
|
+
/**
|
|
688
|
+
* Gets the height of the toolbox.
|
|
689
|
+
* @return {number} The width of the toolbox.
|
|
690
|
+
* @public
|
|
691
|
+
*/
|
|
692
|
+
getHeight() {
|
|
693
|
+
return this.height_;
|
|
569
694
|
}
|
|
570
|
-
};
|
|
571
695
|
|
|
572
|
-
/**
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
* @param {boolean} _couldConnect Whether the element could could connect to
|
|
580
|
-
* another.
|
|
581
|
-
* @return {boolean} Whether the element provided would be deleted if dropped on
|
|
582
|
-
* this area.
|
|
583
|
-
* @override
|
|
584
|
-
*/
|
|
585
|
-
Toolbox.prototype.wouldDelete = function(element, _couldConnect) {
|
|
586
|
-
if (element instanceof BlockSvg) {
|
|
587
|
-
const block = /** @type {BlockSvg} */ (element);
|
|
588
|
-
// Prefer dragging to the toolbox over connecting to other blocks.
|
|
589
|
-
this.updateWouldDelete_(!block.getParent() && block.isDeletable());
|
|
590
|
-
} else {
|
|
591
|
-
this.updateWouldDelete_(element.isDeletable());
|
|
696
|
+
/**
|
|
697
|
+
* Gets the toolbox flyout.
|
|
698
|
+
* @return {?IFlyout} The toolbox flyout.
|
|
699
|
+
* @public
|
|
700
|
+
*/
|
|
701
|
+
getFlyout() {
|
|
702
|
+
return this.flyout_;
|
|
592
703
|
}
|
|
593
|
-
return this.wouldDelete_;
|
|
594
|
-
};
|
|
595
|
-
|
|
596
|
-
/**
|
|
597
|
-
* Handles when a cursor with a block or bubble enters this drag target.
|
|
598
|
-
* @param {!IDraggable} _dragElement The block or bubble currently being
|
|
599
|
-
* dragged.
|
|
600
|
-
* @override
|
|
601
|
-
*/
|
|
602
|
-
Toolbox.prototype.onDragEnter = function(_dragElement) {
|
|
603
|
-
this.updateCursorDeleteStyle_(true);
|
|
604
|
-
};
|
|
605
|
-
|
|
606
|
-
/**
|
|
607
|
-
* Handles when a cursor with a block or bubble exits this drag target.
|
|
608
|
-
* @param {!IDraggable} _dragElement The block or bubble currently being
|
|
609
|
-
* dragged.
|
|
610
|
-
* @override
|
|
611
|
-
*/
|
|
612
|
-
Toolbox.prototype.onDragExit = function(_dragElement) {
|
|
613
|
-
this.updateCursorDeleteStyle_(false);
|
|
614
|
-
};
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
/**
|
|
618
|
-
* Handles when a block or bubble is dropped on this component.
|
|
619
|
-
* Should not handle delete here.
|
|
620
|
-
* @param {!IDraggable} _dragElement The block or bubble currently being
|
|
621
|
-
* dragged.
|
|
622
|
-
* @override
|
|
623
|
-
*/
|
|
624
|
-
Toolbox.prototype.onDrop = function(_dragElement) {
|
|
625
|
-
this.updateCursorDeleteStyle_(false);
|
|
626
|
-
};
|
|
627
704
|
|
|
628
|
-
/**
|
|
629
|
-
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
if (wouldDelete === this.wouldDelete_) {
|
|
636
|
-
return;
|
|
705
|
+
/**
|
|
706
|
+
* Gets the workspace for the toolbox.
|
|
707
|
+
* @return {!WorkspaceSvg} The parent workspace for the toolbox.
|
|
708
|
+
* @public
|
|
709
|
+
*/
|
|
710
|
+
getWorkspace() {
|
|
711
|
+
return this.workspace_;
|
|
637
712
|
}
|
|
638
|
-
// This logic handles updating the deleteStyle properly if the delete state
|
|
639
|
-
// changes while the block is over the Toolbox. This could happen if the
|
|
640
|
-
// implementation of wouldDeleteBlock depends on the couldConnect parameter
|
|
641
|
-
// or if the isDeletable property of the block currently being dragged
|
|
642
|
-
// changes during the drag.
|
|
643
|
-
this.updateCursorDeleteStyle_(false);
|
|
644
|
-
this.wouldDelete_ = wouldDelete;
|
|
645
|
-
this.updateCursorDeleteStyle_(true);
|
|
646
|
-
};
|
|
647
713
|
|
|
648
|
-
/**
|
|
649
|
-
|
|
650
|
-
|
|
651
|
-
|
|
652
|
-
|
|
653
|
-
|
|
654
|
-
|
|
655
|
-
|
|
656
|
-
const style =
|
|
657
|
-
this.wouldDelete_ ? 'blocklyToolboxDelete' : 'blocklyToolboxGrab';
|
|
658
|
-
if (addStyle) {
|
|
659
|
-
this.addStyle(style);
|
|
660
|
-
} else {
|
|
661
|
-
this.removeStyle(style);
|
|
714
|
+
/**
|
|
715
|
+
* Gets the selected item.
|
|
716
|
+
* @return {?ISelectableToolboxItem} The selected item, or null if no item is
|
|
717
|
+
* currently selected.
|
|
718
|
+
* @public
|
|
719
|
+
*/
|
|
720
|
+
getSelectedItem() {
|
|
721
|
+
return this.selectedItem_;
|
|
662
722
|
}
|
|
663
|
-
};
|
|
664
|
-
|
|
665
|
-
/**
|
|
666
|
-
* Gets the toolbox item with the given ID.
|
|
667
|
-
* @param {string} id The ID of the toolbox item.
|
|
668
|
-
* @return {?IToolboxItem} The toolbox item with the given ID, or null
|
|
669
|
-
* if no item exists.
|
|
670
|
-
* @public
|
|
671
|
-
*/
|
|
672
|
-
Toolbox.prototype.getToolboxItemById = function(id) {
|
|
673
|
-
return this.contentMap_[id] || null;
|
|
674
|
-
};
|
|
675
|
-
|
|
676
|
-
/**
|
|
677
|
-
* Gets the width of the toolbox.
|
|
678
|
-
* @return {number} The width of the toolbox.
|
|
679
|
-
* @public
|
|
680
|
-
*/
|
|
681
|
-
Toolbox.prototype.getWidth = function() {
|
|
682
|
-
return this.width_;
|
|
683
|
-
};
|
|
684
|
-
|
|
685
|
-
/**
|
|
686
|
-
* Gets the height of the toolbox.
|
|
687
|
-
* @return {number} The width of the toolbox.
|
|
688
|
-
* @public
|
|
689
|
-
*/
|
|
690
|
-
Toolbox.prototype.getHeight = function() {
|
|
691
|
-
return this.height_;
|
|
692
|
-
};
|
|
693
|
-
|
|
694
|
-
/**
|
|
695
|
-
* Gets the toolbox flyout.
|
|
696
|
-
* @return {?IFlyout} The toolbox flyout.
|
|
697
|
-
* @public
|
|
698
|
-
*/
|
|
699
|
-
Toolbox.prototype.getFlyout = function() {
|
|
700
|
-
return this.flyout_;
|
|
701
|
-
};
|
|
702
723
|
|
|
703
|
-
/**
|
|
704
|
-
|
|
705
|
-
|
|
706
|
-
|
|
707
|
-
|
|
708
|
-
|
|
709
|
-
|
|
710
|
-
|
|
711
|
-
|
|
712
|
-
/**
|
|
713
|
-
* Gets the selected item.
|
|
714
|
-
* @return {?ISelectableToolboxItem} The selected item, or null if no item is
|
|
715
|
-
* currently selected.
|
|
716
|
-
* @public
|
|
717
|
-
*/
|
|
718
|
-
Toolbox.prototype.getSelectedItem = function() {
|
|
719
|
-
return this.selectedItem_;
|
|
720
|
-
};
|
|
721
|
-
|
|
722
|
-
/**
|
|
723
|
-
* Gets the previously selected item.
|
|
724
|
-
* @return {?ISelectableToolboxItem} The previously selected item, or null if no
|
|
725
|
-
* item was previously selected.
|
|
726
|
-
* @public
|
|
727
|
-
*/
|
|
728
|
-
Toolbox.prototype.getPreviouslySelectedItem = function() {
|
|
729
|
-
return this.previouslySelectedItem_;
|
|
730
|
-
};
|
|
731
|
-
|
|
732
|
-
/**
|
|
733
|
-
* Gets whether or not the toolbox is horizontal.
|
|
734
|
-
* @return {boolean} True if the toolbox is horizontal, false if the toolbox is
|
|
735
|
-
* vertical.
|
|
736
|
-
* @public
|
|
737
|
-
*/
|
|
738
|
-
Toolbox.prototype.isHorizontal = function() {
|
|
739
|
-
return this.horizontalLayout_;
|
|
740
|
-
};
|
|
724
|
+
/**
|
|
725
|
+
* Gets the previously selected item.
|
|
726
|
+
* @return {?ISelectableToolboxItem} The previously selected item, or null if
|
|
727
|
+
* no item was previously selected.
|
|
728
|
+
* @public
|
|
729
|
+
*/
|
|
730
|
+
getPreviouslySelectedItem() {
|
|
731
|
+
return this.previouslySelectedItem_;
|
|
732
|
+
}
|
|
741
733
|
|
|
742
|
-
/**
|
|
743
|
-
|
|
744
|
-
|
|
745
|
-
|
|
746
|
-
|
|
747
|
-
|
|
748
|
-
|
|
749
|
-
|
|
750
|
-
if (!toolboxDiv) {
|
|
751
|
-
// Not initialized yet.
|
|
752
|
-
return;
|
|
734
|
+
/**
|
|
735
|
+
* Gets whether or not the toolbox is horizontal.
|
|
736
|
+
* @return {boolean} True if the toolbox is horizontal, false if the toolbox
|
|
737
|
+
* is vertical.
|
|
738
|
+
* @public
|
|
739
|
+
*/
|
|
740
|
+
isHorizontal() {
|
|
741
|
+
return this.horizontalLayout_;
|
|
753
742
|
}
|
|
754
743
|
|
|
755
|
-
|
|
756
|
-
|
|
757
|
-
|
|
758
|
-
|
|
759
|
-
|
|
760
|
-
|
|
761
|
-
|
|
762
|
-
|
|
763
|
-
|
|
764
|
-
|
|
744
|
+
/**
|
|
745
|
+
* Positions the toolbox based on whether it is a horizontal toolbox and
|
|
746
|
+
* whether the workspace is in rtl.
|
|
747
|
+
* @public
|
|
748
|
+
*/
|
|
749
|
+
position() {
|
|
750
|
+
const workspaceMetrics = this.workspace_.getMetrics();
|
|
751
|
+
const toolboxDiv = this.HtmlDiv;
|
|
752
|
+
if (!toolboxDiv) {
|
|
753
|
+
// Not initialized yet.
|
|
754
|
+
return;
|
|
765
755
|
}
|
|
766
|
-
|
|
767
|
-
if (this.
|
|
768
|
-
toolboxDiv.style.right = '0';
|
|
769
|
-
} else { // Left
|
|
756
|
+
|
|
757
|
+
if (this.horizontalLayout_) {
|
|
770
758
|
toolboxDiv.style.left = '0';
|
|
759
|
+
toolboxDiv.style.height = 'auto';
|
|
760
|
+
toolboxDiv.style.width = '100%';
|
|
761
|
+
this.height_ = toolboxDiv.offsetHeight;
|
|
762
|
+
this.width_ = workspaceMetrics.viewWidth;
|
|
763
|
+
if (this.toolboxPosition === toolbox.Position.TOP) {
|
|
764
|
+
toolboxDiv.style.top = '0';
|
|
765
|
+
} else { // Bottom
|
|
766
|
+
toolboxDiv.style.bottom = '0';
|
|
767
|
+
}
|
|
768
|
+
} else {
|
|
769
|
+
if (this.toolboxPosition === toolbox.Position.RIGHT) {
|
|
770
|
+
toolboxDiv.style.right = '0';
|
|
771
|
+
} else { // Left
|
|
772
|
+
toolboxDiv.style.left = '0';
|
|
773
|
+
}
|
|
774
|
+
toolboxDiv.style.height = '100%';
|
|
775
|
+
this.width_ = toolboxDiv.offsetWidth;
|
|
776
|
+
this.height_ = workspaceMetrics.viewHeight;
|
|
771
777
|
}
|
|
772
|
-
|
|
773
|
-
this.width_ = toolboxDiv.offsetWidth;
|
|
774
|
-
this.height_ = workspaceMetrics.viewHeight;
|
|
778
|
+
this.flyout_.position();
|
|
775
779
|
}
|
|
776
|
-
this.flyout_.position();
|
|
777
|
-
};
|
|
778
|
-
/**
|
|
779
|
-
* Handles resizing the toolbox when a toolbox item resizes.
|
|
780
|
-
* @package
|
|
781
|
-
*/
|
|
782
|
-
Toolbox.prototype.handleToolboxItemResize = function() {
|
|
783
|
-
// Reposition the workspace so that (0,0) is in the correct position relative
|
|
784
|
-
// to the new absolute edge (ie toolbox edge).
|
|
785
|
-
const workspace = this.workspace_;
|
|
786
|
-
const rect = this.HtmlDiv.getBoundingClientRect();
|
|
787
|
-
const newX = this.toolboxPosition === toolbox.Position.LEFT ?
|
|
788
|
-
workspace.scrollX + rect.width :
|
|
789
|
-
workspace.scrollX;
|
|
790
|
-
const newY = this.toolboxPosition === toolbox.Position.TOP ?
|
|
791
|
-
workspace.scrollY + rect.height :
|
|
792
|
-
workspace.scrollY;
|
|
793
|
-
workspace.translate(newX, newY);
|
|
794
|
-
|
|
795
|
-
// Even though the div hasn't changed size, the visible workspace
|
|
796
|
-
// surface of the workspace has, so we may need to reposition everything.
|
|
797
|
-
common.svgResize(workspace);
|
|
798
|
-
};
|
|
799
780
|
|
|
800
|
-
/**
|
|
801
|
-
|
|
802
|
-
|
|
803
|
-
|
|
804
|
-
|
|
805
|
-
|
|
806
|
-
|
|
807
|
-
|
|
808
|
-
|
|
809
|
-
|
|
810
|
-
|
|
811
|
-
|
|
812
|
-
|
|
813
|
-
|
|
814
|
-
|
|
815
|
-
|
|
816
|
-
|
|
817
|
-
|
|
781
|
+
/**
|
|
782
|
+
* Handles resizing the toolbox when a toolbox item resizes.
|
|
783
|
+
* @package
|
|
784
|
+
*/
|
|
785
|
+
handleToolboxItemResize() {
|
|
786
|
+
// Reposition the workspace so that (0,0) is in the correct position
|
|
787
|
+
// relative to the new absolute edge (ie toolbox edge).
|
|
788
|
+
const workspace = this.workspace_;
|
|
789
|
+
const rect = this.HtmlDiv.getBoundingClientRect();
|
|
790
|
+
const newX = this.toolboxPosition === toolbox.Position.LEFT ?
|
|
791
|
+
workspace.scrollX + rect.width :
|
|
792
|
+
workspace.scrollX;
|
|
793
|
+
const newY = this.toolboxPosition === toolbox.Position.TOP ?
|
|
794
|
+
workspace.scrollY + rect.height :
|
|
795
|
+
workspace.scrollY;
|
|
796
|
+
workspace.translate(newX, newY);
|
|
797
|
+
|
|
798
|
+
// Even though the div hasn't changed size, the visible workspace
|
|
799
|
+
// surface of the workspace has, so we may need to reposition everything.
|
|
800
|
+
common.svgResize(workspace);
|
|
818
801
|
}
|
|
819
|
-
};
|
|
820
802
|
|
|
821
|
-
/**
|
|
822
|
-
|
|
823
|
-
|
|
824
|
-
|
|
825
|
-
|
|
826
|
-
|
|
827
|
-
Toolbox.prototype.refreshSelection = function() {
|
|
828
|
-
if (this.selectedItem_ && this.selectedItem_.isSelectable() &&
|
|
829
|
-
this.selectedItem_.getContents().length) {
|
|
830
|
-
this.flyout_.show(this.selectedItem_.getContents());
|
|
803
|
+
/**
|
|
804
|
+
* Unhighlights any previously selected item.
|
|
805
|
+
* @public
|
|
806
|
+
*/
|
|
807
|
+
clearSelection() {
|
|
808
|
+
this.setSelectedItem(null);
|
|
831
809
|
}
|
|
832
|
-
};
|
|
833
810
|
|
|
834
|
-
/**
|
|
835
|
-
|
|
836
|
-
|
|
837
|
-
|
|
838
|
-
|
|
839
|
-
|
|
840
|
-
|
|
841
|
-
|
|
811
|
+
/**
|
|
812
|
+
* Updates the category colours and background colour of selected categories.
|
|
813
|
+
* @package
|
|
814
|
+
*/
|
|
815
|
+
refreshTheme() {
|
|
816
|
+
for (let i = 0; i < this.contents_.length; i++) {
|
|
817
|
+
const child = this.contents_[i];
|
|
818
|
+
if (child.refreshTheme) {
|
|
819
|
+
child.refreshTheme();
|
|
820
|
+
}
|
|
821
|
+
}
|
|
842
822
|
}
|
|
843
823
|
|
|
844
|
-
|
|
845
|
-
|
|
846
|
-
|
|
847
|
-
|
|
848
|
-
|
|
849
|
-
|
|
850
|
-
|
|
851
|
-
|
|
852
|
-
|
|
853
|
-
|
|
854
|
-
|
|
855
|
-
*/
|
|
856
|
-
Toolbox.prototype.autoHide = function(onlyClosePopups) {
|
|
857
|
-
if (!onlyClosePopups && this.flyout_ && this.flyout_.autoClose) {
|
|
858
|
-
this.clearSelection();
|
|
824
|
+
/**
|
|
825
|
+
* Updates the flyout's content without closing it. Should be used in
|
|
826
|
+
* response to a change in one of the dynamic categories, such as variables or
|
|
827
|
+
* procedures.
|
|
828
|
+
* @public
|
|
829
|
+
*/
|
|
830
|
+
refreshSelection() {
|
|
831
|
+
if (this.selectedItem_ && this.selectedItem_.isSelectable() &&
|
|
832
|
+
this.selectedItem_.getContents().length) {
|
|
833
|
+
this.flyout_.show(this.selectedItem_.getContents());
|
|
834
|
+
}
|
|
859
835
|
}
|
|
860
|
-
};
|
|
861
|
-
|
|
862
|
-
/**
|
|
863
|
-
* Sets the given item as selected.
|
|
864
|
-
* No-op if the item is not selectable.
|
|
865
|
-
* @param {?IToolboxItem} newItem The toolbox item to select.
|
|
866
|
-
* @public
|
|
867
|
-
*/
|
|
868
|
-
Toolbox.prototype.setSelectedItem = function(newItem) {
|
|
869
|
-
const oldItem = this.selectedItem_;
|
|
870
836
|
|
|
871
|
-
|
|
872
|
-
|
|
873
|
-
|
|
874
|
-
|
|
837
|
+
/**
|
|
838
|
+
* Shows or hides the toolbox.
|
|
839
|
+
* @param {boolean} isVisible True if toolbox should be visible.
|
|
840
|
+
* @public
|
|
841
|
+
*/
|
|
842
|
+
setVisible(isVisible) {
|
|
843
|
+
if (this.isVisible_ === isVisible) {
|
|
844
|
+
return;
|
|
845
|
+
}
|
|
875
846
|
|
|
876
|
-
|
|
877
|
-
this.
|
|
847
|
+
this.HtmlDiv.style.display = isVisible ? 'block' : 'none';
|
|
848
|
+
this.isVisible_ = isVisible;
|
|
849
|
+
// Invisible toolbox is ignored as drag targets and must have the drag
|
|
850
|
+
// target updated.
|
|
851
|
+
this.workspace_.recordDragTargets();
|
|
878
852
|
}
|
|
879
853
|
|
|
880
|
-
|
|
881
|
-
|
|
854
|
+
/**
|
|
855
|
+
* Hides the component. Called in WorkspaceSvg.hideChaff.
|
|
856
|
+
* @param {boolean} onlyClosePopups Whether only popups should be closed.
|
|
857
|
+
* Flyouts should not be closed if this is true.
|
|
858
|
+
*/
|
|
859
|
+
autoHide(onlyClosePopups) {
|
|
860
|
+
if (!onlyClosePopups && this.flyout_ && this.flyout_.autoClose) {
|
|
861
|
+
this.clearSelection();
|
|
862
|
+
}
|
|
882
863
|
}
|
|
883
864
|
|
|
884
|
-
|
|
885
|
-
|
|
886
|
-
|
|
887
|
-
|
|
888
|
-
|
|
889
|
-
|
|
890
|
-
|
|
891
|
-
|
|
892
|
-
* @param {?ISelectableToolboxItem} newItem The newly selected toolbox
|
|
893
|
-
* item.
|
|
894
|
-
* @return {boolean} True if the old item should be deselected, false otherwise.
|
|
895
|
-
* @protected
|
|
896
|
-
*/
|
|
897
|
-
Toolbox.prototype.shouldDeselectItem_ = function(oldItem, newItem) {
|
|
898
|
-
// Deselect the old item unless the old item is collapsible and has been
|
|
899
|
-
// previously clicked on.
|
|
900
|
-
return oldItem !== null && (!oldItem.isCollapsible() || oldItem !== newItem);
|
|
901
|
-
};
|
|
902
|
-
|
|
903
|
-
/**
|
|
904
|
-
* Decides whether the new item should be selected.
|
|
905
|
-
* @param {?ISelectableToolboxItem} oldItem The previously selected
|
|
906
|
-
* toolbox item.
|
|
907
|
-
* @param {?ISelectableToolboxItem} newItem The newly selected toolbox
|
|
908
|
-
* item.
|
|
909
|
-
* @return {boolean} True if the new item should be selected, false otherwise.
|
|
910
|
-
* @protected
|
|
911
|
-
*/
|
|
912
|
-
Toolbox.prototype.shouldSelectItem_ = function(oldItem, newItem) {
|
|
913
|
-
// Select the new item unless the old item equals the new item.
|
|
914
|
-
return newItem !== null && newItem !== oldItem;
|
|
915
|
-
};
|
|
865
|
+
/**
|
|
866
|
+
* Sets the given item as selected.
|
|
867
|
+
* No-op if the item is not selectable.
|
|
868
|
+
* @param {?IToolboxItem} newItem The toolbox item to select.
|
|
869
|
+
* @public
|
|
870
|
+
*/
|
|
871
|
+
setSelectedItem(newItem) {
|
|
872
|
+
const oldItem = this.selectedItem_;
|
|
916
873
|
|
|
917
|
-
|
|
918
|
-
|
|
919
|
-
|
|
920
|
-
|
|
921
|
-
* @protected
|
|
922
|
-
*/
|
|
923
|
-
Toolbox.prototype.deselectItem_ = function(item) {
|
|
924
|
-
this.selectedItem_ = null;
|
|
925
|
-
this.previouslySelectedItem_ = item;
|
|
926
|
-
item.setSelected(false);
|
|
927
|
-
aria.setState(
|
|
928
|
-
/** @type {!Element} */ (this.contentsDiv_), aria.State.ACTIVEDESCENDANT,
|
|
929
|
-
'');
|
|
930
|
-
};
|
|
874
|
+
if ((!newItem && !oldItem) || (newItem && !newItem.isSelectable())) {
|
|
875
|
+
return;
|
|
876
|
+
}
|
|
877
|
+
newItem = /** @type {ISelectableToolboxItem} */ (newItem);
|
|
931
878
|
|
|
932
|
-
|
|
933
|
-
|
|
934
|
-
|
|
935
|
-
* toolbox item.
|
|
936
|
-
* @param {!ISelectableToolboxItem} newItem The newly selected toolbox
|
|
937
|
-
* item.
|
|
938
|
-
* @protected
|
|
939
|
-
*/
|
|
940
|
-
Toolbox.prototype.selectItem_ = function(oldItem, newItem) {
|
|
941
|
-
this.selectedItem_ = newItem;
|
|
942
|
-
this.previouslySelectedItem_ = oldItem;
|
|
943
|
-
newItem.setSelected(true);
|
|
944
|
-
aria.setState(
|
|
945
|
-
/** @type {!Element} */ (this.contentsDiv_), aria.State.ACTIVEDESCENDANT,
|
|
946
|
-
newItem.getId());
|
|
947
|
-
};
|
|
879
|
+
if (this.shouldDeselectItem_(oldItem, newItem) && oldItem !== null) {
|
|
880
|
+
this.deselectItem_(oldItem);
|
|
881
|
+
}
|
|
948
882
|
|
|
949
|
-
|
|
950
|
-
|
|
951
|
-
* @param {number} position The position of the item to select.
|
|
952
|
-
* @public
|
|
953
|
-
*/
|
|
954
|
-
Toolbox.prototype.selectItemByPosition = function(position) {
|
|
955
|
-
if (position > -1 && position < this.contents_.length) {
|
|
956
|
-
const item = this.contents_[position];
|
|
957
|
-
if (item.isSelectable()) {
|
|
958
|
-
this.setSelectedItem(item);
|
|
883
|
+
if (this.shouldSelectItem_(oldItem, newItem) && newItem !== null) {
|
|
884
|
+
this.selectItem_(oldItem, newItem);
|
|
959
885
|
}
|
|
886
|
+
|
|
887
|
+
this.updateFlyout_(oldItem, newItem);
|
|
888
|
+
this.fireSelectEvent_(oldItem, newItem);
|
|
960
889
|
}
|
|
961
|
-
};
|
|
962
890
|
|
|
963
|
-
/**
|
|
964
|
-
|
|
965
|
-
|
|
966
|
-
|
|
967
|
-
|
|
968
|
-
|
|
969
|
-
|
|
970
|
-
|
|
971
|
-
|
|
972
|
-
|
|
973
|
-
|
|
974
|
-
|
|
975
|
-
|
|
976
|
-
|
|
891
|
+
/**
|
|
892
|
+
* Decides whether the old item should be deselected.
|
|
893
|
+
* @param {?ISelectableToolboxItem} oldItem The previously selected
|
|
894
|
+
* toolbox item.
|
|
895
|
+
* @param {?ISelectableToolboxItem} newItem The newly selected toolbox
|
|
896
|
+
* item.
|
|
897
|
+
* @return {boolean} True if the old item should be deselected, false
|
|
898
|
+
* otherwise.
|
|
899
|
+
* @protected
|
|
900
|
+
*/
|
|
901
|
+
shouldDeselectItem_(oldItem, newItem) {
|
|
902
|
+
// Deselect the old item unless the old item is collapsible and has been
|
|
903
|
+
// previously clicked on.
|
|
904
|
+
return oldItem !== null &&
|
|
905
|
+
(!oldItem.isCollapsible() || oldItem !== newItem);
|
|
977
906
|
}
|
|
978
|
-
};
|
|
979
907
|
|
|
980
|
-
/**
|
|
981
|
-
|
|
982
|
-
|
|
983
|
-
|
|
984
|
-
|
|
985
|
-
|
|
986
|
-
|
|
987
|
-
|
|
988
|
-
|
|
989
|
-
|
|
990
|
-
|
|
991
|
-
|
|
992
|
-
if (oldItem === newItem) {
|
|
993
|
-
newElement = null;
|
|
908
|
+
/**
|
|
909
|
+
* Decides whether the new item should be selected.
|
|
910
|
+
* @param {?ISelectableToolboxItem} oldItem The previously selected
|
|
911
|
+
* toolbox item.
|
|
912
|
+
* @param {?ISelectableToolboxItem} newItem The newly selected toolbox
|
|
913
|
+
* item.
|
|
914
|
+
* @return {boolean} True if the new item should be selected, false otherwise.
|
|
915
|
+
* @protected
|
|
916
|
+
*/
|
|
917
|
+
shouldSelectItem_(oldItem, newItem) {
|
|
918
|
+
// Select the new item unless the old item equals the new item.
|
|
919
|
+
return newItem !== null && newItem !== oldItem;
|
|
994
920
|
}
|
|
995
|
-
const event = new (eventUtils.get(eventUtils.TOOLBOX_ITEM_SELECT))(
|
|
996
|
-
oldElement, newElement, this.workspace_.id);
|
|
997
|
-
eventUtils.fire(event);
|
|
998
|
-
};
|
|
999
921
|
|
|
1000
|
-
/**
|
|
1001
|
-
|
|
1002
|
-
|
|
1003
|
-
|
|
1004
|
-
|
|
1005
|
-
|
|
1006
|
-
|
|
1007
|
-
|
|
922
|
+
/**
|
|
923
|
+
* Deselects the given item, marks it as unselected, and updates aria state.
|
|
924
|
+
* @param {!ISelectableToolboxItem} item The previously selected
|
|
925
|
+
* toolbox item which should be deselected.
|
|
926
|
+
* @protected
|
|
927
|
+
*/
|
|
928
|
+
deselectItem_(item) {
|
|
929
|
+
this.selectedItem_ = null;
|
|
930
|
+
this.previouslySelectedItem_ = item;
|
|
931
|
+
item.setSelected(false);
|
|
932
|
+
aria.setState(
|
|
933
|
+
/** @type {!Element} */ (this.contentsDiv_),
|
|
934
|
+
aria.State.ACTIVEDESCENDANT, '');
|
|
1008
935
|
}
|
|
1009
936
|
|
|
1010
|
-
|
|
1011
|
-
|
|
1012
|
-
|
|
1013
|
-
|
|
1014
|
-
|
|
1015
|
-
|
|
1016
|
-
|
|
1017
|
-
|
|
1018
|
-
|
|
1019
|
-
|
|
937
|
+
/**
|
|
938
|
+
* Selects the given item, marks it selected, and updates aria state.
|
|
939
|
+
* @param {?ISelectableToolboxItem} oldItem The previously selected
|
|
940
|
+
* toolbox item.
|
|
941
|
+
* @param {!ISelectableToolboxItem} newItem The newly selected toolbox
|
|
942
|
+
* item.
|
|
943
|
+
* @protected
|
|
944
|
+
*/
|
|
945
|
+
selectItem_(oldItem, newItem) {
|
|
946
|
+
this.selectedItem_ = newItem;
|
|
947
|
+
this.previouslySelectedItem_ = oldItem;
|
|
948
|
+
newItem.setSelected(true);
|
|
949
|
+
aria.setState(
|
|
950
|
+
/** @type {!Element} */ (this.contentsDiv_),
|
|
951
|
+
aria.State.ACTIVEDESCENDANT, newItem.getId());
|
|
1020
952
|
}
|
|
1021
|
-
return false;
|
|
1022
|
-
};
|
|
1023
953
|
|
|
1024
|
-
/**
|
|
1025
|
-
|
|
1026
|
-
|
|
1027
|
-
|
|
1028
|
-
|
|
1029
|
-
|
|
1030
|
-
|
|
1031
|
-
|
|
1032
|
-
|
|
954
|
+
/**
|
|
955
|
+
* Selects the toolbox item by its position in the list of toolbox items.
|
|
956
|
+
* @param {number} position The position of the item to select.
|
|
957
|
+
* @public
|
|
958
|
+
*/
|
|
959
|
+
selectItemByPosition(position) {
|
|
960
|
+
if (position > -1 && position < this.contents_.length) {
|
|
961
|
+
const item = this.contents_[position];
|
|
962
|
+
if (item.isSelectable()) {
|
|
963
|
+
this.setSelectedItem(item);
|
|
964
|
+
}
|
|
965
|
+
}
|
|
1033
966
|
}
|
|
1034
|
-
|
|
1035
|
-
|
|
1036
|
-
|
|
1037
|
-
|
|
1038
|
-
|
|
1039
|
-
|
|
1040
|
-
|
|
1041
|
-
|
|
967
|
+
|
|
968
|
+
/**
|
|
969
|
+
* Decides whether to hide or show the flyout depending on the selected item.
|
|
970
|
+
* @param {?ISelectableToolboxItem} oldItem The previously selected toolbox
|
|
971
|
+
* item.
|
|
972
|
+
* @param {?ISelectableToolboxItem} newItem The newly selected toolbox item.
|
|
973
|
+
* @protected
|
|
974
|
+
*/
|
|
975
|
+
updateFlyout_(oldItem, newItem) {
|
|
976
|
+
if (!newItem || (oldItem === newItem && !newItem.isCollapsible()) ||
|
|
977
|
+
!newItem.getContents().length) {
|
|
978
|
+
this.flyout_.hide();
|
|
979
|
+
} else {
|
|
980
|
+
this.flyout_.show(newItem.getContents());
|
|
981
|
+
this.flyout_.scrollToStart();
|
|
982
|
+
}
|
|
1042
983
|
}
|
|
1043
|
-
};
|
|
1044
984
|
|
|
1045
|
-
/**
|
|
1046
|
-
|
|
1047
|
-
|
|
1048
|
-
|
|
1049
|
-
|
|
1050
|
-
|
|
1051
|
-
|
|
1052
|
-
|
|
985
|
+
/**
|
|
986
|
+
* Emits an event when a new toolbox item is selected.
|
|
987
|
+
* @param {?ISelectableToolboxItem} oldItem The previously selected
|
|
988
|
+
* toolbox item.
|
|
989
|
+
* @param {?ISelectableToolboxItem} newItem The newly selected toolbox
|
|
990
|
+
* item.
|
|
991
|
+
* @private
|
|
992
|
+
*/
|
|
993
|
+
fireSelectEvent_(oldItem, newItem) {
|
|
994
|
+
const oldElement = oldItem && oldItem.getName();
|
|
995
|
+
let newElement = newItem && newItem.getName();
|
|
996
|
+
// In this case the toolbox closes, so the newElement should be null.
|
|
997
|
+
if (oldItem === newItem) {
|
|
998
|
+
newElement = null;
|
|
999
|
+
}
|
|
1000
|
+
const event = new (eventUtils.get(eventUtils.TOOLBOX_ITEM_SELECT))(
|
|
1001
|
+
oldElement, newElement, this.workspace_.id);
|
|
1002
|
+
eventUtils.fire(event);
|
|
1053
1003
|
}
|
|
1054
1004
|
|
|
1055
|
-
|
|
1056
|
-
|
|
1057
|
-
|
|
1058
|
-
|
|
1059
|
-
|
|
1005
|
+
/**
|
|
1006
|
+
* Closes the current item if it is expanded, or selects the parent.
|
|
1007
|
+
* @return {boolean} True if a parent category was selected, false otherwise.
|
|
1008
|
+
* @private
|
|
1009
|
+
*/
|
|
1010
|
+
selectParent_() {
|
|
1011
|
+
if (!this.selectedItem_) {
|
|
1012
|
+
return false;
|
|
1060
1013
|
}
|
|
1061
|
-
|
|
1062
|
-
|
|
1014
|
+
|
|
1015
|
+
if (this.selectedItem_.isCollapsible() && this.selectedItem_.isExpanded()) {
|
|
1016
|
+
const collapsibleItem =
|
|
1017
|
+
/** @type {!ICollapsibleToolboxItem} */ (this.selectedItem_);
|
|
1018
|
+
collapsibleItem.setExpanded(false);
|
|
1019
|
+
return true;
|
|
1020
|
+
} else if (
|
|
1021
|
+
this.selectedItem_.getParent() &&
|
|
1022
|
+
this.selectedItem_.getParent().isSelectable()) {
|
|
1023
|
+
this.setSelectedItem(this.selectedItem_.getParent());
|
|
1063
1024
|
return true;
|
|
1064
1025
|
}
|
|
1065
|
-
}
|
|
1066
|
-
return false;
|
|
1067
|
-
};
|
|
1068
|
-
|
|
1069
|
-
/**
|
|
1070
|
-
* Selects the previous visible toolbox item.
|
|
1071
|
-
* @return {boolean} True if a previous category was selected, false otherwise.
|
|
1072
|
-
* @private
|
|
1073
|
-
*/
|
|
1074
|
-
Toolbox.prototype.selectPrevious_ = function() {
|
|
1075
|
-
if (!this.selectedItem_) {
|
|
1076
1026
|
return false;
|
|
1077
1027
|
}
|
|
1078
1028
|
|
|
1079
|
-
|
|
1080
|
-
|
|
1081
|
-
|
|
1082
|
-
|
|
1083
|
-
|
|
1029
|
+
/**
|
|
1030
|
+
* Selects the first child of the currently selected item, or nothing if the
|
|
1031
|
+
* toolbox item has no children.
|
|
1032
|
+
* @return {boolean} True if a child category was selected, false otherwise.
|
|
1033
|
+
* @private
|
|
1034
|
+
*/
|
|
1035
|
+
selectChild_() {
|
|
1036
|
+
if (!this.selectedItem_ || !this.selectedItem_.isCollapsible()) {
|
|
1037
|
+
return false;
|
|
1084
1038
|
}
|
|
1085
|
-
|
|
1086
|
-
|
|
1039
|
+
const collapsibleItem = /** @type {ICollapsibleToolboxItem} */
|
|
1040
|
+
(this.selectedItem_);
|
|
1041
|
+
if (!collapsibleItem.isExpanded()) {
|
|
1042
|
+
collapsibleItem.setExpanded(true);
|
|
1043
|
+
return true;
|
|
1044
|
+
} else {
|
|
1045
|
+
this.selectNext_();
|
|
1087
1046
|
return true;
|
|
1088
1047
|
}
|
|
1089
1048
|
}
|
|
1090
|
-
return false;
|
|
1091
|
-
};
|
|
1092
1049
|
|
|
1093
|
-
/**
|
|
1094
|
-
|
|
1095
|
-
|
|
1096
|
-
|
|
1097
|
-
|
|
1098
|
-
|
|
1099
|
-
|
|
1100
|
-
|
|
1101
|
-
|
|
1102
|
-
toolboxItem.dispose();
|
|
1103
|
-
}
|
|
1050
|
+
/**
|
|
1051
|
+
* Selects the next visible toolbox item.
|
|
1052
|
+
* @return {boolean} True if a next category was selected, false otherwise.
|
|
1053
|
+
* @private
|
|
1054
|
+
*/
|
|
1055
|
+
selectNext_() {
|
|
1056
|
+
if (!this.selectedItem_) {
|
|
1057
|
+
return false;
|
|
1058
|
+
}
|
|
1104
1059
|
|
|
1105
|
-
|
|
1106
|
-
|
|
1060
|
+
let nextItemIdx = this.contents_.indexOf(this.selectedItem_) + 1;
|
|
1061
|
+
if (nextItemIdx > -1 && nextItemIdx < this.contents_.length) {
|
|
1062
|
+
let nextItem = this.contents_[nextItemIdx];
|
|
1063
|
+
while (nextItem && !nextItem.isSelectable()) {
|
|
1064
|
+
nextItem = this.contents_[++nextItemIdx];
|
|
1065
|
+
}
|
|
1066
|
+
if (nextItem && nextItem.isSelectable()) {
|
|
1067
|
+
this.setSelectedItem(nextItem);
|
|
1068
|
+
return true;
|
|
1069
|
+
}
|
|
1070
|
+
}
|
|
1071
|
+
return false;
|
|
1107
1072
|
}
|
|
1108
|
-
this.boundEvents_ = [];
|
|
1109
|
-
this.contents_ = [];
|
|
1110
1073
|
|
|
1111
|
-
|
|
1112
|
-
|
|
1113
|
-
}
|
|
1074
|
+
/**
|
|
1075
|
+
* Selects the previous visible toolbox item.
|
|
1076
|
+
* @return {boolean} True if a previous category was selected, false
|
|
1077
|
+
* otherwise.
|
|
1078
|
+
* @private
|
|
1079
|
+
*/
|
|
1080
|
+
selectPrevious_() {
|
|
1081
|
+
if (!this.selectedItem_) {
|
|
1082
|
+
return false;
|
|
1083
|
+
}
|
|
1114
1084
|
|
|
1115
|
-
|
|
1116
|
-
|
|
1117
|
-
|
|
1118
|
-
|
|
1119
|
-
|
|
1120
|
-
|
|
1085
|
+
let prevItemIdx = this.contents_.indexOf(this.selectedItem_) - 1;
|
|
1086
|
+
if (prevItemIdx > -1 && prevItemIdx < this.contents_.length) {
|
|
1087
|
+
let prevItem = this.contents_[prevItemIdx];
|
|
1088
|
+
while (prevItem && !prevItem.isSelectable()) {
|
|
1089
|
+
prevItem = this.contents_[--prevItemIdx];
|
|
1090
|
+
}
|
|
1091
|
+
if (prevItem && prevItem.isSelectable()) {
|
|
1092
|
+
this.setSelectedItem(prevItem);
|
|
1093
|
+
return true;
|
|
1094
|
+
}
|
|
1095
|
+
}
|
|
1096
|
+
return false;
|
|
1121
1097
|
}
|
|
1122
1098
|
|
|
1123
|
-
|
|
1124
|
-
|
|
1125
|
-
|
|
1126
|
-
|
|
1127
|
-
|
|
1099
|
+
/**
|
|
1100
|
+
* Disposes of this toolbox.
|
|
1101
|
+
* @public
|
|
1102
|
+
*/
|
|
1103
|
+
dispose() {
|
|
1104
|
+
this.workspace_.getComponentManager().removeComponent('toolbox');
|
|
1105
|
+
this.flyout_.dispose();
|
|
1106
|
+
for (let i = 0; i < this.contents_.length; i++) {
|
|
1107
|
+
const toolboxItem = this.contents_[i];
|
|
1108
|
+
toolboxItem.dispose();
|
|
1109
|
+
}
|
|
1128
1110
|
|
|
1129
|
-
|
|
1130
|
-
|
|
1131
|
-
|
|
1132
|
-
|
|
1133
|
-
|
|
1134
|
-
padding: 4px 0 4px 0;
|
|
1135
|
-
position: absolute;
|
|
1136
|
-
z-index: 70; /* so blocks go under toolbox when dragging */
|
|
1137
|
-
-webkit-tap-highlight-color: transparent; /* issue #1345 */
|
|
1138
|
-
}
|
|
1111
|
+
for (let j = 0; j < this.boundEvents_.length; j++) {
|
|
1112
|
+
browserEvents.unbind(this.boundEvents_[j]);
|
|
1113
|
+
}
|
|
1114
|
+
this.boundEvents_ = [];
|
|
1115
|
+
this.contents_ = [];
|
|
1139
1116
|
|
|
1140
|
-
|
|
1141
|
-
|
|
1142
|
-
flex-wrap: wrap;
|
|
1143
|
-
flex-direction: column;
|
|
1117
|
+
this.workspace_.getThemeManager().unsubscribe(this.HtmlDiv);
|
|
1118
|
+
dom.removeNode(this.HtmlDiv);
|
|
1144
1119
|
}
|
|
1120
|
+
}
|
|
1145
1121
|
|
|
1146
|
-
|
|
1147
|
-
|
|
1148
|
-
|
|
1122
|
+
/**
|
|
1123
|
+
* CSS for Toolbox. See css.js for use.
|
|
1124
|
+
*/
|
|
1125
|
+
Css.register(`
|
|
1126
|
+
.blocklyToolboxDelete {
|
|
1127
|
+
cursor: url("<<<PATH>>>/handdelete.cur"), auto;
|
|
1128
|
+
}
|
|
1129
|
+
|
|
1130
|
+
.blocklyToolboxGrab {
|
|
1131
|
+
cursor: url("<<<PATH>>>/handclosed.cur"), auto;
|
|
1132
|
+
cursor: grabbing;
|
|
1133
|
+
cursor: -webkit-grabbing;
|
|
1134
|
+
}
|
|
1135
|
+
|
|
1136
|
+
/* Category tree in Toolbox. */
|
|
1137
|
+
.blocklyToolboxDiv {
|
|
1138
|
+
background-color: #ddd;
|
|
1139
|
+
overflow-x: visible;
|
|
1140
|
+
overflow-y: auto;
|
|
1141
|
+
padding: 4px 0 4px 0;
|
|
1142
|
+
position: absolute;
|
|
1143
|
+
z-index: 70; /* so blocks go under toolbox when dragging */
|
|
1144
|
+
-webkit-tap-highlight-color: transparent; /* issue #1345 */
|
|
1145
|
+
}
|
|
1146
|
+
|
|
1147
|
+
.blocklyToolboxContents {
|
|
1148
|
+
display: flex;
|
|
1149
|
+
flex-wrap: wrap;
|
|
1150
|
+
flex-direction: column;
|
|
1151
|
+
}
|
|
1152
|
+
|
|
1153
|
+
.blocklyToolboxContents:focus {
|
|
1154
|
+
outline: none;
|
|
1155
|
+
}
|
|
1149
1156
|
`);
|
|
1150
1157
|
|
|
1151
1158
|
registry.register(registry.Type.TOOLBOX, registry.DEFAULT, Toolbox);
|