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
|
@@ -22,10 +22,11 @@ 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 svgMath = goog.require('Blockly.utils.svgMath');
|
|
27
26
|
/* eslint-disable-next-line no-unused-vars */
|
|
28
27
|
const {BlockDragSurfaceSvg} = goog.requireType('Blockly.BlockDragSurfaceSvg');
|
|
28
|
+
/* eslint-disable-next-line no-unused-vars */
|
|
29
|
+
const {CommentMove} = goog.require('Blockly.Events.CommentMove');
|
|
29
30
|
const {Coordinate} = goog.require('Blockly.utils.Coordinate');
|
|
30
31
|
/* eslint-disable-next-line no-unused-vars */
|
|
31
32
|
const {IBoundedElement} = goog.require('Blockly.IBoundedElement');
|
|
@@ -43,8 +44,6 @@ goog.require('Blockly.Events.CommentCreate');
|
|
|
43
44
|
/** @suppress {extraRequire} */
|
|
44
45
|
goog.require('Blockly.Events.CommentDelete');
|
|
45
46
|
/** @suppress {extraRequire} */
|
|
46
|
-
goog.require('Blockly.Events.CommentMove');
|
|
47
|
-
/** @suppress {extraRequire} */
|
|
48
47
|
goog.require('Blockly.Events.Selected');
|
|
49
48
|
|
|
50
49
|
|
|
@@ -71,1076 +70,1155 @@ const TEXTAREA_OFFSET = 2;
|
|
|
71
70
|
|
|
72
71
|
/**
|
|
73
72
|
* Class for a workspace comment's SVG representation.
|
|
74
|
-
* @param {!WorkspaceSvg} workspace The block's workspace.
|
|
75
|
-
* @param {string} content The content of this workspace comment.
|
|
76
|
-
* @param {number} height Height of the comment.
|
|
77
|
-
* @param {number} width Width of the comment.
|
|
78
|
-
* @param {string=} opt_id Optional ID. Use this ID if provided, otherwise
|
|
79
|
-
* create a new ID.
|
|
80
73
|
* @extends {WorkspaceComment}
|
|
81
74
|
* @implements {IBoundedElement}
|
|
82
75
|
* @implements {IBubble}
|
|
83
76
|
* @implements {ICopyable}
|
|
84
|
-
* @constructor
|
|
85
77
|
* @alias Blockly.WorkspaceCommentSvg
|
|
86
78
|
*/
|
|
87
|
-
|
|
88
|
-
workspace, content, height, width, opt_id) {
|
|
79
|
+
class WorkspaceCommentSvg extends WorkspaceComment {
|
|
89
80
|
/**
|
|
90
|
-
* @
|
|
81
|
+
* @param {!WorkspaceSvg} workspace The block's workspace.
|
|
82
|
+
* @param {string} content The content of this workspace comment.
|
|
83
|
+
* @param {number} height Height of the comment.
|
|
84
|
+
* @param {number} width Width of the comment.
|
|
85
|
+
* @param {string=} opt_id Optional ID. Use this ID if provided, otherwise
|
|
86
|
+
* create a new ID.
|
|
91
87
|
*/
|
|
92
|
-
|
|
88
|
+
constructor(workspace, content, height, width, opt_id) {
|
|
89
|
+
super(workspace, content, height, width, opt_id);
|
|
90
|
+
/**
|
|
91
|
+
* @type {!WorkspaceSvg}
|
|
92
|
+
*/
|
|
93
|
+
this.workspace;
|
|
94
|
+
|
|
95
|
+
/**
|
|
96
|
+
* Mouse up event data.
|
|
97
|
+
* @type {?browserEvents.Data}
|
|
98
|
+
* @private
|
|
99
|
+
*/
|
|
100
|
+
this.onMouseUpWrapper_ = null;
|
|
93
101
|
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
102
|
+
/**
|
|
103
|
+
* Mouse move event data.
|
|
104
|
+
* @type {?browserEvents.Data}
|
|
105
|
+
* @private
|
|
106
|
+
*/
|
|
107
|
+
this.onMouseMoveWrapper_ = null;
|
|
108
|
+
|
|
109
|
+
/**
|
|
110
|
+
* Whether event handlers have been initialized.
|
|
111
|
+
* @type {boolean}
|
|
112
|
+
* @private
|
|
113
|
+
*/
|
|
114
|
+
this.eventsInit_ = false;
|
|
115
|
+
|
|
116
|
+
/**
|
|
117
|
+
* @type {?Element}
|
|
118
|
+
* @private
|
|
119
|
+
*/
|
|
120
|
+
this.textarea_ = null;
|
|
121
|
+
|
|
122
|
+
/**
|
|
123
|
+
* @type {?SVGRectElement}
|
|
124
|
+
* @private
|
|
125
|
+
*/
|
|
126
|
+
this.svgRectTarget_ = null;
|
|
127
|
+
|
|
128
|
+
/**
|
|
129
|
+
* @type {?SVGRectElement}
|
|
130
|
+
* @private
|
|
131
|
+
*/
|
|
132
|
+
this.svgHandleTarget_ = null;
|
|
133
|
+
|
|
134
|
+
/**
|
|
135
|
+
* @type {?SVGForeignObjectElement}
|
|
136
|
+
* @private
|
|
137
|
+
*/
|
|
138
|
+
this.foreignObject_ = null;
|
|
139
|
+
|
|
140
|
+
/**
|
|
141
|
+
* @type {?SVGGElement}
|
|
142
|
+
* @private
|
|
143
|
+
*/
|
|
144
|
+
this.resizeGroup_ = null;
|
|
145
|
+
|
|
146
|
+
/**
|
|
147
|
+
* @type {?SVGGElement}
|
|
148
|
+
* @private
|
|
149
|
+
*/
|
|
150
|
+
this.deleteGroup_ = null;
|
|
151
|
+
|
|
152
|
+
/**
|
|
153
|
+
* @type {?SVGCircleElement}
|
|
154
|
+
* @private
|
|
155
|
+
*/
|
|
156
|
+
this.deleteIconBorder_ = null;
|
|
157
|
+
|
|
158
|
+
/**
|
|
159
|
+
* @type {boolean}
|
|
160
|
+
* @private
|
|
161
|
+
*/
|
|
162
|
+
this.focused_ = false;
|
|
163
|
+
|
|
164
|
+
/**
|
|
165
|
+
* @type {boolean}
|
|
166
|
+
* @private
|
|
167
|
+
*/
|
|
168
|
+
this.autoLayout_ = false;
|
|
169
|
+
|
|
170
|
+
// Create core elements for the block.
|
|
171
|
+
/**
|
|
172
|
+
* @type {!SVGElement}
|
|
173
|
+
* @private
|
|
174
|
+
*/
|
|
175
|
+
this.svgGroup_ =
|
|
176
|
+
dom.createSvgElement(Svg.G, {'class': 'blocklyComment'}, null);
|
|
177
|
+
this.svgGroup_.translate_ = '';
|
|
178
|
+
|
|
179
|
+
this.svgRect_ = dom.createSvgElement(Svg.RECT, {
|
|
180
|
+
'class': 'blocklyCommentRect',
|
|
181
|
+
'x': 0,
|
|
182
|
+
'y': 0,
|
|
183
|
+
'rx': BORDER_RADIUS,
|
|
184
|
+
'ry': BORDER_RADIUS,
|
|
185
|
+
});
|
|
186
|
+
this.svgGroup_.appendChild(this.svgRect_);
|
|
187
|
+
|
|
188
|
+
/**
|
|
189
|
+
* Whether the comment is rendered onscreen and is a part of the DOM.
|
|
190
|
+
* @type {boolean}
|
|
191
|
+
* @private
|
|
192
|
+
*/
|
|
193
|
+
this.rendered_ = false;
|
|
194
|
+
|
|
195
|
+
/**
|
|
196
|
+
* Whether to move the comment to the drag surface when it is dragged.
|
|
197
|
+
* True if it should move, false if it should be translated directly.
|
|
198
|
+
* @type {boolean}
|
|
199
|
+
* @private
|
|
200
|
+
*/
|
|
201
|
+
this.useDragSurface_ =
|
|
202
|
+
svgMath.is3dSupported() && !!workspace.getBlockDragSurface();
|
|
203
|
+
|
|
204
|
+
this.render();
|
|
205
|
+
}
|
|
100
206
|
|
|
101
207
|
/**
|
|
102
|
-
*
|
|
103
|
-
* @
|
|
104
|
-
* @private
|
|
208
|
+
* Dispose of this comment.
|
|
209
|
+
* @package
|
|
105
210
|
*/
|
|
106
|
-
|
|
211
|
+
dispose() {
|
|
212
|
+
if (this.disposed_) {
|
|
213
|
+
return;
|
|
214
|
+
}
|
|
215
|
+
// If this comment is being dragged, unlink the mouse events.
|
|
216
|
+
if (common.getSelected() === this) {
|
|
217
|
+
this.unselect();
|
|
218
|
+
this.workspace.cancelCurrentGesture();
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
if (eventUtils.isEnabled()) {
|
|
222
|
+
eventUtils.fire(new (eventUtils.get(eventUtils.COMMENT_DELETE))(this));
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
dom.removeNode(this.svgGroup_);
|
|
226
|
+
// Dispose of any rendered components
|
|
227
|
+
this.disposeInternal_();
|
|
228
|
+
|
|
229
|
+
eventUtils.disable();
|
|
230
|
+
super.dispose();
|
|
231
|
+
eventUtils.enable();
|
|
232
|
+
}
|
|
107
233
|
|
|
108
|
-
// Create core elements for the block.
|
|
109
234
|
/**
|
|
110
|
-
*
|
|
111
|
-
*
|
|
235
|
+
* Create and initialize the SVG representation of a workspace comment.
|
|
236
|
+
* May be called more than once.
|
|
237
|
+
*
|
|
238
|
+
* @param {boolean=} opt_noSelect Text inside text area will be selected if
|
|
239
|
+
* false
|
|
240
|
+
*
|
|
241
|
+
* @package
|
|
112
242
|
*/
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
243
|
+
initSvg(opt_noSelect) {
|
|
244
|
+
if (!this.workspace.rendered) {
|
|
245
|
+
throw TypeError('Workspace is headless.');
|
|
246
|
+
}
|
|
247
|
+
if (!this.workspace.options.readOnly && !this.eventsInit_) {
|
|
248
|
+
browserEvents.conditionalBind(
|
|
249
|
+
/** @type {!SVGRectElement} */ (this.svgRectTarget_), 'mousedown',
|
|
250
|
+
this, this.pathMouseDown_);
|
|
251
|
+
browserEvents.conditionalBind(
|
|
252
|
+
/** @type {!SVGRectElement} */ (this.svgHandleTarget_), 'mousedown',
|
|
253
|
+
this, this.pathMouseDown_);
|
|
254
|
+
}
|
|
255
|
+
this.eventsInit_ = true;
|
|
256
|
+
|
|
257
|
+
this.updateMovable();
|
|
258
|
+
if (!this.getSvgRoot().parentNode) {
|
|
259
|
+
this.workspace.getBubbleCanvas().appendChild(this.getSvgRoot());
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
if (!opt_noSelect && this.textarea_) {
|
|
263
|
+
this.textarea_.select();
|
|
264
|
+
}
|
|
265
|
+
}
|
|
125
266
|
|
|
126
267
|
/**
|
|
127
|
-
*
|
|
128
|
-
* @
|
|
268
|
+
* Handle a mouse-down on an SVG comment.
|
|
269
|
+
* @param {!Event} e Mouse down event or touch start event.
|
|
129
270
|
* @private
|
|
130
271
|
*/
|
|
131
|
-
|
|
272
|
+
pathMouseDown_(e) {
|
|
273
|
+
const gesture = this.workspace.getGesture(e);
|
|
274
|
+
if (gesture) {
|
|
275
|
+
gesture.handleBubbleStart(e, this);
|
|
276
|
+
}
|
|
277
|
+
}
|
|
132
278
|
|
|
133
279
|
/**
|
|
134
|
-
*
|
|
135
|
-
*
|
|
136
|
-
* @
|
|
137
|
-
* @private
|
|
280
|
+
* Show the context menu for this workspace comment.
|
|
281
|
+
* @param {!Event} e Mouse event.
|
|
282
|
+
* @package
|
|
138
283
|
*/
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
};
|
|
147
|
-
object.inherits(WorkspaceCommentSvg, WorkspaceComment);
|
|
148
|
-
|
|
149
|
-
/**
|
|
150
|
-
* The width and height to use to size a workspace comment when it is first
|
|
151
|
-
* added, before it has been edited by the user.
|
|
152
|
-
* @type {number}
|
|
153
|
-
* @package
|
|
154
|
-
*/
|
|
155
|
-
WorkspaceCommentSvg.DEFAULT_SIZE = 100;
|
|
284
|
+
showContextMenu(e) {
|
|
285
|
+
if (this.workspace.options.readOnly) {
|
|
286
|
+
return;
|
|
287
|
+
}
|
|
288
|
+
// Save the current workspace comment in a variable for use in closures.
|
|
289
|
+
const comment = this;
|
|
290
|
+
const menuOptions = [];
|
|
156
291
|
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
* @private
|
|
162
|
-
*/
|
|
163
|
-
WorkspaceCommentSvg.TOP_OFFSET = 10;
|
|
292
|
+
if (this.isDeletable() && this.isMovable()) {
|
|
293
|
+
menuOptions.push(ContextMenu.commentDuplicateOption(comment));
|
|
294
|
+
menuOptions.push(ContextMenu.commentDeleteOption(comment));
|
|
295
|
+
}
|
|
164
296
|
|
|
165
|
-
|
|
166
|
-
* Dispose of this comment.
|
|
167
|
-
* @package
|
|
168
|
-
*/
|
|
169
|
-
WorkspaceCommentSvg.prototype.dispose = function() {
|
|
170
|
-
if (this.disposed_) {
|
|
171
|
-
return;
|
|
172
|
-
}
|
|
173
|
-
// If this comment is being dragged, unlink the mouse events.
|
|
174
|
-
if (common.getSelected() === this) {
|
|
175
|
-
this.unselect();
|
|
176
|
-
this.workspace.cancelCurrentGesture();
|
|
297
|
+
ContextMenu.show(e, menuOptions, this.RTL);
|
|
177
298
|
}
|
|
178
299
|
|
|
179
|
-
|
|
180
|
-
|
|
300
|
+
/**
|
|
301
|
+
* Select this comment. Highlight it visually.
|
|
302
|
+
* @package
|
|
303
|
+
*/
|
|
304
|
+
select() {
|
|
305
|
+
if (common.getSelected() === this) {
|
|
306
|
+
return;
|
|
307
|
+
}
|
|
308
|
+
let oldId = null;
|
|
309
|
+
if (common.getSelected()) {
|
|
310
|
+
oldId = common.getSelected().id;
|
|
311
|
+
// Unselect any previously selected block.
|
|
312
|
+
eventUtils.disable();
|
|
313
|
+
try {
|
|
314
|
+
common.getSelected().unselect();
|
|
315
|
+
} finally {
|
|
316
|
+
eventUtils.enable();
|
|
317
|
+
}
|
|
318
|
+
}
|
|
319
|
+
const event = new (eventUtils.get(eventUtils.SELECTED))(
|
|
320
|
+
oldId, this.id, this.workspace.id);
|
|
321
|
+
eventUtils.fire(event);
|
|
322
|
+
common.setSelected(this);
|
|
323
|
+
this.addSelect();
|
|
181
324
|
}
|
|
182
325
|
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
}
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
* false
|
|
198
|
-
*
|
|
199
|
-
* @package
|
|
200
|
-
*/
|
|
201
|
-
WorkspaceCommentSvg.prototype.initSvg = function(opt_noSelect) {
|
|
202
|
-
if (!this.workspace.rendered) {
|
|
203
|
-
throw TypeError('Workspace is headless.');
|
|
204
|
-
}
|
|
205
|
-
if (!this.workspace.options.readOnly && !this.eventsInit_) {
|
|
206
|
-
browserEvents.conditionalBind(
|
|
207
|
-
this.svgRectTarget_, 'mousedown', this, this.pathMouseDown_);
|
|
208
|
-
browserEvents.conditionalBind(
|
|
209
|
-
this.svgHandleTarget_, 'mousedown', this, this.pathMouseDown_);
|
|
326
|
+
/**
|
|
327
|
+
* Unselect this comment. Remove its highlighting.
|
|
328
|
+
* @package
|
|
329
|
+
*/
|
|
330
|
+
unselect() {
|
|
331
|
+
if (common.getSelected() !== this) {
|
|
332
|
+
return;
|
|
333
|
+
}
|
|
334
|
+
const event = new (eventUtils.get(eventUtils.SELECTED))(
|
|
335
|
+
this.id, null, this.workspace.id);
|
|
336
|
+
eventUtils.fire(event);
|
|
337
|
+
common.setSelected(null);
|
|
338
|
+
this.removeSelect();
|
|
339
|
+
this.blurFocus();
|
|
210
340
|
}
|
|
211
|
-
this.eventsInit_ = true;
|
|
212
341
|
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
342
|
+
/**
|
|
343
|
+
* Select this comment. Highlight it visually.
|
|
344
|
+
* @package
|
|
345
|
+
*/
|
|
346
|
+
addSelect() {
|
|
347
|
+
dom.addClass(
|
|
348
|
+
/** @type {!Element} */ (this.svgGroup_), 'blocklySelected');
|
|
349
|
+
this.setFocus();
|
|
216
350
|
}
|
|
217
351
|
|
|
218
|
-
|
|
219
|
-
|
|
352
|
+
/**
|
|
353
|
+
* Unselect this comment. Remove its highlighting.
|
|
354
|
+
* @package
|
|
355
|
+
*/
|
|
356
|
+
removeSelect() {
|
|
357
|
+
dom.removeClass(
|
|
358
|
+
/** @type {!Element} */ (this.svgGroup_), 'blocklySelected');
|
|
359
|
+
this.blurFocus();
|
|
220
360
|
}
|
|
221
|
-
};
|
|
222
361
|
|
|
223
|
-
/**
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
if (gesture) {
|
|
231
|
-
gesture.handleBubbleStart(e, this);
|
|
362
|
+
/**
|
|
363
|
+
* Focus this comment. Highlight it visually.
|
|
364
|
+
* @package
|
|
365
|
+
*/
|
|
366
|
+
addFocus() {
|
|
367
|
+
dom.addClass(
|
|
368
|
+
/** @type {!Element} */ (this.svgGroup_), 'blocklyFocused');
|
|
232
369
|
}
|
|
233
|
-
};
|
|
234
370
|
|
|
235
|
-
/**
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
return;
|
|
371
|
+
/**
|
|
372
|
+
* Unfocus this comment. Remove its highlighting.
|
|
373
|
+
* @package
|
|
374
|
+
*/
|
|
375
|
+
removeFocus() {
|
|
376
|
+
dom.removeClass(
|
|
377
|
+
/** @type {!Element} */ (this.svgGroup_), 'blocklyFocused');
|
|
243
378
|
}
|
|
244
|
-
// Save the current workspace comment in a variable for use in closures.
|
|
245
|
-
const comment = this;
|
|
246
|
-
const menuOptions = [];
|
|
247
379
|
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
380
|
+
/**
|
|
381
|
+
* Return the coordinates of the top-left corner of this comment relative to
|
|
382
|
+
* the drawing surface's origin (0,0), in workspace units.
|
|
383
|
+
* If the comment is on the workspace, (0, 0) is the origin of the workspace
|
|
384
|
+
* coordinate system.
|
|
385
|
+
* This does not change with workspace scale.
|
|
386
|
+
* @return {!Coordinate} Object with .x and .y properties in
|
|
387
|
+
* workspace coordinates.
|
|
388
|
+
* @package
|
|
389
|
+
*/
|
|
390
|
+
getRelativeToSurfaceXY() {
|
|
391
|
+
let x = 0;
|
|
392
|
+
let y = 0;
|
|
393
|
+
|
|
394
|
+
const dragSurfaceGroup = this.useDragSurface_ ?
|
|
395
|
+
this.workspace.getBlockDragSurface().getGroup() :
|
|
396
|
+
null;
|
|
397
|
+
|
|
398
|
+
let element = this.getSvgRoot();
|
|
399
|
+
if (element) {
|
|
400
|
+
do {
|
|
401
|
+
// Loop through this comment and every parent.
|
|
402
|
+
const xy = svgMath.getRelativeXY(/** @type {!Element} */ (element));
|
|
403
|
+
x += xy.x;
|
|
404
|
+
y += xy.y;
|
|
405
|
+
// If this element is the current element on the drag surface, include
|
|
406
|
+
// the translation of the drag surface itself.
|
|
407
|
+
if (this.useDragSurface_ &&
|
|
408
|
+
this.workspace.getBlockDragSurface().getCurrentBlock() ===
|
|
409
|
+
element) {
|
|
410
|
+
const surfaceTranslation =
|
|
411
|
+
this.workspace.getBlockDragSurface().getSurfaceTranslation();
|
|
412
|
+
x += surfaceTranslation.x;
|
|
413
|
+
y += surfaceTranslation.y;
|
|
414
|
+
}
|
|
415
|
+
element = element.parentNode;
|
|
416
|
+
} while (element && element !== this.workspace.getBubbleCanvas() &&
|
|
417
|
+
element !== dragSurfaceGroup);
|
|
418
|
+
}
|
|
419
|
+
this.xy_ = new Coordinate(x, y);
|
|
420
|
+
return this.xy_;
|
|
251
421
|
}
|
|
252
422
|
|
|
253
|
-
|
|
254
|
-
|
|
423
|
+
/**
|
|
424
|
+
* Move a comment by a relative offset.
|
|
425
|
+
* @param {number} dx Horizontal offset, in workspace units.
|
|
426
|
+
* @param {number} dy Vertical offset, in workspace units.
|
|
427
|
+
* @package
|
|
428
|
+
*/
|
|
429
|
+
moveBy(dx, dy) {
|
|
430
|
+
const event = /** @type {!CommentMove} */ (
|
|
431
|
+
new (eventUtils.get(eventUtils.COMMENT_MOVE))(this));
|
|
432
|
+
// TODO: Do I need to look up the relative to surface XY position here?
|
|
433
|
+
const xy = this.getRelativeToSurfaceXY();
|
|
434
|
+
this.translate(xy.x + dx, xy.y + dy);
|
|
435
|
+
this.xy_ = new Coordinate(xy.x + dx, xy.y + dy);
|
|
436
|
+
event.recordNew();
|
|
437
|
+
eventUtils.fire(event);
|
|
438
|
+
this.workspace.resizeContents();
|
|
439
|
+
}
|
|
255
440
|
|
|
256
|
-
/**
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
441
|
+
/**
|
|
442
|
+
* Transforms a comment by setting the translation on the transform attribute
|
|
443
|
+
* of the block's SVG.
|
|
444
|
+
* @param {number} x The x coordinate of the translation in workspace units.
|
|
445
|
+
* @param {number} y The y coordinate of the translation in workspace units.
|
|
446
|
+
* @package
|
|
447
|
+
*/
|
|
448
|
+
translate(x, y) {
|
|
449
|
+
this.xy_ = new Coordinate(x, y);
|
|
450
|
+
this.getSvgRoot().setAttribute(
|
|
451
|
+
'transform', 'translate(' + x + ',' + y + ')');
|
|
263
452
|
}
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
453
|
+
|
|
454
|
+
/**
|
|
455
|
+
* Move this comment to its workspace's drag surface, accounting for
|
|
456
|
+
* positioning. Generally should be called at the same time as
|
|
457
|
+
* setDragging(true). Does nothing if useDragSurface_ is false.
|
|
458
|
+
* @package
|
|
459
|
+
*/
|
|
460
|
+
moveToDragSurface() {
|
|
461
|
+
if (!this.useDragSurface_) {
|
|
462
|
+
return;
|
|
273
463
|
}
|
|
464
|
+
// The translation for drag surface blocks,
|
|
465
|
+
// is equal to the current relative-to-surface position,
|
|
466
|
+
// to keep the position in sync as it move on/off the surface.
|
|
467
|
+
// This is in workspace coordinates.
|
|
468
|
+
const xy = this.getRelativeToSurfaceXY();
|
|
469
|
+
this.clearTransformAttributes_();
|
|
470
|
+
this.workspace.getBlockDragSurface().translateSurface(xy.x, xy.y);
|
|
471
|
+
// Execute the move on the top-level SVG component
|
|
472
|
+
this.workspace.getBlockDragSurface().setBlocksAndShow(this.getSvgRoot());
|
|
274
473
|
}
|
|
275
|
-
const event = new (eventUtils.get(eventUtils.SELECTED))(
|
|
276
|
-
oldId, this.id, this.workspace.id);
|
|
277
|
-
eventUtils.fire(event);
|
|
278
|
-
common.setSelected(this);
|
|
279
|
-
this.addSelect();
|
|
280
|
-
};
|
|
281
474
|
|
|
282
|
-
/**
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
475
|
+
/**
|
|
476
|
+
* Move this comment during a drag, taking into account whether we are using a
|
|
477
|
+
* drag surface to translate blocks.
|
|
478
|
+
* @param {BlockDragSurfaceSvg} dragSurface The surface that carries
|
|
479
|
+
* rendered items during a drag, or null if no drag surface is in use.
|
|
480
|
+
* @param {!Coordinate} newLoc The location to translate to, in
|
|
481
|
+
* workspace coordinates.
|
|
482
|
+
* @package
|
|
483
|
+
*/
|
|
484
|
+
moveDuringDrag(dragSurface, newLoc) {
|
|
485
|
+
if (dragSurface) {
|
|
486
|
+
dragSurface.translateSurface(newLoc.x, newLoc.y);
|
|
487
|
+
} else {
|
|
488
|
+
this.svgGroup_.translate_ =
|
|
489
|
+
'translate(' + newLoc.x + ',' + newLoc.y + ')';
|
|
490
|
+
this.svgGroup_.setAttribute(
|
|
491
|
+
'transform', this.svgGroup_.translate_ + this.svgGroup_.skew_);
|
|
492
|
+
}
|
|
289
493
|
}
|
|
290
|
-
const event = new (eventUtils.get(eventUtils.SELECTED))(
|
|
291
|
-
this.id, null, this.workspace.id);
|
|
292
|
-
eventUtils.fire(event);
|
|
293
|
-
common.setSelected(null);
|
|
294
|
-
this.removeSelect();
|
|
295
|
-
this.blurFocus();
|
|
296
|
-
};
|
|
297
494
|
|
|
298
|
-
/**
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
};
|
|
307
|
-
|
|
308
|
-
/**
|
|
309
|
-
* Unselect this comment. Remove its highlighting.
|
|
310
|
-
* @package
|
|
311
|
-
*/
|
|
312
|
-
WorkspaceCommentSvg.prototype.removeSelect = function() {
|
|
313
|
-
dom.removeClass(
|
|
314
|
-
/** @type {!Element} */ (this.svgGroup_), 'blocklySelected');
|
|
315
|
-
this.blurFocus();
|
|
316
|
-
};
|
|
317
|
-
|
|
318
|
-
/**
|
|
319
|
-
* Focus this comment. Highlight it visually.
|
|
320
|
-
* @package
|
|
321
|
-
*/
|
|
322
|
-
WorkspaceCommentSvg.prototype.addFocus = function() {
|
|
323
|
-
dom.addClass(
|
|
324
|
-
/** @type {!Element} */ (this.svgGroup_), 'blocklyFocused');
|
|
325
|
-
};
|
|
326
|
-
|
|
327
|
-
/**
|
|
328
|
-
* Unfocus this comment. Remove its highlighting.
|
|
329
|
-
* @package
|
|
330
|
-
*/
|
|
331
|
-
WorkspaceCommentSvg.prototype.removeFocus = function() {
|
|
332
|
-
dom.removeClass(
|
|
333
|
-
/** @type {!Element} */ (this.svgGroup_), 'blocklyFocused');
|
|
334
|
-
};
|
|
335
|
-
|
|
336
|
-
/**
|
|
337
|
-
* Return the coordinates of the top-left corner of this comment relative to
|
|
338
|
-
* the drawing surface's origin (0,0), in workspace units.
|
|
339
|
-
* If the comment is on the workspace, (0, 0) is the origin of the workspace
|
|
340
|
-
* coordinate system.
|
|
341
|
-
* This does not change with workspace scale.
|
|
342
|
-
* @return {!Coordinate} Object with .x and .y properties in
|
|
343
|
-
* workspace coordinates.
|
|
344
|
-
* @package
|
|
345
|
-
*/
|
|
346
|
-
WorkspaceCommentSvg.prototype.getRelativeToSurfaceXY = function() {
|
|
347
|
-
let x = 0;
|
|
348
|
-
let y = 0;
|
|
349
|
-
|
|
350
|
-
const dragSurfaceGroup = this.useDragSurface_ ?
|
|
351
|
-
this.workspace.getBlockDragSurface().getGroup() :
|
|
352
|
-
null;
|
|
353
|
-
|
|
354
|
-
let element = this.getSvgRoot();
|
|
355
|
-
if (element) {
|
|
356
|
-
do {
|
|
357
|
-
// Loop through this comment and every parent.
|
|
358
|
-
const xy = svgMath.getRelativeXY(/** @type {!Element} */ (element));
|
|
359
|
-
x += xy.x;
|
|
360
|
-
y += xy.y;
|
|
361
|
-
// If this element is the current element on the drag surface, include
|
|
362
|
-
// the translation of the drag surface itself.
|
|
363
|
-
if (this.useDragSurface_ &&
|
|
364
|
-
this.workspace.getBlockDragSurface().getCurrentBlock() === element) {
|
|
365
|
-
const surfaceTranslation =
|
|
366
|
-
this.workspace.getBlockDragSurface().getSurfaceTranslation();
|
|
367
|
-
x += surfaceTranslation.x;
|
|
368
|
-
y += surfaceTranslation.y;
|
|
369
|
-
}
|
|
370
|
-
element = element.parentNode;
|
|
371
|
-
} while (element && element !== this.workspace.getBubbleCanvas() &&
|
|
372
|
-
element !== dragSurfaceGroup);
|
|
495
|
+
/**
|
|
496
|
+
* Move the bubble group to the specified location in workspace coordinates.
|
|
497
|
+
* @param {number} x The x position to move to.
|
|
498
|
+
* @param {number} y The y position to move to.
|
|
499
|
+
* @package
|
|
500
|
+
*/
|
|
501
|
+
moveTo(x, y) {
|
|
502
|
+
this.translate(x, y);
|
|
373
503
|
}
|
|
374
|
-
this.xy_ = new Coordinate(x, y);
|
|
375
|
-
return this.xy_;
|
|
376
|
-
};
|
|
377
|
-
|
|
378
|
-
/**
|
|
379
|
-
* Move a comment by a relative offset.
|
|
380
|
-
* @param {number} dx Horizontal offset, in workspace units.
|
|
381
|
-
* @param {number} dy Vertical offset, in workspace units.
|
|
382
|
-
* @package
|
|
383
|
-
*/
|
|
384
|
-
WorkspaceCommentSvg.prototype.moveBy = function(dx, dy) {
|
|
385
|
-
const event = new (eventUtils.get(eventUtils.COMMENT_MOVE))(this);
|
|
386
|
-
// TODO: Do I need to look up the relative to surface XY position here?
|
|
387
|
-
const xy = this.getRelativeToSurfaceXY();
|
|
388
|
-
this.translate(xy.x + dx, xy.y + dy);
|
|
389
|
-
this.xy_ = new Coordinate(xy.x + dx, xy.y + dy);
|
|
390
|
-
event.recordNew();
|
|
391
|
-
eventUtils.fire(event);
|
|
392
|
-
this.workspace.resizeContents();
|
|
393
|
-
};
|
|
394
504
|
|
|
395
|
-
/**
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
WorkspaceCommentSvg.prototype.translate = function(x, y) {
|
|
403
|
-
this.xy_ = new Coordinate(x, y);
|
|
404
|
-
this.getSvgRoot().setAttribute('transform', 'translate(' + x + ',' + y + ')');
|
|
405
|
-
};
|
|
406
|
-
|
|
407
|
-
/**
|
|
408
|
-
* Move this comment to its workspace's drag surface, accounting for
|
|
409
|
-
* positioning. Generally should be called at the same time as
|
|
410
|
-
* setDragging(true). Does nothing if useDragSurface_ is false.
|
|
411
|
-
* @package
|
|
412
|
-
*/
|
|
413
|
-
WorkspaceCommentSvg.prototype.moveToDragSurface = function() {
|
|
414
|
-
if (!this.useDragSurface_) {
|
|
415
|
-
return;
|
|
505
|
+
/**
|
|
506
|
+
* Clear the comment of transform="..." attributes.
|
|
507
|
+
* Used when the comment is switching from 3d to 2d transform or vice versa.
|
|
508
|
+
* @private
|
|
509
|
+
*/
|
|
510
|
+
clearTransformAttributes_() {
|
|
511
|
+
this.getSvgRoot().removeAttribute('transform');
|
|
416
512
|
}
|
|
417
|
-
// The translation for drag surface blocks,
|
|
418
|
-
// is equal to the current relative-to-surface position,
|
|
419
|
-
// to keep the position in sync as it move on/off the surface.
|
|
420
|
-
// This is in workspace coordinates.
|
|
421
|
-
const xy = this.getRelativeToSurfaceXY();
|
|
422
|
-
this.clearTransformAttributes_();
|
|
423
|
-
this.workspace.getBlockDragSurface().translateSurface(xy.x, xy.y);
|
|
424
|
-
// Execute the move on the top-level SVG component
|
|
425
|
-
this.workspace.getBlockDragSurface().setBlocksAndShow(this.getSvgRoot());
|
|
426
|
-
};
|
|
427
513
|
|
|
428
|
-
/**
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
this.
|
|
443
|
-
|
|
514
|
+
/**
|
|
515
|
+
* Returns the coordinates of a bounding box describing the dimensions of this
|
|
516
|
+
* comment.
|
|
517
|
+
* Coordinate system: workspace coordinates.
|
|
518
|
+
* @return {!Rect} Object with coordinates of the bounding box.
|
|
519
|
+
* @package
|
|
520
|
+
*/
|
|
521
|
+
getBoundingRectangle() {
|
|
522
|
+
const blockXY = this.getRelativeToSurfaceXY();
|
|
523
|
+
const commentBounds = this.getHeightWidth();
|
|
524
|
+
const top = blockXY.y;
|
|
525
|
+
const bottom = blockXY.y + commentBounds.height;
|
|
526
|
+
let left;
|
|
527
|
+
let right;
|
|
528
|
+
if (this.RTL) {
|
|
529
|
+
left = blockXY.x - commentBounds.width;
|
|
530
|
+
// Add the width of the tab/puzzle piece knob to the x coordinate
|
|
531
|
+
// since X is the corner of the rectangle, not the whole puzzle piece.
|
|
532
|
+
right = blockXY.x;
|
|
533
|
+
} else {
|
|
534
|
+
// Subtract the width of the tab/puzzle piece knob to the x coordinate
|
|
535
|
+
// since X is the corner of the rectangle, not the whole puzzle piece.
|
|
536
|
+
left = blockXY.x;
|
|
537
|
+
right = blockXY.x + commentBounds.width;
|
|
538
|
+
}
|
|
539
|
+
return new Rect(top, bottom, left, right);
|
|
444
540
|
}
|
|
445
|
-
};
|
|
446
|
-
|
|
447
|
-
/**
|
|
448
|
-
* Move the bubble group to the specified location in workspace coordinates.
|
|
449
|
-
* @param {number} x The x position to move to.
|
|
450
|
-
* @param {number} y The y position to move to.
|
|
451
|
-
* @package
|
|
452
|
-
*/
|
|
453
|
-
WorkspaceCommentSvg.prototype.moveTo = function(x, y) {
|
|
454
|
-
this.translate(x, y);
|
|
455
|
-
};
|
|
456
541
|
|
|
457
|
-
/**
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
};
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
* Coordinate system: workspace coordinates.
|
|
470
|
-
* @return {!Rect} Object with coordinates of the bounding box.
|
|
471
|
-
* @package
|
|
472
|
-
*/
|
|
473
|
-
WorkspaceCommentSvg.prototype.getBoundingRectangle = function() {
|
|
474
|
-
const blockXY = this.getRelativeToSurfaceXY();
|
|
475
|
-
const commentBounds = this.getHeightWidth();
|
|
476
|
-
const top = blockXY.y;
|
|
477
|
-
const bottom = blockXY.y + commentBounds.height;
|
|
478
|
-
let left;
|
|
479
|
-
let right;
|
|
480
|
-
if (this.RTL) {
|
|
481
|
-
left = blockXY.x - commentBounds.width;
|
|
482
|
-
// Add the width of the tab/puzzle piece knob to the x coordinate
|
|
483
|
-
// since X is the corner of the rectangle, not the whole puzzle piece.
|
|
484
|
-
right = blockXY.x;
|
|
485
|
-
} else {
|
|
486
|
-
// Subtract the width of the tab/puzzle piece knob to the x coordinate
|
|
487
|
-
// since X is the corner of the rectangle, not the whole puzzle piece.
|
|
488
|
-
left = blockXY.x;
|
|
489
|
-
right = blockXY.x + commentBounds.width;
|
|
542
|
+
/**
|
|
543
|
+
* Add or remove the UI indicating if this comment is movable or not.
|
|
544
|
+
* @package
|
|
545
|
+
*/
|
|
546
|
+
updateMovable() {
|
|
547
|
+
if (this.isMovable()) {
|
|
548
|
+
dom.addClass(
|
|
549
|
+
/** @type {!Element} */ (this.svgGroup_), 'blocklyDraggable');
|
|
550
|
+
} else {
|
|
551
|
+
dom.removeClass(
|
|
552
|
+
/** @type {!Element} */ (this.svgGroup_), 'blocklyDraggable');
|
|
553
|
+
}
|
|
490
554
|
}
|
|
491
|
-
return new Rect(top, bottom, left, right);
|
|
492
|
-
};
|
|
493
555
|
|
|
494
|
-
/**
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
} else {
|
|
503
|
-
dom.removeClass(
|
|
504
|
-
/** @type {!Element} */ (this.svgGroup_), 'blocklyDraggable');
|
|
556
|
+
/**
|
|
557
|
+
* Set whether this comment is movable or not.
|
|
558
|
+
* @param {boolean} movable True if movable.
|
|
559
|
+
* @package
|
|
560
|
+
*/
|
|
561
|
+
setMovable(movable) {
|
|
562
|
+
super.setMovable(movable);
|
|
563
|
+
this.updateMovable();
|
|
505
564
|
}
|
|
506
|
-
};
|
|
507
565
|
|
|
508
|
-
/**
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
}
|
|
517
|
-
|
|
518
|
-
/**
|
|
519
|
-
* Set whether this comment is editable or not.
|
|
520
|
-
* @param {boolean} editable True if editable.
|
|
521
|
-
*/
|
|
522
|
-
WorkspaceCommentSvg.prototype.setEditable = function(editable) {
|
|
523
|
-
WorkspaceCommentSvg.superClass_.setEditable.call(this, editable);
|
|
524
|
-
if (this.textarea_) {
|
|
525
|
-
this.textarea_.readOnly = !editable;
|
|
566
|
+
/**
|
|
567
|
+
* Set whether this comment is editable or not.
|
|
568
|
+
* @param {boolean} editable True if editable.
|
|
569
|
+
*/
|
|
570
|
+
setEditable(editable) {
|
|
571
|
+
super.setEditable(editable);
|
|
572
|
+
if (this.textarea_) {
|
|
573
|
+
this.textarea_.readOnly = !editable;
|
|
574
|
+
}
|
|
526
575
|
}
|
|
527
|
-
};
|
|
528
576
|
|
|
529
|
-
/**
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
577
|
+
/**
|
|
578
|
+
* Recursively adds or removes the dragging class to this node and its
|
|
579
|
+
* children.
|
|
580
|
+
* @param {boolean} adding True if adding, false if removing.
|
|
581
|
+
* @package
|
|
582
|
+
*/
|
|
583
|
+
setDragging(adding) {
|
|
584
|
+
if (adding) {
|
|
585
|
+
const group = this.getSvgRoot();
|
|
586
|
+
group.translate_ = '';
|
|
587
|
+
group.skew_ = '';
|
|
588
|
+
dom.addClass(
|
|
589
|
+
/** @type {!Element} */ (this.svgGroup_), 'blocklyDragging');
|
|
590
|
+
} else {
|
|
591
|
+
dom.removeClass(
|
|
592
|
+
/** @type {!Element} */ (this.svgGroup_), 'blocklyDragging');
|
|
593
|
+
}
|
|
544
594
|
}
|
|
545
|
-
};
|
|
546
595
|
|
|
547
|
-
/**
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
}
|
|
596
|
+
/**
|
|
597
|
+
* Return the root node of the SVG or null if none exists.
|
|
598
|
+
* @return {!SVGElement} The root SVG node (probably a group).
|
|
599
|
+
* @package
|
|
600
|
+
*/
|
|
601
|
+
getSvgRoot() {
|
|
602
|
+
return this.svgGroup_;
|
|
603
|
+
}
|
|
555
604
|
|
|
556
|
-
/**
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
}
|
|
605
|
+
/**
|
|
606
|
+
* Returns this comment's text.
|
|
607
|
+
* @return {string} Comment text.
|
|
608
|
+
* @package
|
|
609
|
+
*/
|
|
610
|
+
getContent() {
|
|
611
|
+
return this.textarea_ ? this.textarea_.value : this.content_;
|
|
612
|
+
}
|
|
564
613
|
|
|
565
|
-
/**
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
|
|
614
|
+
/**
|
|
615
|
+
* Set this comment's content.
|
|
616
|
+
* @param {string} content Comment content.
|
|
617
|
+
* @package
|
|
618
|
+
*/
|
|
619
|
+
setContent(content) {
|
|
620
|
+
super.setContent(content);
|
|
621
|
+
if (this.textarea_) {
|
|
622
|
+
this.textarea_.value = content;
|
|
623
|
+
}
|
|
574
624
|
}
|
|
575
|
-
};
|
|
576
625
|
|
|
577
|
-
/**
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
|
|
626
|
+
/**
|
|
627
|
+
* Update the cursor over this comment by adding or removing a class.
|
|
628
|
+
* @param {boolean} enable True if the delete cursor should be shown, false
|
|
629
|
+
* otherwise.
|
|
630
|
+
* @package
|
|
631
|
+
*/
|
|
632
|
+
setDeleteStyle(enable) {
|
|
633
|
+
if (enable) {
|
|
634
|
+
dom.addClass(
|
|
635
|
+
/** @type {!Element} */ (this.svgGroup_), 'blocklyDraggingDelete');
|
|
636
|
+
} else {
|
|
637
|
+
dom.removeClass(
|
|
638
|
+
/** @type {!Element} */ (this.svgGroup_), 'blocklyDraggingDelete');
|
|
639
|
+
}
|
|
590
640
|
}
|
|
591
|
-
};
|
|
592
641
|
|
|
593
|
-
/**
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
}
|
|
642
|
+
/**
|
|
643
|
+
* Set whether auto-layout of this bubble is enabled. The first time a bubble
|
|
644
|
+
* is shown it positions itself to not cover any blocks. Once a user has
|
|
645
|
+
* dragged it to reposition, it renders where the user put it.
|
|
646
|
+
* @param {boolean} _enable True if auto-layout should be enabled, false
|
|
647
|
+
* otherwise.
|
|
648
|
+
* @package
|
|
649
|
+
*/
|
|
650
|
+
setAutoLayout(_enable) {
|
|
651
|
+
// NOP for compatibility with the bubble dragger.
|
|
652
|
+
}
|
|
604
653
|
|
|
605
|
-
/**
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
let comment;
|
|
617
|
-
try {
|
|
618
|
-
const info = WorkspaceComment.parseAttributes(xmlComment);
|
|
619
|
-
|
|
620
|
-
comment = new WorkspaceCommentSvg(
|
|
621
|
-
workspace, info.content, info.h, info.w, info.id);
|
|
622
|
-
if (workspace.rendered) {
|
|
623
|
-
comment.initSvg(true);
|
|
624
|
-
comment.render();
|
|
625
|
-
}
|
|
626
|
-
// Position the comment correctly, taking into account the width of a
|
|
627
|
-
// rendered RTL workspace.
|
|
628
|
-
if (!isNaN(info.x) && !isNaN(info.y)) {
|
|
629
|
-
if (workspace.RTL) {
|
|
630
|
-
const wsWidth = opt_wsWidth || workspace.getWidth();
|
|
631
|
-
comment.moveBy(wsWidth - info.x, info.y);
|
|
632
|
-
} else {
|
|
633
|
-
comment.moveBy(info.x, info.y);
|
|
634
|
-
}
|
|
654
|
+
/**
|
|
655
|
+
* Encode a comment subtree as XML with XY coordinates.
|
|
656
|
+
* @param {boolean=} opt_noId True if the encoder should skip the comment ID.
|
|
657
|
+
* @return {!Element} Tree of XML elements.
|
|
658
|
+
* @package
|
|
659
|
+
*/
|
|
660
|
+
toXmlWithXY(opt_noId) {
|
|
661
|
+
let width; // Not used in LTR.
|
|
662
|
+
if (this.workspace.RTL) {
|
|
663
|
+
// Here be performance dragons: This calls getMetrics().
|
|
664
|
+
width = this.workspace.getWidth();
|
|
635
665
|
}
|
|
636
|
-
|
|
637
|
-
|
|
666
|
+
const element = this.toXml(opt_noId);
|
|
667
|
+
const xy = this.getRelativeToSurfaceXY();
|
|
668
|
+
element.setAttribute(
|
|
669
|
+
'x', Math.round(this.workspace.RTL ? width - xy.x : xy.x));
|
|
670
|
+
element.setAttribute('y', Math.round(xy.y));
|
|
671
|
+
element.setAttribute('h', this.getHeight());
|
|
672
|
+
element.setAttribute('w', this.getWidth());
|
|
673
|
+
return element;
|
|
638
674
|
}
|
|
639
675
|
|
|
640
|
-
|
|
641
|
-
|
|
642
|
-
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
|
|
651
|
-
WorkspaceCommentSvg.prototype.toXmlWithXY = function(opt_noId) {
|
|
652
|
-
let width; // Not used in LTR.
|
|
653
|
-
if (this.workspace.RTL) {
|
|
654
|
-
// Here be performance dragons: This calls getMetrics().
|
|
655
|
-
width = this.workspace.getWidth();
|
|
676
|
+
/**
|
|
677
|
+
* Encode a comment for copying.
|
|
678
|
+
* @return {!ICopyable.CopyData} Copy metadata.
|
|
679
|
+
* @package
|
|
680
|
+
*/
|
|
681
|
+
toCopyData() {
|
|
682
|
+
return {
|
|
683
|
+
saveInfo: this.toXmlWithXY(),
|
|
684
|
+
source: this.workspace,
|
|
685
|
+
typeCounts: null,
|
|
686
|
+
};
|
|
656
687
|
}
|
|
657
|
-
const element = this.toXml(opt_noId);
|
|
658
|
-
const xy = this.getRelativeToSurfaceXY();
|
|
659
|
-
element.setAttribute(
|
|
660
|
-
'x', Math.round(this.workspace.RTL ? width - xy.x : xy.x));
|
|
661
|
-
element.setAttribute('y', Math.round(xy.y));
|
|
662
|
-
element.setAttribute('h', this.getHeight());
|
|
663
|
-
element.setAttribute('w', this.getWidth());
|
|
664
|
-
return element;
|
|
665
|
-
};
|
|
666
688
|
|
|
667
|
-
/**
|
|
668
|
-
|
|
669
|
-
|
|
670
|
-
|
|
671
|
-
|
|
672
|
-
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
|
|
676
|
-
typeCounts: null,
|
|
677
|
-
};
|
|
678
|
-
};
|
|
689
|
+
/**
|
|
690
|
+
* Returns a bounding box describing the dimensions of this comment.
|
|
691
|
+
* @return {!{height: number, width: number}} Object with height and width
|
|
692
|
+
* properties in workspace units.
|
|
693
|
+
* @package
|
|
694
|
+
*/
|
|
695
|
+
getHeightWidth() {
|
|
696
|
+
return {width: this.getWidth(), height: this.getHeight()};
|
|
697
|
+
}
|
|
679
698
|
|
|
680
|
-
/**
|
|
681
|
-
|
|
682
|
-
|
|
683
|
-
|
|
684
|
-
|
|
685
|
-
|
|
686
|
-
|
|
687
|
-
|
|
688
|
-
};
|
|
699
|
+
/**
|
|
700
|
+
* Renders the workspace comment.
|
|
701
|
+
* @package
|
|
702
|
+
*/
|
|
703
|
+
render() {
|
|
704
|
+
if (this.rendered_) {
|
|
705
|
+
return;
|
|
706
|
+
}
|
|
689
707
|
|
|
690
|
-
|
|
691
|
-
|
|
692
|
-
|
|
693
|
-
|
|
694
|
-
|
|
695
|
-
|
|
696
|
-
|
|
697
|
-
|
|
708
|
+
const size = this.getHeightWidth();
|
|
709
|
+
|
|
710
|
+
// Add text area
|
|
711
|
+
this.createEditor_();
|
|
712
|
+
this.svgGroup_.appendChild(this.foreignObject_);
|
|
713
|
+
|
|
714
|
+
this.svgHandleTarget_ = dom.createSvgElement(
|
|
715
|
+
Svg.RECT, {'class': 'blocklyCommentHandleTarget', 'x': 0, 'y': 0});
|
|
716
|
+
this.svgGroup_.appendChild(this.svgHandleTarget_);
|
|
717
|
+
this.svgRectTarget_ = dom.createSvgElement(Svg.RECT, {
|
|
718
|
+
'class': 'blocklyCommentTarget',
|
|
719
|
+
'x': 0,
|
|
720
|
+
'y': 0,
|
|
721
|
+
'rx': BORDER_RADIUS,
|
|
722
|
+
'ry': BORDER_RADIUS,
|
|
723
|
+
});
|
|
724
|
+
this.svgGroup_.appendChild(this.svgRectTarget_);
|
|
725
|
+
|
|
726
|
+
// Add the resize icon
|
|
727
|
+
this.addResizeDom_();
|
|
728
|
+
if (this.isDeletable()) {
|
|
729
|
+
// Add the delete icon
|
|
730
|
+
this.addDeleteDom_();
|
|
731
|
+
}
|
|
698
732
|
|
|
699
|
-
|
|
700
|
-
|
|
701
|
-
// Add text area
|
|
702
|
-
this.createEditor_();
|
|
703
|
-
this.svgGroup_.appendChild(this.foreignObject_);
|
|
704
|
-
|
|
705
|
-
this.svgHandleTarget_ = dom.createSvgElement(
|
|
706
|
-
Svg.RECT, {'class': 'blocklyCommentHandleTarget', 'x': 0, 'y': 0});
|
|
707
|
-
this.svgGroup_.appendChild(this.svgHandleTarget_);
|
|
708
|
-
this.svgRectTarget_ = dom.createSvgElement(Svg.RECT, {
|
|
709
|
-
'class': 'blocklyCommentTarget',
|
|
710
|
-
'x': 0,
|
|
711
|
-
'y': 0,
|
|
712
|
-
'rx': BORDER_RADIUS,
|
|
713
|
-
'ry': BORDER_RADIUS,
|
|
714
|
-
});
|
|
715
|
-
this.svgGroup_.appendChild(this.svgRectTarget_);
|
|
716
|
-
|
|
717
|
-
// Add the resize icon
|
|
718
|
-
this.addResizeDom_();
|
|
719
|
-
if (this.isDeletable()) {
|
|
720
|
-
// Add the delete icon
|
|
721
|
-
this.addDeleteDom_();
|
|
722
|
-
}
|
|
733
|
+
this.setSize_(size.width, size.height);
|
|
723
734
|
|
|
724
|
-
|
|
735
|
+
// Set the content
|
|
736
|
+
this.textarea_.value = this.content_;
|
|
725
737
|
|
|
726
|
-
|
|
727
|
-
this.textarea_.value = this.content_;
|
|
738
|
+
this.rendered_ = true;
|
|
728
739
|
|
|
729
|
-
|
|
740
|
+
if (this.resizeGroup_) {
|
|
741
|
+
browserEvents.conditionalBind(
|
|
742
|
+
/** @type {!SVGGElement} */ (this.resizeGroup_), 'mousedown', this,
|
|
743
|
+
this.resizeMouseDown_);
|
|
744
|
+
}
|
|
730
745
|
|
|
731
|
-
|
|
732
|
-
|
|
733
|
-
|
|
746
|
+
if (this.isDeletable()) {
|
|
747
|
+
browserEvents.conditionalBind(
|
|
748
|
+
/** @type {!SVGGElement} */ (this.deleteGroup_), 'mousedown', this,
|
|
749
|
+
this.deleteMouseDown_);
|
|
750
|
+
browserEvents.conditionalBind(
|
|
751
|
+
/** @type {!SVGGElement} */ (this.deleteGroup_), 'mouseout', this,
|
|
752
|
+
this.deleteMouseOut_);
|
|
753
|
+
browserEvents.conditionalBind(
|
|
754
|
+
/** @type {!SVGGElement} */ (this.deleteGroup_), 'mouseup', this,
|
|
755
|
+
this.deleteMouseUp_);
|
|
756
|
+
}
|
|
734
757
|
}
|
|
735
758
|
|
|
736
|
-
|
|
737
|
-
|
|
738
|
-
|
|
739
|
-
|
|
740
|
-
|
|
759
|
+
/**
|
|
760
|
+
* Create the text area for the comment.
|
|
761
|
+
* @return {!Element} The top-level node of the editor.
|
|
762
|
+
* @private
|
|
763
|
+
*/
|
|
764
|
+
createEditor_() {
|
|
765
|
+
/* Create the editor. Here's the markup that will be generated:
|
|
766
|
+
<foreignObject class="blocklyCommentForeignObject" x="0" y="10"
|
|
767
|
+
width="164" height="164"> <body xmlns="http://www.w3.org/1999/xhtml"
|
|
768
|
+
class="blocklyMinimalBody"> <textarea xmlns="http://www.w3.org/1999/xhtml"
|
|
769
|
+
class="blocklyCommentTextarea"
|
|
770
|
+
style="height: 164px; width: 164px;"></textarea>
|
|
771
|
+
</body>
|
|
772
|
+
</foreignObject>
|
|
773
|
+
*/
|
|
774
|
+
this.foreignObject_ = dom.createSvgElement(
|
|
775
|
+
Svg.FOREIGNOBJECT, {
|
|
776
|
+
'x': 0,
|
|
777
|
+
'y': WorkspaceCommentSvg.TOP_OFFSET,
|
|
778
|
+
'class': 'blocklyCommentForeignObject',
|
|
779
|
+
},
|
|
780
|
+
null);
|
|
781
|
+
const body = document.createElementNS(dom.HTML_NS, 'body');
|
|
782
|
+
body.setAttribute('xmlns', dom.HTML_NS);
|
|
783
|
+
body.className = 'blocklyMinimalBody';
|
|
784
|
+
const textarea = document.createElementNS(dom.HTML_NS, 'textarea');
|
|
785
|
+
textarea.className = 'blocklyCommentTextarea';
|
|
786
|
+
textarea.setAttribute('dir', this.RTL ? 'RTL' : 'LTR');
|
|
787
|
+
textarea.readOnly = !this.isEditable();
|
|
788
|
+
body.appendChild(textarea);
|
|
789
|
+
this.textarea_ = textarea;
|
|
790
|
+
this.foreignObject_.appendChild(body);
|
|
791
|
+
// Don't zoom with mousewheel.
|
|
792
|
+
browserEvents.conditionalBind(textarea, 'wheel', this, function(e) {
|
|
793
|
+
e.stopPropagation();
|
|
794
|
+
});
|
|
741
795
|
browserEvents.conditionalBind(
|
|
742
|
-
|
|
796
|
+
textarea, 'change', this,
|
|
797
|
+
/**
|
|
798
|
+
* @this {WorkspaceCommentSvg}
|
|
799
|
+
* @param {Event} e Unused event parameter
|
|
800
|
+
*/
|
|
801
|
+
function(
|
|
802
|
+
/* eslint-disable no-unused-vars */ e
|
|
803
|
+
/* eslint-enable no-unused-vars */) {
|
|
804
|
+
this.setContent(textarea.value);
|
|
805
|
+
});
|
|
806
|
+
return this.foreignObject_;
|
|
743
807
|
}
|
|
744
|
-
};
|
|
745
|
-
|
|
746
|
-
/**
|
|
747
|
-
* Create the text area for the comment.
|
|
748
|
-
* @return {!Element} The top-level node of the editor.
|
|
749
|
-
* @private
|
|
750
|
-
*/
|
|
751
|
-
WorkspaceCommentSvg.prototype.createEditor_ = function() {
|
|
752
|
-
/* Create the editor. Here's the markup that will be generated:
|
|
753
|
-
<foreignObject class="blocklyCommentForeignObject" x="0" y="10" width="164"
|
|
754
|
-
height="164"> <body xmlns="http://www.w3.org/1999/xhtml"
|
|
755
|
-
class="blocklyMinimalBody"> <textarea xmlns="http://www.w3.org/1999/xhtml"
|
|
756
|
-
class="blocklyCommentTextarea"
|
|
757
|
-
style="height: 164px; width: 164px;"></textarea>
|
|
758
|
-
</body>
|
|
759
|
-
</foreignObject>
|
|
760
|
-
*/
|
|
761
|
-
this.foreignObject_ = dom.createSvgElement(
|
|
762
|
-
Svg.FOREIGNOBJECT, {
|
|
763
|
-
'x': 0,
|
|
764
|
-
'y': WorkspaceCommentSvg.TOP_OFFSET,
|
|
765
|
-
'class': 'blocklyCommentForeignObject',
|
|
766
|
-
},
|
|
767
|
-
null);
|
|
768
|
-
const body = document.createElementNS(dom.HTML_NS, 'body');
|
|
769
|
-
body.setAttribute('xmlns', dom.HTML_NS);
|
|
770
|
-
body.className = 'blocklyMinimalBody';
|
|
771
|
-
const textarea = document.createElementNS(dom.HTML_NS, 'textarea');
|
|
772
|
-
textarea.className = 'blocklyCommentTextarea';
|
|
773
|
-
textarea.setAttribute('dir', this.RTL ? 'RTL' : 'LTR');
|
|
774
|
-
textarea.readOnly = !this.isEditable();
|
|
775
|
-
body.appendChild(textarea);
|
|
776
|
-
this.textarea_ = textarea;
|
|
777
|
-
this.foreignObject_.appendChild(body);
|
|
778
|
-
// Don't zoom with mousewheel.
|
|
779
|
-
browserEvents.conditionalBind(textarea, 'wheel', this, function(e) {
|
|
780
|
-
e.stopPropagation();
|
|
781
|
-
});
|
|
782
|
-
browserEvents.conditionalBind(
|
|
783
|
-
textarea, 'change', this,
|
|
784
|
-
/**
|
|
785
|
-
* @this {WorkspaceCommentSvg}
|
|
786
|
-
* @param {Event} e Unused event parameter
|
|
787
|
-
*/
|
|
788
|
-
function(
|
|
789
|
-
/* eslint-disable no-unused-vars */ e
|
|
790
|
-
/* eslint-enable no-unused-vars */) {
|
|
791
|
-
this.setContent(textarea.value);
|
|
792
|
-
});
|
|
793
|
-
return this.foreignObject_;
|
|
794
|
-
};
|
|
795
808
|
|
|
796
|
-
/**
|
|
797
|
-
|
|
798
|
-
|
|
799
|
-
|
|
800
|
-
|
|
801
|
-
|
|
802
|
-
|
|
803
|
-
|
|
804
|
-
|
|
805
|
-
|
|
806
|
-
|
|
807
|
-
|
|
808
|
-
|
|
809
|
-
|
|
810
|
-
|
|
811
|
-
|
|
812
|
-
|
|
813
|
-
|
|
814
|
-
|
|
815
|
-
|
|
816
|
-
|
|
817
|
-
|
|
818
|
-
|
|
819
|
-
|
|
820
|
-
|
|
821
|
-
|
|
822
|
-
|
|
823
|
-
|
|
824
|
-
|
|
825
|
-
|
|
826
|
-
}
|
|
809
|
+
/**
|
|
810
|
+
* Add the resize icon to the DOM
|
|
811
|
+
* @private
|
|
812
|
+
*/
|
|
813
|
+
addResizeDom_() {
|
|
814
|
+
this.resizeGroup_ = dom.createSvgElement(
|
|
815
|
+
Svg.G, {'class': this.RTL ? 'blocklyResizeSW' : 'blocklyResizeSE'},
|
|
816
|
+
this.svgGroup_);
|
|
817
|
+
dom.createSvgElement(
|
|
818
|
+
Svg.POLYGON,
|
|
819
|
+
{'points': '0,x x,x x,0'.replace(/x/g, RESIZE_SIZE.toString())},
|
|
820
|
+
this.resizeGroup_);
|
|
821
|
+
dom.createSvgElement(
|
|
822
|
+
Svg.LINE, {
|
|
823
|
+
'class': 'blocklyResizeLine',
|
|
824
|
+
'x1': RESIZE_SIZE / 3,
|
|
825
|
+
'y1': RESIZE_SIZE - 1,
|
|
826
|
+
'x2': RESIZE_SIZE - 1,
|
|
827
|
+
'y2': RESIZE_SIZE / 3,
|
|
828
|
+
},
|
|
829
|
+
this.resizeGroup_);
|
|
830
|
+
dom.createSvgElement(
|
|
831
|
+
Svg.LINE, {
|
|
832
|
+
'class': 'blocklyResizeLine',
|
|
833
|
+
'x1': RESIZE_SIZE * 2 / 3,
|
|
834
|
+
'y1': RESIZE_SIZE - 1,
|
|
835
|
+
'x2': RESIZE_SIZE - 1,
|
|
836
|
+
'y2': RESIZE_SIZE * 2 / 3,
|
|
837
|
+
},
|
|
838
|
+
this.resizeGroup_);
|
|
839
|
+
}
|
|
827
840
|
|
|
828
|
-
/**
|
|
829
|
-
|
|
830
|
-
|
|
831
|
-
|
|
832
|
-
|
|
833
|
-
|
|
834
|
-
|
|
835
|
-
|
|
836
|
-
|
|
837
|
-
|
|
838
|
-
|
|
839
|
-
|
|
840
|
-
|
|
841
|
-
|
|
842
|
-
|
|
843
|
-
|
|
844
|
-
|
|
845
|
-
|
|
846
|
-
|
|
847
|
-
|
|
848
|
-
|
|
849
|
-
|
|
850
|
-
|
|
851
|
-
|
|
852
|
-
|
|
853
|
-
|
|
854
|
-
|
|
855
|
-
|
|
856
|
-
|
|
857
|
-
|
|
858
|
-
|
|
859
|
-
|
|
860
|
-
}
|
|
841
|
+
/**
|
|
842
|
+
* Add the delete icon to the DOM
|
|
843
|
+
* @private
|
|
844
|
+
*/
|
|
845
|
+
addDeleteDom_() {
|
|
846
|
+
this.deleteGroup_ = dom.createSvgElement(
|
|
847
|
+
Svg.G, {'class': 'blocklyCommentDeleteIcon'}, this.svgGroup_);
|
|
848
|
+
this.deleteIconBorder_ = dom.createSvgElement(
|
|
849
|
+
Svg.CIRCLE,
|
|
850
|
+
{'class': 'blocklyDeleteIconShape', 'r': '7', 'cx': '7.5', 'cy': '7.5'},
|
|
851
|
+
this.deleteGroup_);
|
|
852
|
+
// x icon.
|
|
853
|
+
dom.createSvgElement(
|
|
854
|
+
Svg.LINE, {
|
|
855
|
+
'x1': '5',
|
|
856
|
+
'y1': '10',
|
|
857
|
+
'x2': '10',
|
|
858
|
+
'y2': '5',
|
|
859
|
+
'stroke': '#fff',
|
|
860
|
+
'stroke-width': '2',
|
|
861
|
+
},
|
|
862
|
+
this.deleteGroup_);
|
|
863
|
+
dom.createSvgElement(
|
|
864
|
+
Svg.LINE, {
|
|
865
|
+
'x1': '5',
|
|
866
|
+
'y1': '5',
|
|
867
|
+
'x2': '10',
|
|
868
|
+
'y2': '10',
|
|
869
|
+
'stroke': '#fff',
|
|
870
|
+
'stroke-width': '2',
|
|
871
|
+
},
|
|
872
|
+
this.deleteGroup_);
|
|
873
|
+
}
|
|
861
874
|
|
|
862
|
-
/**
|
|
863
|
-
|
|
864
|
-
|
|
865
|
-
|
|
866
|
-
|
|
867
|
-
|
|
868
|
-
|
|
869
|
-
|
|
870
|
-
|
|
875
|
+
/**
|
|
876
|
+
* Handle a mouse-down on comment's resize corner.
|
|
877
|
+
* @param {!Event} e Mouse down event.
|
|
878
|
+
* @private
|
|
879
|
+
*/
|
|
880
|
+
resizeMouseDown_(e) {
|
|
881
|
+
this.unbindDragEvents_();
|
|
882
|
+
if (browserEvents.isRightButton(e)) {
|
|
883
|
+
// No right-click.
|
|
884
|
+
e.stopPropagation();
|
|
885
|
+
return;
|
|
886
|
+
}
|
|
887
|
+
// Left-click (or middle click)
|
|
888
|
+
this.workspace.startDrag(
|
|
889
|
+
e,
|
|
890
|
+
new Coordinate(
|
|
891
|
+
this.workspace.RTL ? -this.width_ : this.width_, this.height_));
|
|
892
|
+
|
|
893
|
+
this.onMouseUpWrapper_ = browserEvents.conditionalBind(
|
|
894
|
+
document, 'mouseup', this, this.resizeMouseUp_);
|
|
895
|
+
this.onMouseMoveWrapper_ = browserEvents.conditionalBind(
|
|
896
|
+
document, 'mousemove', this, this.resizeMouseMove_);
|
|
897
|
+
this.workspace.hideChaff();
|
|
898
|
+
// This event has been handled. No need to bubble up to the document.
|
|
871
899
|
e.stopPropagation();
|
|
872
|
-
return;
|
|
873
900
|
}
|
|
874
|
-
// Left-click (or middle click)
|
|
875
|
-
this.workspace.startDrag(
|
|
876
|
-
e,
|
|
877
|
-
new Coordinate(
|
|
878
|
-
this.workspace.RTL ? -this.width_ : this.width_, this.height_));
|
|
879
|
-
|
|
880
|
-
this.onMouseUpWrapper_ = browserEvents.conditionalBind(
|
|
881
|
-
document, 'mouseup', this, this.resizeMouseUp_);
|
|
882
|
-
this.onMouseMoveWrapper_ = browserEvents.conditionalBind(
|
|
883
|
-
document, 'mousemove', this, this.resizeMouseMove_);
|
|
884
|
-
this.workspace.hideChaff();
|
|
885
|
-
// This event has been handled. No need to bubble up to the document.
|
|
886
|
-
e.stopPropagation();
|
|
887
|
-
};
|
|
888
|
-
|
|
889
|
-
/**
|
|
890
|
-
* Handle a mouse-down on comment's delete icon.
|
|
891
|
-
* @param {!Event} e Mouse down event.
|
|
892
|
-
* @private
|
|
893
|
-
*/
|
|
894
|
-
WorkspaceCommentSvg.prototype.deleteMouseDown_ = function(e) {
|
|
895
|
-
// Highlight the delete icon.
|
|
896
|
-
dom.addClass(
|
|
897
|
-
/** @type {!Element} */ (this.deleteIconBorder_),
|
|
898
|
-
'blocklyDeleteIconHighlighted');
|
|
899
|
-
// This event has been handled. No need to bubble up to the document.
|
|
900
|
-
e.stopPropagation();
|
|
901
|
-
};
|
|
902
901
|
|
|
903
|
-
/**
|
|
904
|
-
|
|
905
|
-
|
|
906
|
-
|
|
907
|
-
|
|
908
|
-
|
|
909
|
-
|
|
910
|
-
|
|
911
|
-
|
|
912
|
-
|
|
913
|
-
|
|
914
|
-
|
|
915
|
-
/**
|
|
916
|
-
* Handle a mouse-up on comment's delete icon.
|
|
917
|
-
* @param {!Event} e Mouse up event.
|
|
918
|
-
* @private
|
|
919
|
-
*/
|
|
920
|
-
WorkspaceCommentSvg.prototype.deleteMouseUp_ = function(e) {
|
|
921
|
-
// Delete this comment.
|
|
922
|
-
this.dispose();
|
|
923
|
-
// This event has been handled. No need to bubble up to the document.
|
|
924
|
-
e.stopPropagation();
|
|
925
|
-
};
|
|
926
|
-
|
|
927
|
-
/**
|
|
928
|
-
* Stop binding to the global mouseup and mousemove events.
|
|
929
|
-
* @private
|
|
930
|
-
*/
|
|
931
|
-
WorkspaceCommentSvg.prototype.unbindDragEvents_ = function() {
|
|
932
|
-
if (this.onMouseUpWrapper_) {
|
|
933
|
-
browserEvents.unbind(this.onMouseUpWrapper_);
|
|
934
|
-
this.onMouseUpWrapper_ = null;
|
|
902
|
+
/**
|
|
903
|
+
* Handle a mouse-down on comment's delete icon.
|
|
904
|
+
* @param {!Event} e Mouse down event.
|
|
905
|
+
* @private
|
|
906
|
+
*/
|
|
907
|
+
deleteMouseDown_(e) {
|
|
908
|
+
// Highlight the delete icon.
|
|
909
|
+
dom.addClass(
|
|
910
|
+
/** @type {!Element} */ (this.deleteIconBorder_),
|
|
911
|
+
'blocklyDeleteIconHighlighted');
|
|
912
|
+
// This event has been handled. No need to bubble up to the document.
|
|
913
|
+
e.stopPropagation();
|
|
935
914
|
}
|
|
936
|
-
|
|
937
|
-
|
|
938
|
-
|
|
915
|
+
|
|
916
|
+
/**
|
|
917
|
+
* Handle a mouse-out on comment's delete icon.
|
|
918
|
+
* @param {!Event} _e Mouse out event.
|
|
919
|
+
* @private
|
|
920
|
+
*/
|
|
921
|
+
deleteMouseOut_(_e) {
|
|
922
|
+
// Restore highlight on the delete icon.
|
|
923
|
+
dom.removeClass(
|
|
924
|
+
/** @type {!Element} */ (this.deleteIconBorder_),
|
|
925
|
+
'blocklyDeleteIconHighlighted');
|
|
939
926
|
}
|
|
940
|
-
};
|
|
941
927
|
|
|
942
|
-
/**
|
|
943
|
-
|
|
944
|
-
|
|
945
|
-
|
|
946
|
-
|
|
947
|
-
|
|
948
|
-
|
|
949
|
-
|
|
950
|
-
|
|
928
|
+
/**
|
|
929
|
+
* Handle a mouse-up on comment's delete icon.
|
|
930
|
+
* @param {!Event} e Mouse up event.
|
|
931
|
+
* @private
|
|
932
|
+
*/
|
|
933
|
+
deleteMouseUp_(e) {
|
|
934
|
+
// Delete this comment.
|
|
935
|
+
this.dispose();
|
|
936
|
+
// This event has been handled. No need to bubble up to the document.
|
|
937
|
+
e.stopPropagation();
|
|
938
|
+
}
|
|
951
939
|
|
|
952
|
-
/**
|
|
953
|
-
|
|
954
|
-
|
|
955
|
-
|
|
956
|
-
|
|
957
|
-
|
|
958
|
-
|
|
959
|
-
|
|
960
|
-
|
|
961
|
-
|
|
940
|
+
/**
|
|
941
|
+
* Stop binding to the global mouseup and mousemove events.
|
|
942
|
+
* @private
|
|
943
|
+
*/
|
|
944
|
+
unbindDragEvents_() {
|
|
945
|
+
if (this.onMouseUpWrapper_) {
|
|
946
|
+
browserEvents.unbind(this.onMouseUpWrapper_);
|
|
947
|
+
this.onMouseUpWrapper_ = null;
|
|
948
|
+
}
|
|
949
|
+
if (this.onMouseMoveWrapper_) {
|
|
950
|
+
browserEvents.unbind(this.onMouseMoveWrapper_);
|
|
951
|
+
this.onMouseMoveWrapper_ = null;
|
|
952
|
+
}
|
|
953
|
+
}
|
|
962
954
|
|
|
963
|
-
/**
|
|
964
|
-
|
|
965
|
-
|
|
966
|
-
|
|
967
|
-
|
|
968
|
-
|
|
969
|
-
|
|
970
|
-
|
|
971
|
-
const textOffset = TEXTAREA_OFFSET * 2;
|
|
972
|
-
|
|
973
|
-
this.foreignObject_.setAttribute('width', size.width);
|
|
974
|
-
this.foreignObject_.setAttribute('height', size.height - topOffset);
|
|
975
|
-
if (this.RTL) {
|
|
976
|
-
this.foreignObject_.setAttribute('x', -size.width);
|
|
955
|
+
/**
|
|
956
|
+
* Handle a mouse-up event while dragging a comment's border or resize handle.
|
|
957
|
+
* @param {!Event} _e Mouse up event.
|
|
958
|
+
* @private
|
|
959
|
+
*/
|
|
960
|
+
resizeMouseUp_(_e) {
|
|
961
|
+
Touch.clearTouchIdentifier();
|
|
962
|
+
this.unbindDragEvents_();
|
|
977
963
|
}
|
|
978
|
-
this.textarea_.style.width = (size.width - textOffset) + 'px';
|
|
979
|
-
this.textarea_.style.height = (size.height - textOffset - topOffset) + 'px';
|
|
980
|
-
};
|
|
981
964
|
|
|
982
|
-
/**
|
|
983
|
-
|
|
984
|
-
|
|
985
|
-
|
|
986
|
-
|
|
987
|
-
|
|
988
|
-
|
|
989
|
-
|
|
990
|
-
|
|
991
|
-
height = Math.max(height, 20 + WorkspaceCommentSvg.TOP_OFFSET);
|
|
992
|
-
this.width_ = width;
|
|
993
|
-
this.height_ = height;
|
|
994
|
-
this.svgRect_.setAttribute('width', width);
|
|
995
|
-
this.svgRect_.setAttribute('height', height);
|
|
996
|
-
this.svgRectTarget_.setAttribute('width', width);
|
|
997
|
-
this.svgRectTarget_.setAttribute('height', height);
|
|
998
|
-
this.svgHandleTarget_.setAttribute('width', width);
|
|
999
|
-
this.svgHandleTarget_.setAttribute('height', WorkspaceCommentSvg.TOP_OFFSET);
|
|
1000
|
-
if (this.RTL) {
|
|
1001
|
-
this.svgRect_.setAttribute('transform', 'scale(-1 1)');
|
|
1002
|
-
this.svgRectTarget_.setAttribute('transform', 'scale(-1 1)');
|
|
965
|
+
/**
|
|
966
|
+
* Resize this comment to follow the mouse.
|
|
967
|
+
* @param {!Event} e Mouse move event.
|
|
968
|
+
* @private
|
|
969
|
+
*/
|
|
970
|
+
resizeMouseMove_(e) {
|
|
971
|
+
this.autoLayout_ = false;
|
|
972
|
+
const newXY = this.workspace.moveDrag(e);
|
|
973
|
+
this.setSize_(this.RTL ? -newXY.x : newXY.x, newXY.y);
|
|
1003
974
|
}
|
|
1004
975
|
|
|
1005
|
-
|
|
976
|
+
/**
|
|
977
|
+
* Callback function triggered when the comment has resized.
|
|
978
|
+
* Resize the text area accordingly.
|
|
979
|
+
* @private
|
|
980
|
+
*/
|
|
981
|
+
resizeComment_() {
|
|
982
|
+
const size = this.getHeightWidth();
|
|
983
|
+
const topOffset = WorkspaceCommentSvg.TOP_OFFSET;
|
|
984
|
+
const textOffset = TEXTAREA_OFFSET * 2;
|
|
985
|
+
|
|
986
|
+
this.foreignObject_.setAttribute('width', size.width);
|
|
987
|
+
this.foreignObject_.setAttribute('height', size.height - topOffset);
|
|
1006
988
|
if (this.RTL) {
|
|
1007
|
-
|
|
1008
|
-
this.resizeGroup_.setAttribute(
|
|
1009
|
-
'transform',
|
|
1010
|
-
'translate(' + (-width + RESIZE_SIZE) + ',' + (height - RESIZE_SIZE) +
|
|
1011
|
-
') scale(-1 1)');
|
|
1012
|
-
this.deleteGroup_.setAttribute(
|
|
1013
|
-
'transform',
|
|
1014
|
-
'translate(' + (-width + RESIZE_SIZE) + ',' + (-RESIZE_SIZE) +
|
|
1015
|
-
') scale(-1 1)');
|
|
1016
|
-
} else {
|
|
1017
|
-
this.resizeGroup_.setAttribute(
|
|
1018
|
-
'transform',
|
|
1019
|
-
'translate(' + (width - RESIZE_SIZE) + ',' + (height - RESIZE_SIZE) +
|
|
1020
|
-
')');
|
|
1021
|
-
this.deleteGroup_.setAttribute(
|
|
1022
|
-
'transform',
|
|
1023
|
-
'translate(' + (width - RESIZE_SIZE) + ',' + (-RESIZE_SIZE) + ')');
|
|
989
|
+
this.foreignObject_.setAttribute('x', -size.width);
|
|
1024
990
|
}
|
|
991
|
+
this.textarea_.style.width = (size.width - textOffset) + 'px';
|
|
992
|
+
this.textarea_.style.height = (size.height - textOffset - topOffset) + 'px';
|
|
1025
993
|
}
|
|
1026
994
|
|
|
1027
|
-
|
|
1028
|
-
|
|
1029
|
-
}
|
|
1030
|
-
|
|
1031
|
-
|
|
1032
|
-
|
|
1033
|
-
|
|
1034
|
-
|
|
1035
|
-
|
|
1036
|
-
|
|
1037
|
-
|
|
1038
|
-
|
|
1039
|
-
|
|
1040
|
-
|
|
1041
|
-
|
|
1042
|
-
|
|
1043
|
-
|
|
1044
|
-
|
|
1045
|
-
|
|
1046
|
-
|
|
1047
|
-
|
|
1048
|
-
|
|
1049
|
-
this.focused_ = true;
|
|
1050
|
-
// Defer CSS changes.
|
|
1051
|
-
setTimeout(function() {
|
|
1052
|
-
if (comment.disposed_) {
|
|
1053
|
-
return;
|
|
995
|
+
/**
|
|
996
|
+
* Set size
|
|
997
|
+
* @param {number} width width of the container
|
|
998
|
+
* @param {number} height height of the container
|
|
999
|
+
* @private
|
|
1000
|
+
*/
|
|
1001
|
+
setSize_(width, height) {
|
|
1002
|
+
// Minimum size of a comment.
|
|
1003
|
+
width = Math.max(width, 45);
|
|
1004
|
+
height = Math.max(height, 20 + WorkspaceCommentSvg.TOP_OFFSET);
|
|
1005
|
+
this.width_ = width;
|
|
1006
|
+
this.height_ = height;
|
|
1007
|
+
this.svgRect_.setAttribute('width', width);
|
|
1008
|
+
this.svgRect_.setAttribute('height', height);
|
|
1009
|
+
this.svgRectTarget_.setAttribute('width', width);
|
|
1010
|
+
this.svgRectTarget_.setAttribute('height', height);
|
|
1011
|
+
this.svgHandleTarget_.setAttribute('width', width);
|
|
1012
|
+
this.svgHandleTarget_.setAttribute(
|
|
1013
|
+
'height', WorkspaceCommentSvg.TOP_OFFSET);
|
|
1014
|
+
if (this.RTL) {
|
|
1015
|
+
this.svgRect_.setAttribute('transform', 'scale(-1 1)');
|
|
1016
|
+
this.svgRectTarget_.setAttribute('transform', 'scale(-1 1)');
|
|
1054
1017
|
}
|
|
1055
|
-
comment.textarea_.focus();
|
|
1056
|
-
comment.addFocus();
|
|
1057
|
-
dom.addClass(comment.svgRectTarget_, 'blocklyCommentTargetFocused');
|
|
1058
|
-
dom.addClass(comment.svgHandleTarget_, 'blocklyCommentHandleTargetFocused');
|
|
1059
|
-
}, 0);
|
|
1060
|
-
};
|
|
1061
1018
|
|
|
1062
|
-
|
|
1063
|
-
|
|
1064
|
-
|
|
1065
|
-
|
|
1066
|
-
|
|
1067
|
-
|
|
1068
|
-
|
|
1069
|
-
|
|
1070
|
-
|
|
1071
|
-
|
|
1072
|
-
|
|
1019
|
+
if (this.resizeGroup_) {
|
|
1020
|
+
if (this.RTL) {
|
|
1021
|
+
// Mirror the resize group.
|
|
1022
|
+
this.resizeGroup_.setAttribute(
|
|
1023
|
+
'transform',
|
|
1024
|
+
'translate(' + (-width + RESIZE_SIZE) + ',' +
|
|
1025
|
+
(height - RESIZE_SIZE) + ') scale(-1 1)');
|
|
1026
|
+
this.deleteGroup_.setAttribute(
|
|
1027
|
+
'transform',
|
|
1028
|
+
'translate(' + (-width + RESIZE_SIZE) + ',' + (-RESIZE_SIZE) +
|
|
1029
|
+
') scale(-1 1)');
|
|
1030
|
+
} else {
|
|
1031
|
+
this.resizeGroup_.setAttribute(
|
|
1032
|
+
'transform',
|
|
1033
|
+
'translate(' + (width - RESIZE_SIZE) + ',' +
|
|
1034
|
+
(height - RESIZE_SIZE) + ')');
|
|
1035
|
+
this.deleteGroup_.setAttribute(
|
|
1036
|
+
'transform',
|
|
1037
|
+
'translate(' + (width - RESIZE_SIZE) + ',' + (-RESIZE_SIZE) + ')');
|
|
1038
|
+
}
|
|
1073
1039
|
}
|
|
1074
1040
|
|
|
1075
|
-
|
|
1076
|
-
|
|
1077
|
-
dom.removeClass(comment.svgRectTarget_, 'blocklyCommentTargetFocused');
|
|
1078
|
-
dom.removeClass(
|
|
1079
|
-
comment.svgHandleTarget_, 'blocklyCommentHandleTargetFocused');
|
|
1080
|
-
}, 0);
|
|
1081
|
-
};
|
|
1082
|
-
|
|
1083
|
-
/**
|
|
1084
|
-
* CSS for workspace comment. See css.js for use.
|
|
1085
|
-
*/
|
|
1086
|
-
Css.register(`
|
|
1087
|
-
.blocklyCommentForeignObject {
|
|
1088
|
-
position: relative;
|
|
1089
|
-
z-index: 0;
|
|
1090
|
-
}
|
|
1091
|
-
|
|
1092
|
-
.blocklyCommentRect {
|
|
1093
|
-
fill: #E7DE8E;
|
|
1094
|
-
stroke: #bcA903;
|
|
1095
|
-
stroke-width: 1px;
|
|
1041
|
+
// Allow the contents to resize.
|
|
1042
|
+
this.resizeComment_();
|
|
1096
1043
|
}
|
|
1097
1044
|
|
|
1098
|
-
|
|
1099
|
-
|
|
1100
|
-
|
|
1045
|
+
/**
|
|
1046
|
+
* Dispose of any rendered comment components.
|
|
1047
|
+
* @private
|
|
1048
|
+
*/
|
|
1049
|
+
disposeInternal_() {
|
|
1050
|
+
this.textarea_ = null;
|
|
1051
|
+
this.foreignObject_ = null;
|
|
1052
|
+
this.svgRectTarget_ = null;
|
|
1053
|
+
this.svgHandleTarget_ = null;
|
|
1054
|
+
this.disposed_ = true;
|
|
1101
1055
|
}
|
|
1102
1056
|
|
|
1103
|
-
|
|
1104
|
-
|
|
1057
|
+
/**
|
|
1058
|
+
* Set the focus on the text area.
|
|
1059
|
+
* @package
|
|
1060
|
+
*/
|
|
1061
|
+
setFocus() {
|
|
1062
|
+
const comment = this;
|
|
1063
|
+
this.focused_ = true;
|
|
1064
|
+
// Defer CSS changes.
|
|
1065
|
+
setTimeout(function() {
|
|
1066
|
+
if (comment.disposed_) {
|
|
1067
|
+
return;
|
|
1068
|
+
}
|
|
1069
|
+
comment.textarea_.focus();
|
|
1070
|
+
comment.addFocus();
|
|
1071
|
+
dom.addClass(
|
|
1072
|
+
/** @type {!SVGRectElement} */ (comment.svgRectTarget_),
|
|
1073
|
+
'blocklyCommentTargetFocused');
|
|
1074
|
+
dom.addClass(
|
|
1075
|
+
/** @type {!SVGRectElement} */ (comment.svgHandleTarget_),
|
|
1076
|
+
'blocklyCommentHandleTargetFocused');
|
|
1077
|
+
}, 0);
|
|
1105
1078
|
}
|
|
1106
1079
|
|
|
1107
|
-
|
|
1108
|
-
|
|
1109
|
-
|
|
1080
|
+
/**
|
|
1081
|
+
* Remove focus from the text area.
|
|
1082
|
+
* @package
|
|
1083
|
+
*/
|
|
1084
|
+
blurFocus() {
|
|
1085
|
+
const comment = this;
|
|
1086
|
+
this.focused_ = false;
|
|
1087
|
+
// Defer CSS changes.
|
|
1088
|
+
setTimeout(function() {
|
|
1089
|
+
if (comment.disposed_) {
|
|
1090
|
+
return;
|
|
1091
|
+
}
|
|
1110
1092
|
|
|
1111
|
-
|
|
1112
|
-
|
|
1093
|
+
comment.textarea_.blur();
|
|
1094
|
+
comment.removeFocus();
|
|
1095
|
+
dom.removeClass(
|
|
1096
|
+
/** @type {!SVGRectElement} */ (comment.svgRectTarget_),
|
|
1097
|
+
'blocklyCommentTargetFocused');
|
|
1098
|
+
dom.removeClass(
|
|
1099
|
+
/** @type {!SVGRectElement} */ (comment.svgHandleTarget_),
|
|
1100
|
+
'blocklyCommentHandleTargetFocused');
|
|
1101
|
+
}, 0);
|
|
1113
1102
|
}
|
|
1114
1103
|
|
|
1115
|
-
|
|
1116
|
-
|
|
1117
|
-
|
|
1118
|
-
|
|
1104
|
+
/**
|
|
1105
|
+
* Decode an XML comment tag and create a rendered comment on the workspace.
|
|
1106
|
+
* @param {!Element} xmlComment XML comment element.
|
|
1107
|
+
* @param {!WorkspaceSvg} workspace The workspace.
|
|
1108
|
+
* @param {number=} opt_wsWidth The width of the workspace, which is used to
|
|
1109
|
+
* position comments correctly in RTL.
|
|
1110
|
+
* @return {!WorkspaceCommentSvg} The created workspace comment.
|
|
1111
|
+
* @package
|
|
1112
|
+
*/
|
|
1113
|
+
static fromXmlRendered(xmlComment, workspace, opt_wsWidth) {
|
|
1114
|
+
eventUtils.disable();
|
|
1115
|
+
let comment;
|
|
1116
|
+
try {
|
|
1117
|
+
const info = WorkspaceComment.parseAttributes(xmlComment);
|
|
1119
1118
|
|
|
1120
|
-
|
|
1121
|
-
|
|
1122
|
-
|
|
1123
|
-
|
|
1119
|
+
comment = new WorkspaceCommentSvg(
|
|
1120
|
+
workspace, info.content, info.h, info.w, info.id);
|
|
1121
|
+
if (workspace.rendered) {
|
|
1122
|
+
comment.initSvg(true);
|
|
1123
|
+
comment.render();
|
|
1124
|
+
}
|
|
1125
|
+
// Position the comment correctly, taking into account the width of a
|
|
1126
|
+
// rendered RTL workspace.
|
|
1127
|
+
if (!isNaN(info.x) && !isNaN(info.y)) {
|
|
1128
|
+
if (workspace.RTL) {
|
|
1129
|
+
const wsWidth = opt_wsWidth || workspace.getWidth();
|
|
1130
|
+
comment.moveBy(wsWidth - info.x, info.y);
|
|
1131
|
+
} else {
|
|
1132
|
+
comment.moveBy(info.x, info.y);
|
|
1133
|
+
}
|
|
1134
|
+
}
|
|
1135
|
+
} finally {
|
|
1136
|
+
eventUtils.enable();
|
|
1137
|
+
}
|
|
1124
1138
|
|
|
1125
|
-
|
|
1126
|
-
|
|
1127
|
-
|
|
1128
|
-
display: none;
|
|
1139
|
+
WorkspaceComment.fireCreateEvent(
|
|
1140
|
+
/** @type {!WorkspaceCommentSvg} */ (comment));
|
|
1141
|
+
return (/** @type {!WorkspaceCommentSvg} */ (comment));
|
|
1129
1142
|
}
|
|
1143
|
+
}
|
|
1130
1144
|
|
|
1131
|
-
|
|
1132
|
-
|
|
1133
|
-
|
|
1145
|
+
/**
|
|
1146
|
+
* The width and height to use to size a workspace comment when it is first
|
|
1147
|
+
* added, before it has been edited by the user.
|
|
1148
|
+
* @type {number}
|
|
1149
|
+
* @package
|
|
1150
|
+
*/
|
|
1151
|
+
WorkspaceCommentSvg.DEFAULT_SIZE = 100;
|
|
1134
1152
|
|
|
1135
|
-
|
|
1136
|
-
|
|
1137
|
-
|
|
1138
|
-
|
|
1139
|
-
|
|
1153
|
+
/**
|
|
1154
|
+
* Offset from the top to make room for a top bar.
|
|
1155
|
+
* @type {number}
|
|
1156
|
+
* @const
|
|
1157
|
+
* @private
|
|
1158
|
+
*/
|
|
1159
|
+
WorkspaceCommentSvg.TOP_OFFSET = 10;
|
|
1140
1160
|
|
|
1141
|
-
|
|
1142
|
-
|
|
1143
|
-
|
|
1161
|
+
/**
|
|
1162
|
+
* CSS for workspace comment. See css.js for use.
|
|
1163
|
+
*/
|
|
1164
|
+
Css.register(`
|
|
1165
|
+
.blocklyCommentForeignObject {
|
|
1166
|
+
position: relative;
|
|
1167
|
+
z-index: 0;
|
|
1168
|
+
}
|
|
1169
|
+
|
|
1170
|
+
.blocklyCommentRect {
|
|
1171
|
+
fill: #E7DE8E;
|
|
1172
|
+
stroke: #bcA903;
|
|
1173
|
+
stroke-width: 1px;
|
|
1174
|
+
}
|
|
1175
|
+
|
|
1176
|
+
.blocklyCommentTarget {
|
|
1177
|
+
fill: transparent;
|
|
1178
|
+
stroke: #bcA903;
|
|
1179
|
+
}
|
|
1180
|
+
|
|
1181
|
+
.blocklyCommentTargetFocused {
|
|
1182
|
+
fill: none;
|
|
1183
|
+
}
|
|
1184
|
+
|
|
1185
|
+
.blocklyCommentHandleTarget {
|
|
1186
|
+
fill: none;
|
|
1187
|
+
}
|
|
1188
|
+
|
|
1189
|
+
.blocklyCommentHandleTargetFocused {
|
|
1190
|
+
fill: transparent;
|
|
1191
|
+
}
|
|
1192
|
+
|
|
1193
|
+
.blocklyFocused>.blocklyCommentRect {
|
|
1194
|
+
fill: #B9B272;
|
|
1195
|
+
stroke: #B9B272;
|
|
1196
|
+
}
|
|
1197
|
+
|
|
1198
|
+
.blocklySelected>.blocklyCommentTarget {
|
|
1199
|
+
stroke: #fc3;
|
|
1200
|
+
stroke-width: 3px;
|
|
1201
|
+
}
|
|
1202
|
+
|
|
1203
|
+
.blocklyCommentDeleteIcon {
|
|
1204
|
+
cursor: pointer;
|
|
1205
|
+
fill: #000;
|
|
1206
|
+
display: none;
|
|
1207
|
+
}
|
|
1208
|
+
|
|
1209
|
+
.blocklySelected > .blocklyCommentDeleteIcon {
|
|
1210
|
+
display: block;
|
|
1211
|
+
}
|
|
1212
|
+
|
|
1213
|
+
.blocklyDeleteIconShape {
|
|
1214
|
+
fill: #000;
|
|
1215
|
+
stroke: #000;
|
|
1216
|
+
stroke-width: 1px;
|
|
1217
|
+
}
|
|
1218
|
+
|
|
1219
|
+
.blocklyDeleteIconShape.blocklyDeleteIconHighlighted {
|
|
1220
|
+
stroke: #fc3;
|
|
1221
|
+
}
|
|
1144
1222
|
`);
|
|
1145
1223
|
|
|
1146
1224
|
exports.WorkspaceCommentSvg = WorkspaceCommentSvg;
|