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/workspace.js
CHANGED
|
@@ -15,8 +15,6 @@
|
|
|
15
15
|
*/
|
|
16
16
|
goog.module('Blockly.Workspace');
|
|
17
17
|
|
|
18
|
-
/* eslint-disable-next-line no-unused-vars */
|
|
19
|
-
const Abstract = goog.requireType('Blockly.Events.Abstract');
|
|
20
18
|
const arrayUtils = goog.require('Blockly.utils.array');
|
|
21
19
|
const eventUtils = goog.require('Blockly.Events.utils');
|
|
22
20
|
const idGenerator = goog.require('Blockly.utils.idGenerator');
|
|
@@ -25,6 +23,8 @@ const registry = goog.require('Blockly.registry');
|
|
|
25
23
|
/* eslint-disable-next-line no-unused-vars */
|
|
26
24
|
const toolbox = goog.requireType('Blockly.utils.toolbox');
|
|
27
25
|
/* eslint-disable-next-line no-unused-vars */
|
|
26
|
+
const {Abstract} = goog.requireType('Blockly.Events.Abstract');
|
|
27
|
+
/* eslint-disable-next-line no-unused-vars */
|
|
28
28
|
const {BlocklyOptions} = goog.requireType('Blockly.BlocklyOptions');
|
|
29
29
|
/* eslint-disable-next-line no-unused-vars */
|
|
30
30
|
const {Block} = goog.requireType('Blockly.Block');
|
|
@@ -53,763 +53,784 @@ const WorkspaceDB_ = Object.create(null);
|
|
|
53
53
|
/**
|
|
54
54
|
* Class for a workspace. This is a data structure that contains blocks.
|
|
55
55
|
* There is no UI, and can be created headlessly.
|
|
56
|
-
* @param {!Options=} opt_options Dictionary of options.
|
|
57
|
-
* @constructor
|
|
58
56
|
* @implements {IASTNodeLocation}
|
|
59
57
|
* @alias Blockly.Workspace
|
|
60
58
|
*/
|
|
61
|
-
|
|
62
|
-
/** @type {string} */
|
|
63
|
-
this.id = idGenerator.genUid();
|
|
64
|
-
WorkspaceDB_[this.id] = this;
|
|
65
|
-
/** @type {!Options} */
|
|
66
|
-
this.options =
|
|
67
|
-
opt_options || new Options(/** @type {!BlocklyOptions} */ ({}));
|
|
68
|
-
/** @type {boolean} */
|
|
69
|
-
this.RTL = !!this.options.RTL;
|
|
70
|
-
/** @type {boolean} */
|
|
71
|
-
this.horizontalLayout = !!this.options.horizontalLayout;
|
|
72
|
-
/** @type {toolbox.Position} */
|
|
73
|
-
this.toolboxPosition = this.options.toolboxPosition;
|
|
74
|
-
|
|
75
|
-
const connectionCheckerClass = registry.getClassFromOptions(
|
|
76
|
-
registry.Type.CONNECTION_CHECKER, this.options, true);
|
|
77
|
-
/**
|
|
78
|
-
* An object that encapsulates logic for safety, type, and dragging checks.
|
|
79
|
-
* @type {!IConnectionChecker}
|
|
80
|
-
*/
|
|
81
|
-
this.connectionChecker = new connectionCheckerClass(this);
|
|
82
|
-
|
|
83
|
-
/**
|
|
84
|
-
* @type {!Array<!Block>}
|
|
85
|
-
* @private
|
|
86
|
-
*/
|
|
87
|
-
this.topBlocks_ = [];
|
|
59
|
+
class Workspace {
|
|
88
60
|
/**
|
|
89
|
-
* @
|
|
90
|
-
* @private
|
|
61
|
+
* @param {!Options=} opt_options Dictionary of options.
|
|
91
62
|
*/
|
|
92
|
-
|
|
63
|
+
constructor(opt_options) {
|
|
64
|
+
/** @type {string} */
|
|
65
|
+
this.id = idGenerator.genUid();
|
|
66
|
+
WorkspaceDB_[this.id] = this;
|
|
67
|
+
/** @type {!Options} */
|
|
68
|
+
this.options =
|
|
69
|
+
opt_options || new Options(/** @type {!BlocklyOptions} */ ({}));
|
|
70
|
+
/** @type {boolean} */
|
|
71
|
+
this.RTL = !!this.options.RTL;
|
|
72
|
+
/** @type {boolean} */
|
|
73
|
+
this.horizontalLayout = !!this.options.horizontalLayout;
|
|
74
|
+
/** @type {toolbox.Position} */
|
|
75
|
+
this.toolboxPosition = this.options.toolboxPosition;
|
|
76
|
+
|
|
77
|
+
/**
|
|
78
|
+
* Returns `true` if the workspace is visible and `false` if it's headless.
|
|
79
|
+
* @type {boolean}
|
|
80
|
+
*/
|
|
81
|
+
this.rendered = false;
|
|
82
|
+
|
|
83
|
+
/**
|
|
84
|
+
* Is this workspace the surface for a flyout?
|
|
85
|
+
* @type {boolean}
|
|
86
|
+
*/
|
|
87
|
+
this.isFlyout = false;
|
|
88
|
+
|
|
89
|
+
/**
|
|
90
|
+
* Is this workspace the surface for a mutator?
|
|
91
|
+
* @type {boolean}
|
|
92
|
+
* @package
|
|
93
|
+
*/
|
|
94
|
+
this.isMutator = false;
|
|
95
|
+
|
|
96
|
+
/**
|
|
97
|
+
* Returns `true` if the workspace is currently in the process of a bulk
|
|
98
|
+
* clear.
|
|
99
|
+
* @type {boolean}
|
|
100
|
+
* @package
|
|
101
|
+
*/
|
|
102
|
+
this.isClearing = false;
|
|
103
|
+
|
|
104
|
+
/**
|
|
105
|
+
* Maximum number of undo events in stack. `0` turns off undo, `Infinity`
|
|
106
|
+
* sets it to unlimited.
|
|
107
|
+
* @type {number}
|
|
108
|
+
*/
|
|
109
|
+
this.MAX_UNDO = 1024;
|
|
110
|
+
|
|
111
|
+
/**
|
|
112
|
+
* Set of databases for rapid lookup of connection locations.
|
|
113
|
+
* @type {Array<!ConnectionDB>}
|
|
114
|
+
*/
|
|
115
|
+
this.connectionDBList = null;
|
|
116
|
+
|
|
117
|
+
const connectionCheckerClass = registry.getClassFromOptions(
|
|
118
|
+
registry.Type.CONNECTION_CHECKER, this.options, true);
|
|
119
|
+
/**
|
|
120
|
+
* An object that encapsulates logic for safety, type, and dragging checks.
|
|
121
|
+
* @type {!IConnectionChecker}
|
|
122
|
+
*/
|
|
123
|
+
this.connectionChecker = new connectionCheckerClass(this);
|
|
124
|
+
|
|
125
|
+
/**
|
|
126
|
+
* @type {!Array<!Block>}
|
|
127
|
+
* @private
|
|
128
|
+
*/
|
|
129
|
+
this.topBlocks_ = [];
|
|
130
|
+
/**
|
|
131
|
+
* @type {!Array<!WorkspaceComment>}
|
|
132
|
+
* @private
|
|
133
|
+
*/
|
|
134
|
+
this.topComments_ = [];
|
|
135
|
+
/**
|
|
136
|
+
* @type {!Object}
|
|
137
|
+
* @private
|
|
138
|
+
*/
|
|
139
|
+
this.commentDB_ = Object.create(null);
|
|
140
|
+
/**
|
|
141
|
+
* @type {!Array<!Function>}
|
|
142
|
+
* @private
|
|
143
|
+
*/
|
|
144
|
+
this.listeners_ = [];
|
|
145
|
+
/**
|
|
146
|
+
* @type {!Array<!Abstract>}
|
|
147
|
+
* @protected
|
|
148
|
+
*/
|
|
149
|
+
this.undoStack_ = [];
|
|
150
|
+
/**
|
|
151
|
+
* @type {!Array<!Abstract>}
|
|
152
|
+
* @protected
|
|
153
|
+
*/
|
|
154
|
+
this.redoStack_ = [];
|
|
155
|
+
/**
|
|
156
|
+
* @type {!Object}
|
|
157
|
+
* @private
|
|
158
|
+
*/
|
|
159
|
+
this.blockDB_ = Object.create(null);
|
|
160
|
+
/**
|
|
161
|
+
* @type {!Object}
|
|
162
|
+
* @private
|
|
163
|
+
*/
|
|
164
|
+
this.typedBlocksDB_ = Object.create(null);
|
|
165
|
+
|
|
166
|
+
/**
|
|
167
|
+
* A map from variable type to list of variable names. The lists contain
|
|
168
|
+
* all of the named variables in the workspace, including variables that are
|
|
169
|
+
* not currently in use.
|
|
170
|
+
* @type {!VariableMap}
|
|
171
|
+
* @private
|
|
172
|
+
*/
|
|
173
|
+
this.variableMap_ = new VariableMap(this);
|
|
174
|
+
|
|
175
|
+
/**
|
|
176
|
+
* Blocks in the flyout can refer to variables that don't exist in the main
|
|
177
|
+
* workspace. For instance, the "get item in list" block refers to an
|
|
178
|
+
* "item" variable regardless of whether the variable has been created yet.
|
|
179
|
+
* A FieldVariable must always refer to a VariableModel. We reconcile
|
|
180
|
+
* these by tracking "potential" variables in the flyout. These variables
|
|
181
|
+
* become real when references to them are dragged into the main workspace.
|
|
182
|
+
* @type {?VariableMap}
|
|
183
|
+
* @private
|
|
184
|
+
*/
|
|
185
|
+
this.potentialVariableMap_ = null;
|
|
186
|
+
}
|
|
187
|
+
|
|
93
188
|
/**
|
|
94
|
-
*
|
|
95
|
-
*
|
|
189
|
+
* Dispose of this workspace.
|
|
190
|
+
* Unlink from all DOM elements to prevent memory leaks.
|
|
191
|
+
* @suppress {checkTypes}
|
|
96
192
|
*/
|
|
97
|
-
|
|
193
|
+
dispose() {
|
|
194
|
+
this.listeners_.length = 0;
|
|
195
|
+
this.clear();
|
|
196
|
+
// Remove from workspace database.
|
|
197
|
+
delete WorkspaceDB_[this.id];
|
|
198
|
+
}
|
|
199
|
+
|
|
98
200
|
/**
|
|
99
|
-
*
|
|
201
|
+
* Compare function for sorting objects (blocks, comments, etc) by position;
|
|
202
|
+
* top to bottom (with slight LTR or RTL bias).
|
|
203
|
+
* @param {!Block | !WorkspaceComment} a The first object to
|
|
204
|
+
* compare.
|
|
205
|
+
* @param {!Block | !WorkspaceComment} b The second object to
|
|
206
|
+
* compare.
|
|
207
|
+
* @return {number} The comparison value. This tells Array.sort() how to
|
|
208
|
+
* change object a's index.
|
|
100
209
|
* @private
|
|
101
210
|
*/
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
* @type {!Array<!Abstract>}
|
|
110
|
-
* @protected
|
|
111
|
-
*/
|
|
112
|
-
this.redoStack_ = [];
|
|
211
|
+
sortObjects_(a, b) {
|
|
212
|
+
const aXY = a.getRelativeToSurfaceXY();
|
|
213
|
+
const bXY = b.getRelativeToSurfaceXY();
|
|
214
|
+
return (aXY.y + Workspace.prototype.sortObjects_.offset * aXY.x) -
|
|
215
|
+
(bXY.y + Workspace.prototype.sortObjects_.offset * bXY.x);
|
|
216
|
+
}
|
|
217
|
+
|
|
113
218
|
/**
|
|
114
|
-
*
|
|
115
|
-
* @
|
|
219
|
+
* Adds a block to the list of top blocks.
|
|
220
|
+
* @param {!Block} block Block to add.
|
|
116
221
|
*/
|
|
117
|
-
|
|
222
|
+
addTopBlock(block) {
|
|
223
|
+
this.topBlocks_.push(block);
|
|
224
|
+
}
|
|
225
|
+
|
|
118
226
|
/**
|
|
119
|
-
*
|
|
120
|
-
* @
|
|
227
|
+
* Removes a block from the list of top blocks.
|
|
228
|
+
* @param {!Block} block Block to remove.
|
|
121
229
|
*/
|
|
122
|
-
|
|
230
|
+
removeTopBlock(block) {
|
|
231
|
+
if (!arrayUtils.removeElem(this.topBlocks_, block)) {
|
|
232
|
+
throw Error('Block not present in workspace\'s list of top-most blocks.');
|
|
233
|
+
}
|
|
234
|
+
}
|
|
123
235
|
|
|
124
236
|
/**
|
|
125
|
-
*
|
|
126
|
-
*
|
|
127
|
-
*
|
|
128
|
-
* @
|
|
129
|
-
* @private
|
|
237
|
+
* Finds the top-level blocks and returns them. Blocks are optionally sorted
|
|
238
|
+
* by position; top to bottom (with slight LTR or RTL bias).
|
|
239
|
+
* @param {boolean} ordered Sort the list if true.
|
|
240
|
+
* @return {!Array<!Block>} The top-level block objects.
|
|
130
241
|
*/
|
|
131
|
-
|
|
242
|
+
getTopBlocks(ordered) {
|
|
243
|
+
// Copy the topBlocks_ list.
|
|
244
|
+
const blocks = [].concat(this.topBlocks_);
|
|
245
|
+
if (ordered && blocks.length > 1) {
|
|
246
|
+
this.sortObjects_.offset = Math.sin(math.toRadians(Workspace.SCAN_ANGLE));
|
|
247
|
+
if (this.RTL) {
|
|
248
|
+
this.sortObjects_.offset *= -1;
|
|
249
|
+
}
|
|
250
|
+
blocks.sort(this.sortObjects_);
|
|
251
|
+
}
|
|
252
|
+
return blocks;
|
|
253
|
+
}
|
|
132
254
|
|
|
133
255
|
/**
|
|
134
|
-
*
|
|
135
|
-
*
|
|
136
|
-
* variable regardless of whether the variable has been created yet.
|
|
137
|
-
* A FieldVariable must always refer to a VariableModel. We reconcile
|
|
138
|
-
* these by tracking "potential" variables in the flyout. These variables
|
|
139
|
-
* become real when references to them are dragged into the main workspace.
|
|
140
|
-
* @type {?VariableMap}
|
|
141
|
-
* @private
|
|
256
|
+
* Add a block to the list of blocks keyed by type.
|
|
257
|
+
* @param {!Block} block Block to add.
|
|
142
258
|
*/
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
* @type {boolean}
|
|
149
|
-
*/
|
|
150
|
-
Workspace.prototype.rendered = false;
|
|
151
|
-
|
|
152
|
-
/**
|
|
153
|
-
* Returns `true` if the workspace is currently in the process of a bulk clear.
|
|
154
|
-
* @type {boolean}
|
|
155
|
-
* @package
|
|
156
|
-
*/
|
|
157
|
-
Workspace.prototype.isClearing = false;
|
|
158
|
-
|
|
159
|
-
/**
|
|
160
|
-
* Maximum number of undo events in stack. `0` turns off undo, `Infinity` sets
|
|
161
|
-
* it to unlimited.
|
|
162
|
-
* @type {number}
|
|
163
|
-
*/
|
|
164
|
-
Workspace.prototype.MAX_UNDO = 1024;
|
|
165
|
-
|
|
166
|
-
/**
|
|
167
|
-
* Set of databases for rapid lookup of connection locations.
|
|
168
|
-
* @type {Array<!ConnectionDB>}
|
|
169
|
-
*/
|
|
170
|
-
Workspace.prototype.connectionDBList = null;
|
|
171
|
-
|
|
172
|
-
/**
|
|
173
|
-
* Dispose of this workspace.
|
|
174
|
-
* Unlink from all DOM elements to prevent memory leaks.
|
|
175
|
-
* @suppress {checkTypes}
|
|
176
|
-
*/
|
|
177
|
-
Workspace.prototype.dispose = function() {
|
|
178
|
-
this.listeners_.length = 0;
|
|
179
|
-
this.clear();
|
|
180
|
-
// Remove from workspace database.
|
|
181
|
-
delete WorkspaceDB_[this.id];
|
|
182
|
-
};
|
|
183
|
-
|
|
184
|
-
/**
|
|
185
|
-
* Angle away from the horizontal to sweep for blocks. Order of execution is
|
|
186
|
-
* generally top to bottom, but a small angle changes the scan to give a bit of
|
|
187
|
-
* a left to right bias (reversed in RTL). Units are in degrees.
|
|
188
|
-
* See: https://tvtropes.org/pmwiki/pmwiki.php/Main/DiagonalBilling
|
|
189
|
-
*/
|
|
190
|
-
Workspace.SCAN_ANGLE = 3;
|
|
191
|
-
|
|
192
|
-
/**
|
|
193
|
-
* Compare function for sorting objects (blocks, comments, etc) by position;
|
|
194
|
-
* top to bottom (with slight LTR or RTL bias).
|
|
195
|
-
* @param {!Block | !WorkspaceComment} a The first object to
|
|
196
|
-
* compare.
|
|
197
|
-
* @param {!Block | !WorkspaceComment} b The second object to
|
|
198
|
-
* compare.
|
|
199
|
-
* @return {number} The comparison value. This tells Array.sort() how to change
|
|
200
|
-
* object a's index.
|
|
201
|
-
* @private
|
|
202
|
-
*/
|
|
203
|
-
Workspace.prototype.sortObjects_ = function(a, b) {
|
|
204
|
-
const aXY = a.getRelativeToSurfaceXY();
|
|
205
|
-
const bXY = b.getRelativeToSurfaceXY();
|
|
206
|
-
return (aXY.y + Workspace.prototype.sortObjects_.offset * aXY.x) -
|
|
207
|
-
(bXY.y + Workspace.prototype.sortObjects_.offset * bXY.x);
|
|
208
|
-
};
|
|
209
|
-
|
|
210
|
-
/**
|
|
211
|
-
* Adds a block to the list of top blocks.
|
|
212
|
-
* @param {!Block} block Block to add.
|
|
213
|
-
*/
|
|
214
|
-
Workspace.prototype.addTopBlock = function(block) {
|
|
215
|
-
this.topBlocks_.push(block);
|
|
216
|
-
};
|
|
217
|
-
|
|
218
|
-
/**
|
|
219
|
-
* Removes a block from the list of top blocks.
|
|
220
|
-
* @param {!Block} block Block to remove.
|
|
221
|
-
*/
|
|
222
|
-
Workspace.prototype.removeTopBlock = function(block) {
|
|
223
|
-
if (!arrayUtils.removeElem(this.topBlocks_, block)) {
|
|
224
|
-
throw Error('Block not present in workspace\'s list of top-most blocks.');
|
|
259
|
+
addTypedBlock(block) {
|
|
260
|
+
if (!this.typedBlocksDB_[block.type]) {
|
|
261
|
+
this.typedBlocksDB_[block.type] = [];
|
|
262
|
+
}
|
|
263
|
+
this.typedBlocksDB_[block.type].push(block);
|
|
225
264
|
}
|
|
226
|
-
};
|
|
227
265
|
|
|
228
|
-
/**
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
const blocks = [].concat(this.topBlocks_);
|
|
237
|
-
if (ordered && blocks.length > 1) {
|
|
238
|
-
this.sortObjects_.offset = Math.sin(math.toRadians(Workspace.SCAN_ANGLE));
|
|
239
|
-
if (this.RTL) {
|
|
240
|
-
this.sortObjects_.offset *= -1;
|
|
266
|
+
/**
|
|
267
|
+
* Remove a block from the list of blocks keyed by type.
|
|
268
|
+
* @param {!Block} block Block to remove.
|
|
269
|
+
*/
|
|
270
|
+
removeTypedBlock(block) {
|
|
271
|
+
arrayUtils.removeElem(this.typedBlocksDB_[block.type], block);
|
|
272
|
+
if (!this.typedBlocksDB_[block.type].length) {
|
|
273
|
+
delete this.typedBlocksDB_[block.type];
|
|
241
274
|
}
|
|
242
|
-
blocks.sort(this.sortObjects_);
|
|
243
275
|
}
|
|
244
|
-
return blocks;
|
|
245
|
-
};
|
|
246
276
|
|
|
247
|
-
/**
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
277
|
+
/**
|
|
278
|
+
* Finds the blocks with the associated type and returns them. Blocks are
|
|
279
|
+
* optionally sorted by position; top to bottom (with slight LTR or RTL bias).
|
|
280
|
+
* @param {string} type The type of block to search for.
|
|
281
|
+
* @param {boolean} ordered Sort the list if true.
|
|
282
|
+
* @return {!Array<!Block>} The blocks of the given type.
|
|
283
|
+
*/
|
|
284
|
+
getBlocksByType(type, ordered) {
|
|
285
|
+
if (!this.typedBlocksDB_[type]) {
|
|
286
|
+
return [];
|
|
287
|
+
}
|
|
288
|
+
const blocks = this.typedBlocksDB_[type].slice(0);
|
|
289
|
+
if (ordered && blocks.length > 1) {
|
|
290
|
+
this.sortObjects_.offset = Math.sin(math.toRadians(Workspace.SCAN_ANGLE));
|
|
291
|
+
if (this.RTL) {
|
|
292
|
+
this.sortObjects_.offset *= -1;
|
|
293
|
+
}
|
|
294
|
+
blocks.sort(this.sortObjects_);
|
|
295
|
+
}
|
|
257
296
|
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
*/
|
|
262
|
-
Workspace.prototype.removeTypedBlock = function(block) {
|
|
263
|
-
arrayUtils.removeElem(this.typedBlocksDB_[block.type], block);
|
|
264
|
-
if (!this.typedBlocksDB_[block.type].length) {
|
|
265
|
-
delete this.typedBlocksDB_[block.type];
|
|
297
|
+
return blocks.filter(function(block) {
|
|
298
|
+
return !block.isInsertionMarker();
|
|
299
|
+
});
|
|
266
300
|
}
|
|
267
|
-
};
|
|
268
301
|
|
|
269
|
-
/**
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
if (this.RTL) {
|
|
284
|
-
this.sortObjects_.offset *= -1;
|
|
302
|
+
/**
|
|
303
|
+
* Adds a comment to the list of top comments.
|
|
304
|
+
* @param {!WorkspaceComment} comment comment to add.
|
|
305
|
+
* @package
|
|
306
|
+
*/
|
|
307
|
+
addTopComment(comment) {
|
|
308
|
+
this.topComments_.push(comment);
|
|
309
|
+
|
|
310
|
+
// Note: If the comment database starts to hold block comments, this may
|
|
311
|
+
// need to move to a separate function.
|
|
312
|
+
if (this.commentDB_[comment.id]) {
|
|
313
|
+
console.warn(
|
|
314
|
+
'Overriding an existing comment on this workspace, with id "' +
|
|
315
|
+
comment.id + '"');
|
|
285
316
|
}
|
|
286
|
-
|
|
287
|
-
}
|
|
288
|
-
|
|
289
|
-
return blocks.filter(function(block) {
|
|
290
|
-
return !block.isInsertionMarker();
|
|
291
|
-
});
|
|
292
|
-
};
|
|
293
|
-
|
|
294
|
-
/**
|
|
295
|
-
* Adds a comment to the list of top comments.
|
|
296
|
-
* @param {!WorkspaceComment} comment comment to add.
|
|
297
|
-
* @package
|
|
298
|
-
*/
|
|
299
|
-
Workspace.prototype.addTopComment = function(comment) {
|
|
300
|
-
this.topComments_.push(comment);
|
|
301
|
-
|
|
302
|
-
// Note: If the comment database starts to hold block comments, this may need
|
|
303
|
-
// to move to a separate function.
|
|
304
|
-
if (this.commentDB_[comment.id]) {
|
|
305
|
-
console.warn(
|
|
306
|
-
'Overriding an existing comment on this workspace, with id "' +
|
|
307
|
-
comment.id + '"');
|
|
317
|
+
this.commentDB_[comment.id] = comment;
|
|
308
318
|
}
|
|
309
|
-
this.commentDB_[comment.id] = comment;
|
|
310
|
-
};
|
|
311
319
|
|
|
312
|
-
/**
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
320
|
+
/**
|
|
321
|
+
* Removes a comment from the list of top comments.
|
|
322
|
+
* @param {!WorkspaceComment} comment comment to remove.
|
|
323
|
+
* @package
|
|
324
|
+
*/
|
|
325
|
+
removeTopComment(comment) {
|
|
326
|
+
if (!arrayUtils.removeElem(this.topComments_, comment)) {
|
|
327
|
+
throw Error(
|
|
328
|
+
'Comment not present in workspace\'s list of top-most ' +
|
|
329
|
+
'comments.');
|
|
330
|
+
}
|
|
331
|
+
// Note: If the comment database starts to hold block comments, this may
|
|
332
|
+
// need to move to a separate function.
|
|
333
|
+
delete this.commentDB_[comment.id];
|
|
322
334
|
}
|
|
323
|
-
// Note: If the comment database starts to hold block comments, this may need
|
|
324
|
-
// to move to a separate function.
|
|
325
|
-
delete this.commentDB_[comment.id];
|
|
326
|
-
};
|
|
327
335
|
|
|
328
|
-
/**
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
336
|
+
/**
|
|
337
|
+
* Finds the top-level comments and returns them. Comments are optionally
|
|
338
|
+
* sorted by position; top to bottom (with slight LTR or RTL bias).
|
|
339
|
+
* @param {boolean} ordered Sort the list if true.
|
|
340
|
+
* @return {!Array<!WorkspaceComment>} The top-level comment objects.
|
|
341
|
+
* @package
|
|
342
|
+
*/
|
|
343
|
+
getTopComments(ordered) {
|
|
344
|
+
// Copy the topComments_ list.
|
|
345
|
+
const comments = [].concat(this.topComments_);
|
|
346
|
+
if (ordered && comments.length > 1) {
|
|
347
|
+
this.sortObjects_.offset = Math.sin(math.toRadians(Workspace.SCAN_ANGLE));
|
|
348
|
+
if (this.RTL) {
|
|
349
|
+
this.sortObjects_.offset *= -1;
|
|
350
|
+
}
|
|
351
|
+
comments.sort(this.sortObjects_);
|
|
342
352
|
}
|
|
343
|
-
comments
|
|
353
|
+
return comments;
|
|
344
354
|
}
|
|
345
|
-
return comments;
|
|
346
|
-
};
|
|
347
355
|
|
|
348
|
-
/**
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
356
|
+
/**
|
|
357
|
+
* Find all blocks in workspace. Blocks are optionally sorted
|
|
358
|
+
* by position; top to bottom (with slight LTR or RTL bias).
|
|
359
|
+
* @param {boolean} ordered Sort the list if true.
|
|
360
|
+
* @return {!Array<!Block>} Array of blocks.
|
|
361
|
+
*/
|
|
362
|
+
getAllBlocks(ordered) {
|
|
363
|
+
let blocks;
|
|
364
|
+
if (ordered) {
|
|
365
|
+
// Slow, but ordered.
|
|
366
|
+
const topBlocks = this.getTopBlocks(true);
|
|
367
|
+
blocks = [];
|
|
368
|
+
for (let i = 0; i < topBlocks.length; i++) {
|
|
369
|
+
blocks.push.apply(blocks, topBlocks[i].getDescendants(true));
|
|
370
|
+
}
|
|
371
|
+
} else {
|
|
372
|
+
// Fast, but in no particular order.
|
|
373
|
+
blocks = this.getTopBlocks(false);
|
|
374
|
+
for (let i = 0; i < blocks.length; i++) {
|
|
375
|
+
blocks.push.apply(blocks, blocks[i].getChildren(false));
|
|
376
|
+
}
|
|
368
377
|
}
|
|
369
|
-
}
|
|
370
378
|
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
379
|
+
// Insertion markers exist on the workspace for rendering reasons, but
|
|
380
|
+
// aren't "real" blocks from a developer perspective.
|
|
381
|
+
const filtered = blocks.filter(function(block) {
|
|
382
|
+
return !block.isInsertionMarker();
|
|
383
|
+
});
|
|
376
384
|
|
|
377
|
-
|
|
378
|
-
}
|
|
385
|
+
return filtered;
|
|
386
|
+
}
|
|
379
387
|
|
|
380
|
-
/**
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
388
|
+
/**
|
|
389
|
+
* Dispose of all blocks and comments in workspace.
|
|
390
|
+
*/
|
|
391
|
+
clear() {
|
|
392
|
+
this.isClearing = true;
|
|
393
|
+
try {
|
|
394
|
+
const existingGroup = eventUtils.getGroup();
|
|
395
|
+
if (!existingGroup) {
|
|
396
|
+
eventUtils.setGroup(true);
|
|
397
|
+
}
|
|
398
|
+
while (this.topBlocks_.length) {
|
|
399
|
+
this.topBlocks_[0].dispose(false);
|
|
400
|
+
}
|
|
401
|
+
while (this.topComments_.length) {
|
|
402
|
+
this.topComments_[this.topComments_.length - 1].dispose();
|
|
403
|
+
}
|
|
404
|
+
if (!existingGroup) {
|
|
405
|
+
eventUtils.setGroup(false);
|
|
406
|
+
}
|
|
407
|
+
this.variableMap_.clear();
|
|
408
|
+
if (this.potentialVariableMap_) {
|
|
409
|
+
this.potentialVariableMap_.clear();
|
|
410
|
+
}
|
|
411
|
+
} finally {
|
|
412
|
+
this.isClearing = false;
|
|
402
413
|
}
|
|
403
|
-
} finally {
|
|
404
|
-
this.isClearing = false;
|
|
405
414
|
}
|
|
406
|
-
};
|
|
407
415
|
|
|
408
|
-
/* Begin functions that are just pass-throughs to the variable map. */
|
|
409
|
-
/**
|
|
410
|
-
* Rename a variable by updating its name in the variable map. Identify the
|
|
411
|
-
* variable to rename with the given ID.
|
|
412
|
-
* @param {string} id ID of the variable to rename.
|
|
413
|
-
* @param {string} newName New variable name.
|
|
414
|
-
*/
|
|
415
|
-
Workspace.prototype.renameVariableById = function(id, newName) {
|
|
416
|
-
this.variableMap_.renameVariableById(id, newName);
|
|
417
|
-
};
|
|
416
|
+
/* Begin functions that are just pass-throughs to the variable map. */
|
|
418
417
|
|
|
419
|
-
/**
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
* @return {!VariableModel} The newly created variable.
|
|
429
|
-
*/
|
|
430
|
-
Workspace.prototype.createVariable = function(name, opt_type, opt_id) {
|
|
431
|
-
return this.variableMap_.createVariable(name, opt_type, opt_id);
|
|
432
|
-
};
|
|
418
|
+
/**
|
|
419
|
+
* Rename a variable by updating its name in the variable map. Identify the
|
|
420
|
+
* variable to rename with the given ID.
|
|
421
|
+
* @param {string} id ID of the variable to rename.
|
|
422
|
+
* @param {string} newName New variable name.
|
|
423
|
+
*/
|
|
424
|
+
renameVariableById(id, newName) {
|
|
425
|
+
this.variableMap_.renameVariableById(id, newName);
|
|
426
|
+
}
|
|
433
427
|
|
|
434
|
-
/**
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
}
|
|
428
|
+
/**
|
|
429
|
+
* Create a variable with a given name, optional type, and optional ID.
|
|
430
|
+
* @param {string} name The name of the variable. This must be unique across
|
|
431
|
+
* variables and procedures.
|
|
432
|
+
* @param {?string=} opt_type The type of the variable like 'int' or 'string'.
|
|
433
|
+
* Does not need to be unique. Field_variable can filter variables based
|
|
434
|
+
* on their type. This will default to '' which is a specific type.
|
|
435
|
+
* @param {?string=} opt_id The unique ID of the variable. This will default
|
|
436
|
+
* to a UUID.
|
|
437
|
+
* @return {!VariableModel} The newly created variable.
|
|
438
|
+
*/
|
|
439
|
+
createVariable(name, opt_type, opt_id) {
|
|
440
|
+
return this.variableMap_.createVariable(name, opt_type, opt_id);
|
|
441
|
+
}
|
|
442
442
|
|
|
443
|
-
/**
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
}
|
|
443
|
+
/**
|
|
444
|
+
* Find all the uses of the given variable, which is identified by ID.
|
|
445
|
+
* @param {string} id ID of the variable to find.
|
|
446
|
+
* @return {!Array<!Block>} Array of block usages.
|
|
447
|
+
*/
|
|
448
|
+
getVariableUsesById(id) {
|
|
449
|
+
return this.variableMap_.getVariableUsesById(id);
|
|
450
|
+
}
|
|
451
451
|
|
|
452
|
-
/**
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
Workspace.prototype.getVariable = function(name, opt_type) {
|
|
461
|
-
return this.variableMap_.getVariable(name, opt_type);
|
|
462
|
-
};
|
|
452
|
+
/**
|
|
453
|
+
* Delete a variables by the passed in ID and all of its uses from this
|
|
454
|
+
* workspace. May prompt the user for confirmation.
|
|
455
|
+
* @param {string} id ID of variable to delete.
|
|
456
|
+
*/
|
|
457
|
+
deleteVariableById(id) {
|
|
458
|
+
this.variableMap_.deleteVariableById(id);
|
|
459
|
+
}
|
|
463
460
|
|
|
464
|
-
/**
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
461
|
+
/**
|
|
462
|
+
* Find the variable by the given name and return it. Return null if not
|
|
463
|
+
* found.
|
|
464
|
+
* @param {string} name The name to check for.
|
|
465
|
+
* @param {string=} opt_type The type of the variable. If not provided it
|
|
466
|
+
* defaults to the empty string, which is a specific type.
|
|
467
|
+
* @return {?VariableModel} The variable with the given name.
|
|
468
|
+
*/
|
|
469
|
+
getVariable(name, opt_type) {
|
|
470
|
+
// TODO (#1559): Possibly delete this function after resolving #1559.
|
|
471
|
+
return this.variableMap_.getVariable(name, opt_type);
|
|
472
|
+
}
|
|
472
473
|
|
|
473
|
-
/**
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
return this.variableMap_.getVariablesOfType(type);
|
|
482
|
-
};
|
|
474
|
+
/**
|
|
475
|
+
* Find the variable by the given ID and return it. Return null if not found.
|
|
476
|
+
* @param {string} id The ID to check for.
|
|
477
|
+
* @return {?VariableModel} The variable with the given ID.
|
|
478
|
+
*/
|
|
479
|
+
getVariableById(id) {
|
|
480
|
+
return this.variableMap_.getVariableById(id);
|
|
481
|
+
}
|
|
483
482
|
|
|
484
|
-
/**
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
483
|
+
/**
|
|
484
|
+
* Find the variable with the specified type. If type is null, return list of
|
|
485
|
+
* variables with empty string type.
|
|
486
|
+
* @param {?string} type Type of the variables to find.
|
|
487
|
+
* @return {!Array<!VariableModel>} The sought after variables of the
|
|
488
|
+
* passed in type. An empty array if none are found.
|
|
489
|
+
*/
|
|
490
|
+
getVariablesOfType(type) {
|
|
491
|
+
return this.variableMap_.getVariablesOfType(type);
|
|
492
|
+
}
|
|
492
493
|
|
|
493
|
-
/**
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
494
|
+
/**
|
|
495
|
+
* Return all variable types.
|
|
496
|
+
* @return {!Array<string>} List of variable types.
|
|
497
|
+
* @package
|
|
498
|
+
*/
|
|
499
|
+
getVariableTypes() {
|
|
500
|
+
return this.variableMap_.getVariableTypes(this);
|
|
501
|
+
}
|
|
500
502
|
|
|
501
|
-
/**
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
}
|
|
503
|
+
/**
|
|
504
|
+
* Return all variables of all types.
|
|
505
|
+
* @return {!Array<!VariableModel>} List of variable models.
|
|
506
|
+
*/
|
|
507
|
+
getAllVariables() {
|
|
508
|
+
return this.variableMap_.getAllVariables();
|
|
509
|
+
}
|
|
508
510
|
|
|
509
|
-
|
|
511
|
+
/**
|
|
512
|
+
* Returns all variable names of all types.
|
|
513
|
+
* @return {!Array<string>} List of all variable names of all types.
|
|
514
|
+
*/
|
|
515
|
+
getAllVariableNames() {
|
|
516
|
+
return this.variableMap_.getAllVariableNames();
|
|
517
|
+
}
|
|
510
518
|
|
|
511
|
-
|
|
512
|
-
* Returns the horizontal offset of the workspace.
|
|
513
|
-
* Intended for LTR/RTL compatibility in XML.
|
|
514
|
-
* Not relevant for a headless workspace.
|
|
515
|
-
* @return {number} Width.
|
|
516
|
-
*/
|
|
517
|
-
Workspace.prototype.getWidth = function() {
|
|
518
|
-
return 0;
|
|
519
|
-
};
|
|
519
|
+
/* End functions that are just pass-throughs to the variable map. */
|
|
520
520
|
|
|
521
|
-
/**
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
const {Block} = goog.module.get('Blockly.Block');
|
|
531
|
-
return new Block(this, prototypeName, opt_id);
|
|
532
|
-
};
|
|
521
|
+
/**
|
|
522
|
+
* Returns the horizontal offset of the workspace.
|
|
523
|
+
* Intended for LTR/RTL compatibility in XML.
|
|
524
|
+
* Not relevant for a headless workspace.
|
|
525
|
+
* @return {number} Width.
|
|
526
|
+
*/
|
|
527
|
+
getWidth() {
|
|
528
|
+
return 0;
|
|
529
|
+
}
|
|
533
530
|
|
|
534
|
-
/**
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
531
|
+
/**
|
|
532
|
+
* Obtain a newly created block.
|
|
533
|
+
* @param {!string} prototypeName Name of the language object containing
|
|
534
|
+
* type-specific functions for this block.
|
|
535
|
+
* @param {string=} opt_id Optional ID. Use this ID if provided, otherwise
|
|
536
|
+
* create a new ID.
|
|
537
|
+
* @return {!Block} The created block.
|
|
538
|
+
*/
|
|
539
|
+
newBlock(prototypeName, opt_id) {
|
|
540
|
+
const {Block} = goog.module.get('Blockly.Block');
|
|
541
|
+
return new Block(this, prototypeName, opt_id);
|
|
542
542
|
}
|
|
543
543
|
|
|
544
|
-
|
|
545
|
-
|
|
544
|
+
/**
|
|
545
|
+
* The number of blocks that may be added to the workspace before reaching
|
|
546
|
+
* the maxBlocks.
|
|
547
|
+
* @return {number} Number of blocks left.
|
|
548
|
+
*/
|
|
549
|
+
remainingCapacity() {
|
|
550
|
+
if (isNaN(this.options.maxBlocks)) {
|
|
551
|
+
return Infinity;
|
|
552
|
+
}
|
|
546
553
|
|
|
547
|
-
|
|
548
|
-
* The number of blocks of the given type that may be added to the workspace
|
|
549
|
-
* before reaching the maxInstances allowed for that type.
|
|
550
|
-
* @param {string} type Type of block to return capacity for.
|
|
551
|
-
* @return {number} Number of blocks of type left.
|
|
552
|
-
*/
|
|
553
|
-
Workspace.prototype.remainingCapacityOfType = function(type) {
|
|
554
|
-
if (!this.options.maxInstances) {
|
|
555
|
-
return Infinity;
|
|
554
|
+
return this.options.maxBlocks - this.getAllBlocks(false).length;
|
|
556
555
|
}
|
|
557
556
|
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
557
|
+
/**
|
|
558
|
+
* The number of blocks of the given type that may be added to the workspace
|
|
559
|
+
* before reaching the maxInstances allowed for that type.
|
|
560
|
+
* @param {string} type Type of block to return capacity for.
|
|
561
|
+
* @return {number} Number of blocks of type left.
|
|
562
|
+
*/
|
|
563
|
+
remainingCapacityOfType(type) {
|
|
564
|
+
if (!this.options.maxInstances) {
|
|
565
|
+
return Infinity;
|
|
566
|
+
}
|
|
561
567
|
|
|
562
|
-
|
|
563
|
-
|
|
568
|
+
const maxInstanceOfType = (this.options.maxInstances[type] !== undefined) ?
|
|
569
|
+
this.options.maxInstances[type] :
|
|
570
|
+
Infinity;
|
|
564
571
|
|
|
565
|
-
|
|
566
|
-
* Check if there is remaining capacity for blocks of the given counts to be
|
|
567
|
-
* created. If the total number of blocks represented by the map is more than
|
|
568
|
-
* the total remaining capacity, it returns false. If a type count is more
|
|
569
|
-
* than the remaining capacity for that type, it returns false.
|
|
570
|
-
* @param {!Object} typeCountsMap A map of types to counts (usually representing
|
|
571
|
-
* blocks to be created).
|
|
572
|
-
* @return {boolean} True if there is capacity for the given map,
|
|
573
|
-
* false otherwise.
|
|
574
|
-
*/
|
|
575
|
-
Workspace.prototype.isCapacityAvailable = function(typeCountsMap) {
|
|
576
|
-
if (!this.hasBlockLimits()) {
|
|
577
|
-
return true;
|
|
572
|
+
return maxInstanceOfType - this.getBlocksByType(type, false).length;
|
|
578
573
|
}
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
|
|
574
|
+
|
|
575
|
+
/**
|
|
576
|
+
* Check if there is remaining capacity for blocks of the given counts to be
|
|
577
|
+
* created. If the total number of blocks represented by the map is more
|
|
578
|
+
* than the total remaining capacity, it returns false. If a type count is
|
|
579
|
+
* more than the remaining capacity for that type, it returns false.
|
|
580
|
+
* @param {!Object} typeCountsMap A map of types to counts (usually
|
|
581
|
+
* representing
|
|
582
|
+
* blocks to be created).
|
|
583
|
+
* @return {boolean} True if there is capacity for the given map,
|
|
584
|
+
* false otherwise.
|
|
585
|
+
*/
|
|
586
|
+
isCapacityAvailable(typeCountsMap) {
|
|
587
|
+
if (!this.hasBlockLimits()) {
|
|
588
|
+
return true;
|
|
589
|
+
}
|
|
590
|
+
let copyableBlocksCount = 0;
|
|
591
|
+
for (const type in typeCountsMap) {
|
|
592
|
+
if (typeCountsMap[type] > this.remainingCapacityOfType(type)) {
|
|
593
|
+
return false;
|
|
594
|
+
}
|
|
595
|
+
copyableBlocksCount += typeCountsMap[type];
|
|
596
|
+
}
|
|
597
|
+
if (copyableBlocksCount > this.remainingCapacity()) {
|
|
582
598
|
return false;
|
|
583
599
|
}
|
|
584
|
-
|
|
585
|
-
}
|
|
586
|
-
if (copyableBlocksCount > this.remainingCapacity()) {
|
|
587
|
-
return false;
|
|
600
|
+
return true;
|
|
588
601
|
}
|
|
589
|
-
return true;
|
|
590
|
-
};
|
|
591
602
|
|
|
592
|
-
/**
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
}
|
|
603
|
+
/**
|
|
604
|
+
* Checks if the workspace has any limits on the maximum number of blocks,
|
|
605
|
+
* or the maximum number of blocks of specific types.
|
|
606
|
+
* @return {boolean} True if it has block limits, false otherwise.
|
|
607
|
+
*/
|
|
608
|
+
hasBlockLimits() {
|
|
609
|
+
return this.options.maxBlocks !== Infinity || !!this.options.maxInstances;
|
|
610
|
+
}
|
|
600
611
|
|
|
601
|
-
/**
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
}
|
|
612
|
+
/**
|
|
613
|
+
* Gets the undo stack for workplace.
|
|
614
|
+
* @return {!Array<!Abstract>} undo stack
|
|
615
|
+
* @package
|
|
616
|
+
*/
|
|
617
|
+
getUndoStack() {
|
|
618
|
+
return this.undoStack_;
|
|
619
|
+
}
|
|
609
620
|
|
|
610
|
-
/**
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
}
|
|
621
|
+
/**
|
|
622
|
+
* Gets the redo stack for workplace.
|
|
623
|
+
* @return {!Array<!Abstract>} redo stack
|
|
624
|
+
* @package
|
|
625
|
+
*/
|
|
626
|
+
getRedoStack() {
|
|
627
|
+
return this.redoStack_;
|
|
628
|
+
}
|
|
618
629
|
|
|
619
|
-
/**
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
|
|
636
|
-
|
|
637
|
-
for (let i = 0; i < events.length; i++) {
|
|
638
|
-
const event = events[i];
|
|
639
|
-
outputStack.push(event);
|
|
640
|
-
}
|
|
641
|
-
events = eventUtils.filter(events, redo);
|
|
642
|
-
eventUtils.setRecordUndo(false);
|
|
643
|
-
try {
|
|
630
|
+
/**
|
|
631
|
+
* Undo or redo the previous action.
|
|
632
|
+
* @param {boolean} redo False if undo, true if redo.
|
|
633
|
+
*/
|
|
634
|
+
undo(redo) {
|
|
635
|
+
const inputStack = redo ? this.redoStack_ : this.undoStack_;
|
|
636
|
+
const outputStack = redo ? this.undoStack_ : this.redoStack_;
|
|
637
|
+
const inputEvent = inputStack.pop();
|
|
638
|
+
if (!inputEvent) {
|
|
639
|
+
return;
|
|
640
|
+
}
|
|
641
|
+
let events = [inputEvent];
|
|
642
|
+
// Do another undo/redo if the next one is of the same group.
|
|
643
|
+
while (inputStack.length && inputEvent.group &&
|
|
644
|
+
inputEvent.group === inputStack[inputStack.length - 1].group) {
|
|
645
|
+
events.push(inputStack.pop());
|
|
646
|
+
}
|
|
647
|
+
// Push these popped events on the opposite stack.
|
|
644
648
|
for (let i = 0; i < events.length; i++) {
|
|
645
649
|
const event = events[i];
|
|
646
|
-
|
|
650
|
+
outputStack.push(event);
|
|
651
|
+
}
|
|
652
|
+
events = eventUtils.filter(events, redo);
|
|
653
|
+
eventUtils.setRecordUndo(false);
|
|
654
|
+
try {
|
|
655
|
+
for (let i = 0; i < events.length; i++) {
|
|
656
|
+
const event = events[i];
|
|
657
|
+
event.run(redo);
|
|
658
|
+
}
|
|
659
|
+
} finally {
|
|
660
|
+
eventUtils.setRecordUndo(true);
|
|
647
661
|
}
|
|
648
|
-
} finally {
|
|
649
|
-
eventUtils.setRecordUndo(true);
|
|
650
662
|
}
|
|
651
|
-
};
|
|
652
663
|
|
|
653
|
-
/**
|
|
654
|
-
|
|
655
|
-
|
|
656
|
-
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
|
|
660
|
-
|
|
661
|
-
}
|
|
664
|
+
/**
|
|
665
|
+
* Clear the undo/redo stacks.
|
|
666
|
+
*/
|
|
667
|
+
clearUndo() {
|
|
668
|
+
this.undoStack_.length = 0;
|
|
669
|
+
this.redoStack_.length = 0;
|
|
670
|
+
// Stop any events already in the firing queue from being undoable.
|
|
671
|
+
eventUtils.clearPendingUndo();
|
|
672
|
+
}
|
|
662
673
|
|
|
663
|
-
/**
|
|
664
|
-
|
|
665
|
-
|
|
666
|
-
|
|
667
|
-
|
|
668
|
-
|
|
669
|
-
|
|
670
|
-
|
|
671
|
-
|
|
672
|
-
|
|
673
|
-
|
|
674
|
-
}
|
|
674
|
+
/**
|
|
675
|
+
* When something in this workspace changes, call a function.
|
|
676
|
+
* Note that there may be a few recent events already on the stack. Thus the
|
|
677
|
+
* new change listener might be called with events that occurred a few
|
|
678
|
+
* milliseconds before the change listener was added.
|
|
679
|
+
* @param {!Function} func Function to call.
|
|
680
|
+
* @return {!Function} Obsolete return value, ignore.
|
|
681
|
+
*/
|
|
682
|
+
addChangeListener(func) {
|
|
683
|
+
this.listeners_.push(func);
|
|
684
|
+
return func;
|
|
685
|
+
}
|
|
675
686
|
|
|
676
|
-
/**
|
|
677
|
-
|
|
678
|
-
|
|
679
|
-
|
|
680
|
-
|
|
681
|
-
|
|
682
|
-
}
|
|
687
|
+
/**
|
|
688
|
+
* Stop listening for this workspace's changes.
|
|
689
|
+
* @param {!Function} func Function to stop calling.
|
|
690
|
+
*/
|
|
691
|
+
removeChangeListener(func) {
|
|
692
|
+
arrayUtils.removeElem(this.listeners_, func);
|
|
693
|
+
}
|
|
683
694
|
|
|
684
|
-
/**
|
|
685
|
-
|
|
686
|
-
|
|
687
|
-
|
|
688
|
-
|
|
689
|
-
|
|
690
|
-
|
|
691
|
-
|
|
692
|
-
|
|
693
|
-
|
|
695
|
+
/**
|
|
696
|
+
* Fire a change event.
|
|
697
|
+
* @param {!Abstract} event Event to fire.
|
|
698
|
+
*/
|
|
699
|
+
fireChangeListener(event) {
|
|
700
|
+
if (event.recordUndo) {
|
|
701
|
+
this.undoStack_.push(event);
|
|
702
|
+
this.redoStack_.length = 0;
|
|
703
|
+
while (this.undoStack_.length > this.MAX_UNDO && this.MAX_UNDO >= 0) {
|
|
704
|
+
this.undoStack_.shift();
|
|
705
|
+
}
|
|
706
|
+
}
|
|
707
|
+
for (let i = 0; i < this.listeners_.length; i++) {
|
|
708
|
+
const func = this.listeners_[i];
|
|
709
|
+
func(event);
|
|
694
710
|
}
|
|
695
711
|
}
|
|
696
|
-
for (let i = 0; i < this.listeners_.length; i++) {
|
|
697
|
-
const func = this.listeners_[i];
|
|
698
|
-
func(event);
|
|
699
|
-
}
|
|
700
|
-
};
|
|
701
712
|
|
|
702
|
-
/**
|
|
703
|
-
|
|
704
|
-
|
|
705
|
-
|
|
706
|
-
|
|
707
|
-
|
|
708
|
-
|
|
709
|
-
}
|
|
713
|
+
/**
|
|
714
|
+
* Find the block on this workspace with the specified ID.
|
|
715
|
+
* @param {string} id ID of block to find.
|
|
716
|
+
* @return {?Block} The sought after block, or null if not found.
|
|
717
|
+
*/
|
|
718
|
+
getBlockById(id) {
|
|
719
|
+
return this.blockDB_[id] || null;
|
|
720
|
+
}
|
|
710
721
|
|
|
711
|
-
/**
|
|
712
|
-
|
|
713
|
-
|
|
714
|
-
|
|
715
|
-
|
|
716
|
-
|
|
717
|
-
|
|
718
|
-
|
|
719
|
-
}
|
|
722
|
+
/**
|
|
723
|
+
* Set a block on this workspace with the specified ID.
|
|
724
|
+
* @param {string} id ID of block to set.
|
|
725
|
+
* @param {Block} block The block to set.
|
|
726
|
+
* @package
|
|
727
|
+
*/
|
|
728
|
+
setBlockById(id, block) {
|
|
729
|
+
this.blockDB_[id] = block;
|
|
730
|
+
}
|
|
720
731
|
|
|
721
|
-
/**
|
|
722
|
-
|
|
723
|
-
|
|
724
|
-
|
|
725
|
-
|
|
726
|
-
|
|
727
|
-
|
|
728
|
-
}
|
|
732
|
+
/**
|
|
733
|
+
* Delete a block off this workspace with the specified ID.
|
|
734
|
+
* @param {string} id ID of block to delete.
|
|
735
|
+
* @package
|
|
736
|
+
*/
|
|
737
|
+
removeBlockById(id) {
|
|
738
|
+
delete this.blockDB_[id];
|
|
739
|
+
}
|
|
729
740
|
|
|
730
|
-
/**
|
|
731
|
-
|
|
732
|
-
|
|
733
|
-
|
|
734
|
-
|
|
735
|
-
|
|
736
|
-
|
|
737
|
-
|
|
738
|
-
|
|
739
|
-
}
|
|
741
|
+
/**
|
|
742
|
+
* Find the comment on this workspace with the specified ID.
|
|
743
|
+
* @param {string} id ID of comment to find.
|
|
744
|
+
* @return {?WorkspaceComment} The sought after comment, or null if not
|
|
745
|
+
* found.
|
|
746
|
+
* @package
|
|
747
|
+
*/
|
|
748
|
+
getCommentById(id) {
|
|
749
|
+
return this.commentDB_[id] || null;
|
|
750
|
+
}
|
|
740
751
|
|
|
741
|
-
/**
|
|
742
|
-
|
|
743
|
-
|
|
744
|
-
|
|
745
|
-
|
|
746
|
-
|
|
747
|
-
|
|
748
|
-
|
|
749
|
-
|
|
750
|
-
|
|
751
|
-
|
|
752
|
-
|
|
753
|
-
|
|
752
|
+
/**
|
|
753
|
+
* Checks whether all value and statement inputs in the workspace are filled
|
|
754
|
+
* with blocks.
|
|
755
|
+
* @param {boolean=} opt_shadowBlocksAreFilled An optional argument
|
|
756
|
+
* controlling whether shadow blocks are counted as filled. Defaults to
|
|
757
|
+
* true.
|
|
758
|
+
* @return {boolean} True if all inputs are filled, false otherwise.
|
|
759
|
+
*/
|
|
760
|
+
allInputsFilled(opt_shadowBlocksAreFilled) {
|
|
761
|
+
const blocks = this.getTopBlocks(false);
|
|
762
|
+
for (let i = 0; i < blocks.length; i++) {
|
|
763
|
+
const block = blocks[i];
|
|
764
|
+
if (!block.allInputsFilled(opt_shadowBlocksAreFilled)) {
|
|
765
|
+
return false;
|
|
766
|
+
}
|
|
754
767
|
}
|
|
768
|
+
return true;
|
|
755
769
|
}
|
|
756
|
-
return true;
|
|
757
|
-
};
|
|
758
770
|
|
|
759
|
-
/**
|
|
760
|
-
|
|
761
|
-
|
|
762
|
-
|
|
763
|
-
|
|
764
|
-
|
|
765
|
-
|
|
766
|
-
|
|
767
|
-
}
|
|
771
|
+
/**
|
|
772
|
+
* Return the variable map that contains "potential" variables.
|
|
773
|
+
* These exist in the flyout but not in the workspace.
|
|
774
|
+
* @return {?VariableMap} The potential variable map.
|
|
775
|
+
* @package
|
|
776
|
+
*/
|
|
777
|
+
getPotentialVariableMap() {
|
|
778
|
+
return this.potentialVariableMap_;
|
|
779
|
+
}
|
|
768
780
|
|
|
769
|
-
/**
|
|
770
|
-
|
|
771
|
-
|
|
772
|
-
|
|
773
|
-
|
|
774
|
-
|
|
775
|
-
}
|
|
781
|
+
/**
|
|
782
|
+
* Create and store the potential variable map for this workspace.
|
|
783
|
+
* @package
|
|
784
|
+
*/
|
|
785
|
+
createPotentialVariableMap() {
|
|
786
|
+
this.potentialVariableMap_ = new VariableMap(this);
|
|
787
|
+
}
|
|
776
788
|
|
|
777
|
-
/**
|
|
778
|
-
|
|
779
|
-
|
|
780
|
-
|
|
781
|
-
|
|
782
|
-
|
|
783
|
-
}
|
|
789
|
+
/**
|
|
790
|
+
* Return the map of all variables on the workspace.
|
|
791
|
+
* @return {!VariableMap} The variable map.
|
|
792
|
+
*/
|
|
793
|
+
getVariableMap() {
|
|
794
|
+
return this.variableMap_;
|
|
795
|
+
}
|
|
784
796
|
|
|
785
|
-
/**
|
|
786
|
-
|
|
787
|
-
|
|
788
|
-
|
|
789
|
-
|
|
790
|
-
|
|
791
|
-
|
|
792
|
-
}
|
|
797
|
+
/**
|
|
798
|
+
* Set the map of all variables on the workspace.
|
|
799
|
+
* @param {!VariableMap} variableMap The variable map.
|
|
800
|
+
* @package
|
|
801
|
+
*/
|
|
802
|
+
setVariableMap(variableMap) {
|
|
803
|
+
this.variableMap_ = variableMap;
|
|
804
|
+
}
|
|
793
805
|
|
|
794
|
-
/**
|
|
795
|
-
|
|
796
|
-
|
|
797
|
-
|
|
798
|
-
|
|
799
|
-
|
|
800
|
-
|
|
801
|
-
}
|
|
806
|
+
/**
|
|
807
|
+
* Find the workspace with the specified ID.
|
|
808
|
+
* @param {string} id ID of workspace to find.
|
|
809
|
+
* @return {?Workspace} The sought after workspace or null if not found.
|
|
810
|
+
*/
|
|
811
|
+
static getById(id) {
|
|
812
|
+
return WorkspaceDB_[id] || null;
|
|
813
|
+
}
|
|
814
|
+
|
|
815
|
+
/**
|
|
816
|
+
* Find all workspaces.
|
|
817
|
+
* @return {!Array<!Workspace>} Array of workspaces.
|
|
818
|
+
*/
|
|
819
|
+
static getAll() {
|
|
820
|
+
const workspaces = [];
|
|
821
|
+
for (const workspaceId in WorkspaceDB_) {
|
|
822
|
+
workspaces.push(WorkspaceDB_[workspaceId]);
|
|
823
|
+
}
|
|
824
|
+
return workspaces;
|
|
825
|
+
}
|
|
826
|
+
}
|
|
802
827
|
|
|
803
828
|
/**
|
|
804
|
-
*
|
|
805
|
-
*
|
|
829
|
+
* Angle away from the horizontal to sweep for blocks. Order of execution is
|
|
830
|
+
* generally top to bottom, but a small angle changes the scan to give a bit of
|
|
831
|
+
* a left to right bias (reversed in RTL). Units are in degrees.
|
|
832
|
+
* See: https://tvtropes.org/pmwiki/pmwiki.php/Main/DiagonalBilling
|
|
806
833
|
*/
|
|
807
|
-
Workspace.
|
|
808
|
-
const workspaces = [];
|
|
809
|
-
for (const workspaceId in WorkspaceDB_) {
|
|
810
|
-
workspaces.push(WorkspaceDB_[workspaceId]);
|
|
811
|
-
}
|
|
812
|
-
return workspaces;
|
|
813
|
-
};
|
|
834
|
+
Workspace.SCAN_ANGLE = 3;
|
|
814
835
|
|
|
815
836
|
exports.Workspace = Workspace;
|