@blockdia/scratch-blocks 0.1.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/.nvmrc +1 -0
- package/LICENSE +674 -0
- package/README.md +57 -0
- package/TRADEMARK +1 -0
- package/blockly_compressed_horizontal.js +2268 -0
- package/blockly_compressed_vertical.js +2296 -0
- package/blockly_uncompressed_horizontal.js +1212 -0
- package/blockly_uncompressed_vertical.js +1212 -0
- package/blocks_common/colour.js +61 -0
- package/blocks_common/math.js +159 -0
- package/blocks_common/matrix.js +54 -0
- package/blocks_common/note.js +58 -0
- package/blocks_common/text.js +57 -0
- package/blocks_compressed.js +37 -0
- package/blocks_compressed_horizontal.js +68 -0
- package/blocks_compressed_vertical.js +216 -0
- package/blocks_horizontal/control.js +212 -0
- package/blocks_horizontal/default_toolbox.js +139 -0
- package/blocks_horizontal/event.js +190 -0
- package/blocks_horizontal/wedo.js +325 -0
- package/blocks_vertical/control.js +532 -0
- package/blocks_vertical/data.js +666 -0
- package/blocks_vertical/default_toolbox.js +571 -0
- package/blocks_vertical/event.js +329 -0
- package/blocks_vertical/extensions.js +294 -0
- package/blocks_vertical/looks.js +591 -0
- package/blocks_vertical/motion.js +587 -0
- package/blocks_vertical/operators.js +470 -0
- package/blocks_vertical/procedures.js +1051 -0
- package/blocks_vertical/sensing.js +555 -0
- package/blocks_vertical/sound.js +246 -0
- package/blocks_vertical/vertical_extensions.js +289 -0
- package/build/gen_blocks.js +1 -0
- package/build/test_expect.js +1 -0
- package/build/test_input.js +1 -0
- package/build.py +647 -0
- package/cleanup.sh +101 -0
- package/core/block.js +1837 -0
- package/core/block_animations.js +107 -0
- package/core/block_drag_surface.js +299 -0
- package/core/block_dragger.js +424 -0
- package/core/block_events.js +531 -0
- package/core/block_render_svg_horizontal.js +892 -0
- package/core/block_render_svg_vertical.js +1734 -0
- package/core/block_svg.js +1355 -0
- package/core/blockly.js +620 -0
- package/core/blocks.js +37 -0
- package/core/bubble.js +664 -0
- package/core/bubble_dragger.js +285 -0
- package/core/colours.js +177 -0
- package/core/comment.js +293 -0
- package/core/comment_events.js +539 -0
- package/core/connection.js +776 -0
- package/core/connection_db.js +300 -0
- package/core/constants.js +408 -0
- package/core/contextmenu.js +534 -0
- package/core/css.js +1354 -0
- package/core/data_category.js +490 -0
- package/core/dragged_connection_manager.js +260 -0
- package/core/dropdowndiv.js +408 -0
- package/core/events.js +429 -0
- package/core/events_abstract.js +113 -0
- package/core/extensions.js +450 -0
- package/core/field.js +810 -0
- package/core/field_angle.js +410 -0
- package/core/field_checkbox.js +133 -0
- package/core/field_colour.js +253 -0
- package/core/field_colour_slider.js +387 -0
- package/core/field_date.js +353 -0
- package/core/field_dropdown.js +447 -0
- package/core/field_iconmenu.js +309 -0
- package/core/field_image.js +200 -0
- package/core/field_label.js +136 -0
- package/core/field_label_serializable.js +125 -0
- package/core/field_matrix.js +566 -0
- package/core/field_note.js +850 -0
- package/core/field_number.js +366 -0
- package/core/field_numberdropdown.js +77 -0
- package/core/field_textdropdown.js +164 -0
- package/core/field_textinput.js +675 -0
- package/core/field_textinput_removable.js +105 -0
- package/core/field_variable.js +385 -0
- package/core/field_variable_getter.js +185 -0
- package/core/field_vertical_separator.js +161 -0
- package/core/flyout_base.js +935 -0
- package/core/flyout_button.js +324 -0
- package/core/flyout_dragger.js +83 -0
- package/core/flyout_extension_category_header.js +159 -0
- package/core/flyout_horizontal.js +475 -0
- package/core/flyout_vertical.js +770 -0
- package/core/generator.js +426 -0
- package/core/gesture.js +1010 -0
- package/core/grid.js +227 -0
- package/core/icon.js +205 -0
- package/core/inject.js +496 -0
- package/core/input.js +285 -0
- package/core/insertion_marker_manager.js +678 -0
- package/core/intersection_observer.js +102 -0
- package/core/msg.js +62 -0
- package/core/mutator.js +426 -0
- package/core/names.js +198 -0
- package/core/options.js +244 -0
- package/core/procedures.js +739 -0
- package/core/rendered_connection.js +417 -0
- package/core/scratch_block_comment.js +646 -0
- package/core/scratch_blocks_utils.js +246 -0
- package/core/scratch_bubble.js +699 -0
- package/core/scratch_events.js +131 -0
- package/core/scratch_msgs.js +85 -0
- package/core/scrollbar.js +875 -0
- package/core/toolbox.js +803 -0
- package/core/tooltip.js +337 -0
- package/core/touch.js +226 -0
- package/core/trashcan.js +343 -0
- package/core/ui_events.js +91 -0
- package/core/ui_menu_utils.js +68 -0
- package/core/utils.js +825 -0
- package/core/variable_events.js +259 -0
- package/core/variable_map.js +415 -0
- package/core/variable_model.js +116 -0
- package/core/variables.js +674 -0
- package/core/warning.js +199 -0
- package/core/widgetdiv.js +344 -0
- package/core/workspace.js +673 -0
- package/core/workspace_audio.js +170 -0
- package/core/workspace_comment.js +426 -0
- package/core/workspace_comment_render_svg.js +706 -0
- package/core/workspace_comment_svg.js +609 -0
- package/core/workspace_drag_surface_svg.js +195 -0
- package/core/workspace_dragger.js +132 -0
- package/core/workspace_svg.js +2382 -0
- package/core/xml.js +930 -0
- package/core/zoom_controls.js +301 -0
- package/dist/horizontal.js +222 -0
- package/dist/vertical.js +222 -0
- package/dist/web/horizontal.js +232 -0
- package/dist/web/vertical.js +232 -0
- package/i18n/common.py +234 -0
- package/i18n/create_messages.py +162 -0
- package/i18n/create_scratch_msgs.js +69 -0
- package/i18n/dedup_json.py +73 -0
- package/i18n/js_to_json.js +46 -0
- package/i18n/js_to_json.py +136 -0
- package/i18n/json_to_js.js +52 -0
- package/i18n/json_to_js.py +185 -0
- package/i18n/sync_tx_translations.js +111 -0
- package/i18n/test_scratch_msgs.js +87 -0
- package/i18n/tests.py +47 -0
- package/i18n/xliff_to_json.py +232 -0
- package/local_build.sh +70 -0
- package/media/click.mp3 +0 -0
- package/media/click.ogg +0 -0
- package/media/click.wav +0 -0
- package/media/comment-arrow-down.svg +10 -0
- package/media/comment-arrow-up.svg +10 -0
- package/media/delete-x.svg +10 -0
- package/media/delete.mp3 +0 -0
- package/media/delete.ogg +0 -0
- package/media/delete.wav +0 -0
- package/media/dropdown-arrow-dark.svg +1 -0
- package/media/dropdown-arrow.svg +1 -0
- package/media/extensions/microbit-block-icon.svg +130 -0
- package/media/extensions/music-block-icon.svg +17 -0
- package/media/extensions/pen-block-icon.svg +19 -0
- package/media/extensions/wedo2-block-icon.svg +36 -0
- package/media/eyedropper.svg +22 -0
- package/media/green-flag.svg +17 -0
- package/media/handclosed.cur +0 -0
- package/media/handdelete.cur +0 -0
- package/media/handopen.cur +0 -0
- package/media/icons/arrow.svg +12 -0
- package/media/icons/arrow_button.svg +1 -0
- package/media/icons/control_forever.svg +1 -0
- package/media/icons/control_repeat.svg +1 -0
- package/media/icons/control_stop.svg +1 -0
- package/media/icons/control_wait.svg +1 -0
- package/media/icons/event_broadcast_blue.svg +1 -0
- package/media/icons/event_broadcast_coral.svg +1 -0
- package/media/icons/event_broadcast_green.svg +1 -0
- package/media/icons/event_broadcast_magenta.svg +1 -0
- package/media/icons/event_broadcast_orange.svg +1 -0
- package/media/icons/event_broadcast_purple.svg +1 -0
- package/media/icons/event_when-broadcast-received_blue.svg +1 -0
- package/media/icons/event_when-broadcast-received_coral.svg +1 -0
- package/media/icons/event_when-broadcast-received_green.svg +1 -0
- package/media/icons/event_when-broadcast-received_magenta.svg +1 -0
- package/media/icons/event_when-broadcast-received_orange.svg +1 -0
- package/media/icons/event_when-broadcast-received_purple.svg +1 -0
- package/media/icons/event_whenflagclicked.svg +1 -0
- package/media/icons/remove.svg +19 -0
- package/media/icons/set-led_blue.svg +1 -0
- package/media/icons/set-led_coral.svg +1 -0
- package/media/icons/set-led_green.svg +1 -0
- package/media/icons/set-led_magenta.svg +1 -0
- package/media/icons/set-led_mystery.svg +1 -0
- package/media/icons/set-led_orange.svg +1 -0
- package/media/icons/set-led_purple.svg +1 -0
- package/media/icons/set-led_white.svg +1 -0
- package/media/icons/set-led_yellow.svg +1 -0
- package/media/icons/wedo_motor-clockwise.svg +1 -0
- package/media/icons/wedo_motor-counterclockwise.svg +1 -0
- package/media/icons/wedo_motor-speed_fast.svg +1 -0
- package/media/icons/wedo_motor-speed_med.svg +1 -0
- package/media/icons/wedo_motor-speed_slow.svg +1 -0
- package/media/icons/wedo_when-distance_close.svg +1 -0
- package/media/icons/wedo_when-tilt-backward.svg +1 -0
- package/media/icons/wedo_when-tilt-forward.svg +1 -0
- package/media/icons/wedo_when-tilt-left.svg +1 -0
- package/media/icons/wedo_when-tilt-right.svg +1 -0
- package/media/icons/wedo_when-tilt.svg +1 -0
- package/media/repeat.svg +18 -0
- package/media/rotate-left.svg +1 -0
- package/media/rotate-right.svg +1 -0
- package/media/sprites.png +0 -0
- package/media/status-not-ready.svg +13 -0
- package/media/status-ready.svg +13 -0
- package/media/zoom-in.svg +1 -0
- package/media/zoom-out.svg +1 -0
- package/media/zoom-reset.svg +1 -0
- package/msg/js/en.js +290 -0
- package/msg/json/en.json +285 -0
- package/msg/messages.js +359 -0
- package/msg/scratch_msgs.js +22969 -0
- package/package.json +60 -0
- package/pull_from_blockly.sh +151 -0
- package/renovate.json5 +15 -0
- package/shim/blockly_compressed_horizontal-blocks_compressed.js +1 -0
- package/shim/blockly_compressed_horizontal.Blockly.js +1 -0
- package/shim/blockly_compressed_horizontal.goog.js +1 -0
- package/shim/blockly_compressed_horizontal.js +1 -0
- package/shim/blockly_compressed_vertical-blocks_compressed.js +1 -0
- package/shim/blockly_compressed_vertical.Blockly.js +1 -0
- package/shim/blockly_compressed_vertical.goog.js +1 -0
- package/shim/blockly_compressed_vertical.js +1 -0
- package/shim/blocks_compressed_horizontal-blockly_compressed_horizontal-messages.js +1 -0
- package/shim/blocks_compressed_horizontal.js +1 -0
- package/shim/blocks_compressed_vertical-blockly_compressed_vertical-messages.js +1 -0
- package/shim/blocks_compressed_vertical.js +1 -0
- package/shim/gh-pages.js +1 -0
- package/shim/horizontal.js +1 -0
- package/shim/index.js +17 -0
- package/shim/vertical.js +1 -0
- package/universal-python.js +82 -0
|
@@ -0,0 +1,770 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @license
|
|
3
|
+
* Visual Blocks Editor
|
|
4
|
+
*
|
|
5
|
+
* Copyright 2017 Google Inc.
|
|
6
|
+
* https://developers.google.com/blockly/
|
|
7
|
+
*
|
|
8
|
+
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
9
|
+
* you may not use this file except in compliance with the License.
|
|
10
|
+
* You may obtain a copy of the License at
|
|
11
|
+
*
|
|
12
|
+
* http://www.apache.org/licenses/LICENSE-2.0
|
|
13
|
+
*
|
|
14
|
+
* Unless required by applicable law or agreed to in writing, software
|
|
15
|
+
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
16
|
+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
17
|
+
* See the License for the specific language governing permissions and
|
|
18
|
+
* limitations under the License.
|
|
19
|
+
*/
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* @fileoverview Layout code for a vertical variant of the flyout.
|
|
23
|
+
* @author fenichel@google.com (Rachel Fenichel)
|
|
24
|
+
*/
|
|
25
|
+
'use strict';
|
|
26
|
+
|
|
27
|
+
goog.provide('Blockly.VerticalFlyout');
|
|
28
|
+
|
|
29
|
+
goog.require('Blockly.Block');
|
|
30
|
+
goog.require('Blockly.Comment');
|
|
31
|
+
goog.require('Blockly.Events');
|
|
32
|
+
goog.require('Blockly.Flyout');
|
|
33
|
+
goog.require('Blockly.FlyoutButton');
|
|
34
|
+
goog.require('Blockly.utils');
|
|
35
|
+
goog.require('Blockly.WorkspaceSvg');
|
|
36
|
+
goog.require('goog.dom');
|
|
37
|
+
goog.require('goog.dom.animationFrame.polyfill');
|
|
38
|
+
goog.require('goog.events');
|
|
39
|
+
goog.require('goog.math.Rect');
|
|
40
|
+
goog.require('goog.userAgent');
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
/**
|
|
44
|
+
* Class for a flyout.
|
|
45
|
+
* @param {!Object} workspaceOptions Dictionary of options for the workspace.
|
|
46
|
+
* @extends {Blockly.Flyout}
|
|
47
|
+
* @constructor
|
|
48
|
+
*/
|
|
49
|
+
Blockly.VerticalFlyout = function(workspaceOptions) {
|
|
50
|
+
workspaceOptions.getMetrics = this.getMetrics_.bind(this);
|
|
51
|
+
workspaceOptions.setMetrics = this.setMetrics_.bind(this);
|
|
52
|
+
|
|
53
|
+
Blockly.VerticalFlyout.superClass_.constructor.call(this, workspaceOptions);
|
|
54
|
+
/**
|
|
55
|
+
* Flyout should be laid out vertically.
|
|
56
|
+
* @type {boolean}
|
|
57
|
+
* @private
|
|
58
|
+
*/
|
|
59
|
+
this.horizontalLayout_ = false;
|
|
60
|
+
|
|
61
|
+
/**
|
|
62
|
+
* Map of checkboxes that correspond to monitored blocks.
|
|
63
|
+
* Each element is an object containing the SVG for the checkbox, a boolean
|
|
64
|
+
* for its checked state, and the block the checkbox is associated with.
|
|
65
|
+
* @type {!Object.<string, !Object>}
|
|
66
|
+
* @private
|
|
67
|
+
*/
|
|
68
|
+
this.checkboxes_ = {};
|
|
69
|
+
};
|
|
70
|
+
goog.inherits(Blockly.VerticalFlyout, Blockly.Flyout);
|
|
71
|
+
|
|
72
|
+
/**
|
|
73
|
+
* Does the flyout automatically close when a block is created?
|
|
74
|
+
* @type {boolean}
|
|
75
|
+
*/
|
|
76
|
+
Blockly.VerticalFlyout.prototype.autoClose = false;
|
|
77
|
+
|
|
78
|
+
/**
|
|
79
|
+
* The width of the flyout, if not otherwise specified.
|
|
80
|
+
* @type {number}
|
|
81
|
+
*/
|
|
82
|
+
Blockly.VerticalFlyout.prototype.DEFAULT_WIDTH = 250;
|
|
83
|
+
|
|
84
|
+
/**
|
|
85
|
+
* Size of a checkbox next to a variable reporter.
|
|
86
|
+
* @type {number}
|
|
87
|
+
* @const
|
|
88
|
+
*/
|
|
89
|
+
Blockly.VerticalFlyout.prototype.CHECKBOX_SIZE = 25;
|
|
90
|
+
|
|
91
|
+
/**
|
|
92
|
+
* Amount of touchable padding around reporter checkboxes.
|
|
93
|
+
* @type {number}
|
|
94
|
+
* @const
|
|
95
|
+
*/
|
|
96
|
+
Blockly.VerticalFlyout.prototype.CHECKBOX_TOUCH_PADDING = 12;
|
|
97
|
+
|
|
98
|
+
/**
|
|
99
|
+
* SVG path data for checkmark in checkbox.
|
|
100
|
+
* @type {string}
|
|
101
|
+
* @const
|
|
102
|
+
*/
|
|
103
|
+
Blockly.VerticalFlyout.prototype.CHECKMARK_PATH =
|
|
104
|
+
'M' + Blockly.VerticalFlyout.prototype.CHECKBOX_SIZE / 4 +
|
|
105
|
+
' ' + Blockly.VerticalFlyout.prototype.CHECKBOX_SIZE / 2 +
|
|
106
|
+
'L' + 5 * Blockly.VerticalFlyout.prototype.CHECKBOX_SIZE / 12 +
|
|
107
|
+
' ' + 2 * Blockly.VerticalFlyout.prototype.CHECKBOX_SIZE / 3 +
|
|
108
|
+
'L' + 3 * Blockly.VerticalFlyout.prototype.CHECKBOX_SIZE / 4 +
|
|
109
|
+
' ' + Blockly.VerticalFlyout.prototype.CHECKBOX_SIZE / 3;
|
|
110
|
+
|
|
111
|
+
/**
|
|
112
|
+
* Size of the checkbox corner radius
|
|
113
|
+
* @type {number}
|
|
114
|
+
* @const
|
|
115
|
+
*/
|
|
116
|
+
Blockly.VerticalFlyout.prototype.CHECKBOX_CORNER_RADIUS = 5;
|
|
117
|
+
|
|
118
|
+
/**
|
|
119
|
+
* Space above and around the checkbox.
|
|
120
|
+
* @type {number}
|
|
121
|
+
* @const
|
|
122
|
+
*/
|
|
123
|
+
Blockly.VerticalFlyout.prototype.CHECKBOX_MARGIN = Blockly.Flyout.prototype.MARGIN;
|
|
124
|
+
|
|
125
|
+
/**
|
|
126
|
+
* Total additional width of a row that contains a checkbox.
|
|
127
|
+
* @type {number}
|
|
128
|
+
* @const
|
|
129
|
+
*/
|
|
130
|
+
Blockly.VerticalFlyout.prototype.CHECKBOX_SPACE_X =
|
|
131
|
+
Blockly.VerticalFlyout.prototype.CHECKBOX_SIZE +
|
|
132
|
+
2 * Blockly.VerticalFlyout.prototype.CHECKBOX_MARGIN;
|
|
133
|
+
|
|
134
|
+
/**
|
|
135
|
+
* Initializes the flyout.
|
|
136
|
+
* @param {!Blockly.Workspace} targetWorkspace The workspace in which to create
|
|
137
|
+
* new blocks.
|
|
138
|
+
*/
|
|
139
|
+
Blockly.VerticalFlyout.prototype.init = function(targetWorkspace) {
|
|
140
|
+
Blockly.VerticalFlyout.superClass_.init.call(this, targetWorkspace);
|
|
141
|
+
this.workspace_.scale = targetWorkspace.scale;
|
|
142
|
+
};
|
|
143
|
+
|
|
144
|
+
/**
|
|
145
|
+
* Creates the flyout's DOM. Only needs to be called once.
|
|
146
|
+
* @param {string} tagName HTML element
|
|
147
|
+
* @return {!Element} The flyout's SVG group.
|
|
148
|
+
*/
|
|
149
|
+
Blockly.VerticalFlyout.prototype.createDom = function(tagName) {
|
|
150
|
+
Blockly.VerticalFlyout.superClass_.createDom.call(this, tagName);
|
|
151
|
+
|
|
152
|
+
/*
|
|
153
|
+
<defs>
|
|
154
|
+
<clipPath id="blocklyBlockMenuClipPath">
|
|
155
|
+
<rect id="blocklyBlockMenuClipRect" height="1147px"
|
|
156
|
+
width="248px" y="0" x="0">
|
|
157
|
+
</rect>
|
|
158
|
+
</clipPath>
|
|
159
|
+
</defs>
|
|
160
|
+
*/
|
|
161
|
+
this.defs_ = Blockly.utils.createSvgElement('defs', {}, this.svgGroup_);
|
|
162
|
+
var clipPath = Blockly.utils.createSvgElement('clipPath',
|
|
163
|
+
{'id':'blocklyBlockMenuClipPath'}, this.defs_);
|
|
164
|
+
this.clipRect_ = Blockly.utils.createSvgElement('rect',
|
|
165
|
+
{
|
|
166
|
+
'id': 'blocklyBlockMenuClipRect',
|
|
167
|
+
'height': '0',
|
|
168
|
+
'width': '0',
|
|
169
|
+
'y': '0',
|
|
170
|
+
'x': '0'
|
|
171
|
+
},
|
|
172
|
+
clipPath);
|
|
173
|
+
this.workspace_.svgGroup_.setAttribute(
|
|
174
|
+
'clip-path', 'url(#blocklyBlockMenuClipPath)');
|
|
175
|
+
|
|
176
|
+
return this.svgGroup_;
|
|
177
|
+
};
|
|
178
|
+
|
|
179
|
+
/**
|
|
180
|
+
* Calculate the bounding box of the flyout.
|
|
181
|
+
*
|
|
182
|
+
* @return {Object} Contains the position and size of the bounding
|
|
183
|
+
* box containing the elements (blocks, buttons, labels) in the flyout.
|
|
184
|
+
*/
|
|
185
|
+
Blockly.VerticalFlyout.prototype.getContentBoundingBox_ = function() {
|
|
186
|
+
var contentBounds = this.workspace_.getBlocksBoundingBox();
|
|
187
|
+
var bounds = {
|
|
188
|
+
xMin: contentBounds.x,
|
|
189
|
+
yMin: contentBounds.y,
|
|
190
|
+
xMax: contentBounds.x + contentBounds.width,
|
|
191
|
+
yMax: contentBounds.y + contentBounds.height
|
|
192
|
+
};
|
|
193
|
+
|
|
194
|
+
// Check if any of the buttons/labels are outside the blocks bounding box.
|
|
195
|
+
for (var i = 0; i < this.buttons_.length; i ++) {
|
|
196
|
+
var button = this.buttons_[i];
|
|
197
|
+
var buttonPosition = button.getPosition();
|
|
198
|
+
if (buttonPosition.x < bounds.xMin) {
|
|
199
|
+
bounds.xMin = buttonPosition.x;
|
|
200
|
+
}
|
|
201
|
+
if (buttonPosition.y < bounds.yMin) {
|
|
202
|
+
bounds.yMin = buttonPosition.y;
|
|
203
|
+
}
|
|
204
|
+
// Button extends past the bounding box to the right.
|
|
205
|
+
if (buttonPosition.x + button.width > bounds.xMax) {
|
|
206
|
+
bounds.xMax = buttonPosition.x + button.width;
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
// Button extends past the bounding box on the bottom
|
|
210
|
+
if (buttonPosition.y + button.height > bounds.yMax) {
|
|
211
|
+
bounds.yMax = buttonPosition.y + button.height;
|
|
212
|
+
}
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
return {
|
|
216
|
+
x: bounds.xMin,
|
|
217
|
+
y: bounds.yMin,
|
|
218
|
+
width: bounds.xMax - bounds.xMin,
|
|
219
|
+
height: bounds.yMax - bounds.yMin,
|
|
220
|
+
};
|
|
221
|
+
};
|
|
222
|
+
|
|
223
|
+
/**
|
|
224
|
+
* Return an object with all the metrics required to size scrollbars for the
|
|
225
|
+
* flyout. The following properties are computed:
|
|
226
|
+
* .viewHeight: Height of the visible rectangle,
|
|
227
|
+
* .viewWidth: Width of the visible rectangle,
|
|
228
|
+
* .contentHeight: Height of the contents,
|
|
229
|
+
* .contentWidth: Width of the contents,
|
|
230
|
+
* .viewTop: Offset of top edge of visible rectangle from parent,
|
|
231
|
+
* .contentTop: Offset of the top-most content from the y=0 coordinate,
|
|
232
|
+
* .absoluteTop: Top-edge of view.
|
|
233
|
+
* .viewLeft: Offset of the left edge of visible rectangle from parent,
|
|
234
|
+
* .contentLeft: Offset of the left-most content from the x=0 coordinate,
|
|
235
|
+
* .absoluteLeft: Left-edge of view.
|
|
236
|
+
* @return {Object} Contains size and position metrics of the flyout.
|
|
237
|
+
* @private
|
|
238
|
+
*/
|
|
239
|
+
Blockly.VerticalFlyout.prototype.getMetrics_ = function() {
|
|
240
|
+
if (!this.isVisible()) {
|
|
241
|
+
// Flyout is hidden.
|
|
242
|
+
return null;
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
var optionBox = this.getContentBoundingBox_();
|
|
246
|
+
|
|
247
|
+
// Padding for the end of the scrollbar.
|
|
248
|
+
var absoluteTop = this.SCROLLBAR_PADDING;
|
|
249
|
+
var absoluteLeft = 0;
|
|
250
|
+
|
|
251
|
+
var viewHeight = this.height_ - 2 * this.SCROLLBAR_PADDING;
|
|
252
|
+
var viewWidth = this.getWidth() - this.SCROLLBAR_PADDING;
|
|
253
|
+
|
|
254
|
+
// Add padding to the bottom of the flyout, so we can scroll to the top of
|
|
255
|
+
// the last category.
|
|
256
|
+
var contentHeight = optionBox.height * this.workspace_.scale;
|
|
257
|
+
this.recordCategoryScrollPositions_();
|
|
258
|
+
var bottomPadding = this.MARGIN;
|
|
259
|
+
if (this.categoryScrollPositions.length > 0) {
|
|
260
|
+
var lastLabel = this.categoryScrollPositions[
|
|
261
|
+
this.categoryScrollPositions.length - 1];
|
|
262
|
+
var lastPos = lastLabel.position * this.workspace_.scale;
|
|
263
|
+
var lastCategoryHeight = contentHeight - lastPos;
|
|
264
|
+
if (lastCategoryHeight < viewHeight) {
|
|
265
|
+
bottomPadding = viewHeight - lastCategoryHeight;
|
|
266
|
+
}
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
var metrics = {
|
|
270
|
+
viewHeight: viewHeight,
|
|
271
|
+
viewWidth: viewWidth,
|
|
272
|
+
contentHeight: contentHeight + bottomPadding,
|
|
273
|
+
contentWidth: optionBox.width * this.workspace_.scale + 2 * this.MARGIN,
|
|
274
|
+
viewTop: -this.workspace_.scrollY + optionBox.y,
|
|
275
|
+
viewLeft: -this.workspace_.scrollX,
|
|
276
|
+
contentTop: optionBox.y,
|
|
277
|
+
contentLeft: optionBox.x,
|
|
278
|
+
absoluteTop: absoluteTop,
|
|
279
|
+
absoluteLeft: absoluteLeft
|
|
280
|
+
};
|
|
281
|
+
return metrics;
|
|
282
|
+
};
|
|
283
|
+
|
|
284
|
+
/**
|
|
285
|
+
* Sets the translation of the flyout to match the scrollbars.
|
|
286
|
+
* @param {!Object} xyRatio Contains a y property which is a float
|
|
287
|
+
* between 0 and 1 specifying the degree of scrolling and a
|
|
288
|
+
* similar x property.
|
|
289
|
+
* @private
|
|
290
|
+
*/
|
|
291
|
+
Blockly.VerticalFlyout.prototype.setMetrics_ = function(xyRatio) {
|
|
292
|
+
var metrics = this.getMetrics_();
|
|
293
|
+
// This is a fix to an apparent race condition.
|
|
294
|
+
if (!metrics) {
|
|
295
|
+
return;
|
|
296
|
+
}
|
|
297
|
+
if (goog.isNumber(xyRatio.y)) {
|
|
298
|
+
this.workspace_.scrollY = -metrics.contentHeight * xyRatio.y;
|
|
299
|
+
}
|
|
300
|
+
this.workspace_.translate(this.workspace_.scrollX + metrics.absoluteLeft,
|
|
301
|
+
this.workspace_.scrollY + metrics.absoluteTop);
|
|
302
|
+
|
|
303
|
+
this.clipRect_.setAttribute('height', Math.max(0, metrics.viewHeight) + 'px');
|
|
304
|
+
this.clipRect_.setAttribute('width', metrics.viewWidth + 'px');
|
|
305
|
+
|
|
306
|
+
if (this.categoryScrollPositions) {
|
|
307
|
+
this.selectCategoryByScrollPosition(-this.workspace_.scrollY);
|
|
308
|
+
}
|
|
309
|
+
};
|
|
310
|
+
|
|
311
|
+
/**
|
|
312
|
+
* Move the flyout to the edge of the workspace.
|
|
313
|
+
*/
|
|
314
|
+
Blockly.VerticalFlyout.prototype.position = function() {
|
|
315
|
+
if (!this.isVisible()) {
|
|
316
|
+
return;
|
|
317
|
+
}
|
|
318
|
+
var targetWorkspaceMetrics = this.targetWorkspace_.getMetrics();
|
|
319
|
+
if (!targetWorkspaceMetrics) {
|
|
320
|
+
// Hidden components will return null.
|
|
321
|
+
return;
|
|
322
|
+
}
|
|
323
|
+
|
|
324
|
+
// This version of the flyout does not change width to fit its contents.
|
|
325
|
+
// Instead it matches the width of its parent or uses a default value.
|
|
326
|
+
this.width_ = this.getWidth();
|
|
327
|
+
|
|
328
|
+
if (this.parentToolbox_) {
|
|
329
|
+
var toolboxWidth = this.parentToolbox_.getWidth();
|
|
330
|
+
var categoryWidth = toolboxWidth - this.width_;
|
|
331
|
+
var x = this.toolboxPosition_ == Blockly.TOOLBOX_AT_RIGHT ?
|
|
332
|
+
targetWorkspaceMetrics.viewWidth : categoryWidth;
|
|
333
|
+
var y = 0;
|
|
334
|
+
} else {
|
|
335
|
+
var x = this.toolboxPosition_ == Blockly.TOOLBOX_AT_RIGHT ?
|
|
336
|
+
targetWorkspaceMetrics.viewWidth - this.width_ : 0;
|
|
337
|
+
var y = 0;
|
|
338
|
+
}
|
|
339
|
+
|
|
340
|
+
// Record the height for Blockly.Flyout.getMetrics_
|
|
341
|
+
this.height_ = Math.max(0, targetWorkspaceMetrics.viewHeight - y);
|
|
342
|
+
|
|
343
|
+
this.setBackgroundPath_(this.width_, this.height_);
|
|
344
|
+
|
|
345
|
+
this.svgGroup_.setAttribute("width", this.width_);
|
|
346
|
+
this.svgGroup_.setAttribute("height", this.height_);
|
|
347
|
+
var transform = 'translate(' + x + 'px,' + y + 'px)';
|
|
348
|
+
Blockly.utils.setCssTransform(this.svgGroup_, transform);
|
|
349
|
+
|
|
350
|
+
// Update the scrollbar (if one exists).
|
|
351
|
+
if (this.scrollbar_) {
|
|
352
|
+
// Set the scrollbars origin to be the top left of the flyout.
|
|
353
|
+
this.scrollbar_.setOrigin(x, y);
|
|
354
|
+
this.scrollbar_.resize();
|
|
355
|
+
}
|
|
356
|
+
// The blocks need to be visible in order to be laid out and measured
|
|
357
|
+
// correctly, but we don't want the flyout to show up until it's properly
|
|
358
|
+
// sized. Opacity is set to zero in show().
|
|
359
|
+
this.svgGroup_.style.opacity = 1;
|
|
360
|
+
};
|
|
361
|
+
|
|
362
|
+
/**
|
|
363
|
+
* Create and set the path for the visible boundaries of the flyout.
|
|
364
|
+
* @param {number} width The width of the flyout, not including the
|
|
365
|
+
* rounded corners.
|
|
366
|
+
* @param {number} height The height of the flyout, not including
|
|
367
|
+
* rounded corners.
|
|
368
|
+
* @private
|
|
369
|
+
*/
|
|
370
|
+
Blockly.VerticalFlyout.prototype.setBackgroundPath_ = function(width, height) {
|
|
371
|
+
var atRight = this.toolboxPosition_ == Blockly.TOOLBOX_AT_RIGHT;
|
|
372
|
+
// Decide whether to start on the left or right.
|
|
373
|
+
var path = ['M ' + 0 + ',0'];
|
|
374
|
+
// Top.
|
|
375
|
+
path.push('h', width);
|
|
376
|
+
// Rounded corner.
|
|
377
|
+
path.push('a', this.CORNER_RADIUS, this.CORNER_RADIUS, 0, 0,
|
|
378
|
+
atRight ? 0 : 1,
|
|
379
|
+
atRight ? -this.CORNER_RADIUS : this.CORNER_RADIUS,
|
|
380
|
+
this.CORNER_RADIUS);
|
|
381
|
+
// Side closest to workspace.
|
|
382
|
+
path.push('v', Math.max(0, height - this.CORNER_RADIUS * 2));
|
|
383
|
+
// Rounded corner.
|
|
384
|
+
path.push('a', this.CORNER_RADIUS, this.CORNER_RADIUS, 0, 0,
|
|
385
|
+
atRight ? 0 : 1,
|
|
386
|
+
atRight ? this.CORNER_RADIUS : -this.CORNER_RADIUS,
|
|
387
|
+
this.CORNER_RADIUS);
|
|
388
|
+
// Bottom.
|
|
389
|
+
path.push('h', -width);
|
|
390
|
+
path.push('z');
|
|
391
|
+
this.svgBackground_.setAttribute('d', path.join(' '));
|
|
392
|
+
};
|
|
393
|
+
|
|
394
|
+
/**
|
|
395
|
+
* Scroll the flyout to the top.
|
|
396
|
+
*/
|
|
397
|
+
Blockly.VerticalFlyout.prototype.scrollToStart = function() {
|
|
398
|
+
this.scrollbar_.set(0);
|
|
399
|
+
};
|
|
400
|
+
|
|
401
|
+
/**
|
|
402
|
+
* Scroll the flyout to a position.
|
|
403
|
+
* @param {number} pos The targeted scroll position in workspace coordinates.
|
|
404
|
+
* @package
|
|
405
|
+
*/
|
|
406
|
+
Blockly.VerticalFlyout.prototype.scrollTo = function(pos) {
|
|
407
|
+
this.scrollTarget = pos * this.workspace_.scale;
|
|
408
|
+
|
|
409
|
+
// Make sure not to set the scroll target below the lowest point we can
|
|
410
|
+
// scroll to, i.e. the content height minus the view height
|
|
411
|
+
var metrics = this.workspace_.getMetrics();
|
|
412
|
+
var contentHeight = metrics.contentHeight;
|
|
413
|
+
var viewHeight = metrics.viewHeight;
|
|
414
|
+
this.scrollTarget = Math.min(this.scrollTarget, contentHeight - viewHeight);
|
|
415
|
+
|
|
416
|
+
this.startScrollAnimation();
|
|
417
|
+
};
|
|
418
|
+
|
|
419
|
+
/**
|
|
420
|
+
* Scroll the flyout.
|
|
421
|
+
* @param {!Event} e Mouse wheel scroll event.
|
|
422
|
+
* @private
|
|
423
|
+
*/
|
|
424
|
+
Blockly.VerticalFlyout.prototype.wheel_ = function(e) {
|
|
425
|
+
// remove scrollTarget to stop auto scrolling in stepScrollAnimation
|
|
426
|
+
this.scrollTarget = null;
|
|
427
|
+
|
|
428
|
+
var delta = e.deltaY;
|
|
429
|
+
|
|
430
|
+
if (delta) {
|
|
431
|
+
// Firefox's mouse wheel deltas are a tenth that of Chrome/Safari.
|
|
432
|
+
// DeltaMode is 1 for a mouse wheel, but not for a trackpad scroll event
|
|
433
|
+
if (goog.userAgent.GECKO && (e.deltaMode === 1)) {
|
|
434
|
+
delta *= 10;
|
|
435
|
+
}
|
|
436
|
+
var metrics = this.getMetrics_();
|
|
437
|
+
var pos = (metrics.viewTop - metrics.contentTop) + delta;
|
|
438
|
+
var limit = metrics.contentHeight - metrics.viewHeight;
|
|
439
|
+
pos = Math.min(pos, limit);
|
|
440
|
+
pos = Math.max(pos, 0);
|
|
441
|
+
this.scrollbar_.set(pos);
|
|
442
|
+
// When the flyout moves from a wheel event, hide WidgetDiv and DropDownDiv.
|
|
443
|
+
Blockly.WidgetDiv.hide(true);
|
|
444
|
+
Blockly.DropDownDiv.hideWithoutAnimation();
|
|
445
|
+
}
|
|
446
|
+
|
|
447
|
+
// Don't scroll the page.
|
|
448
|
+
e.preventDefault();
|
|
449
|
+
// Don't propagate mousewheel event (zooming).
|
|
450
|
+
e.stopPropagation();
|
|
451
|
+
};
|
|
452
|
+
|
|
453
|
+
/**
|
|
454
|
+
* Delete blocks and background buttons from a previous showing of the flyout.
|
|
455
|
+
* @private
|
|
456
|
+
*/
|
|
457
|
+
Blockly.VerticalFlyout.prototype.clearOldBlocks_ = function() {
|
|
458
|
+
Blockly.VerticalFlyout.superClass_.clearOldBlocks_.call(this);
|
|
459
|
+
|
|
460
|
+
// Do the same for checkboxes.
|
|
461
|
+
for (var checkboxId in this.checkboxes_) {
|
|
462
|
+
if (!Object.prototype.hasOwnProperty.call(this.checkboxes_, checkboxId)) {
|
|
463
|
+
continue;
|
|
464
|
+
}
|
|
465
|
+
var checkbox = this.checkboxes_[checkboxId];
|
|
466
|
+
checkbox.block.flyoutCheckbox = null;
|
|
467
|
+
goog.dom.removeNode(checkbox.svgRoot);
|
|
468
|
+
}
|
|
469
|
+
this.checkboxes_ = {};
|
|
470
|
+
};
|
|
471
|
+
|
|
472
|
+
/**
|
|
473
|
+
* Add listeners to a block that has been added to the flyout.
|
|
474
|
+
* @param {Element} root The root node of the SVG group the block is in.
|
|
475
|
+
* @param {!Blockly.Block} block The block to add listeners for.
|
|
476
|
+
* @param {!Element} rect The invisible rectangle under the block that acts as
|
|
477
|
+
* a button for that block.
|
|
478
|
+
* @private
|
|
479
|
+
*/
|
|
480
|
+
Blockly.VerticalFlyout.prototype.addBlockListeners_ = function(root, block,
|
|
481
|
+
rect) {
|
|
482
|
+
Blockly.VerticalFlyout.superClass_.addBlockListeners_.call(this, root, block,
|
|
483
|
+
rect);
|
|
484
|
+
if (block.flyoutCheckbox) {
|
|
485
|
+
this.listeners_.push(Blockly.bindEvent_(block.flyoutCheckbox.svgRoot,
|
|
486
|
+
'mousedown', null, this.checkboxClicked_(block.flyoutCheckbox)));
|
|
487
|
+
}
|
|
488
|
+
};
|
|
489
|
+
|
|
490
|
+
/**
|
|
491
|
+
* Lay out the blocks in the flyout.
|
|
492
|
+
* @param {!Array.<!Object>} contents The blocks and buttons to lay out.
|
|
493
|
+
* @param {!Array.<number>} gaps The visible gaps between blocks.
|
|
494
|
+
* @private
|
|
495
|
+
*/
|
|
496
|
+
Blockly.VerticalFlyout.prototype.layout_ = function(contents, gaps) {
|
|
497
|
+
var margin = this.MARGIN;
|
|
498
|
+
var flyoutWidth = this.getWidth() / this.workspace_.scale;
|
|
499
|
+
var cursorX = margin;
|
|
500
|
+
var cursorY = margin;
|
|
501
|
+
|
|
502
|
+
for (var i = 0, item; item = contents[i]; i++) {
|
|
503
|
+
if (item.type == 'block') {
|
|
504
|
+
var block = item.block;
|
|
505
|
+
var allBlocks = block.getDescendants(false);
|
|
506
|
+
for (var j = 0, child; child = allBlocks[j]; j++) {
|
|
507
|
+
// Mark blocks as being inside a flyout. This is used to detect and
|
|
508
|
+
// prevent the closure of the flyout if the user right-clicks on such a
|
|
509
|
+
// block.
|
|
510
|
+
child.isInFlyout = true;
|
|
511
|
+
}
|
|
512
|
+
var root = block.getSvgRoot();
|
|
513
|
+
var blockHW = block.getHeightWidth();
|
|
514
|
+
|
|
515
|
+
// Figure out where the block goes, taking into account its size, whether
|
|
516
|
+
// we're in RTL mode, and whether it has a checkbox.
|
|
517
|
+
var oldX = block.getRelativeToSurfaceXY().x;
|
|
518
|
+
var newX = flyoutWidth - this.MARGIN;
|
|
519
|
+
|
|
520
|
+
var moveX = this.RTL ? newX - oldX : margin;
|
|
521
|
+
if (block.hasCheckboxInFlyout()) {
|
|
522
|
+
this.createCheckbox_(block, cursorX, cursorY, blockHW);
|
|
523
|
+
if (this.RTL) {
|
|
524
|
+
moveX -= (this.CHECKBOX_SIZE + this.CHECKBOX_MARGIN);
|
|
525
|
+
} else {
|
|
526
|
+
moveX += this.CHECKBOX_SIZE + this.CHECKBOX_MARGIN;
|
|
527
|
+
}
|
|
528
|
+
}
|
|
529
|
+
|
|
530
|
+
// The block moves a bit extra for the hat, but the block's rectangle
|
|
531
|
+
// doesn't. That's because the hat actually extends up from 0.
|
|
532
|
+
block.moveBy(moveX,
|
|
533
|
+
cursorY + (block.startHat_ ? Blockly.BlockSvg.START_HAT_HEIGHT : 0));
|
|
534
|
+
|
|
535
|
+
var rect = this.createRect_(block, this.RTL ? moveX - blockHW.width : moveX, cursorY, blockHW, i);
|
|
536
|
+
|
|
537
|
+
this.addBlockListeners_(root, block, rect);
|
|
538
|
+
|
|
539
|
+
cursorY += blockHW.height + gaps[i] + (block.startHat_ ? Blockly.BlockSvg.START_HAT_HEIGHT : 0);
|
|
540
|
+
} else if (item.type == 'button') {
|
|
541
|
+
var button = item.button;
|
|
542
|
+
var buttonSvg = button.createDom();
|
|
543
|
+
if (this.RTL) {
|
|
544
|
+
button.moveTo(flyoutWidth - this.MARGIN - button.width, cursorY);
|
|
545
|
+
} else {
|
|
546
|
+
button.moveTo(cursorX, cursorY);
|
|
547
|
+
}
|
|
548
|
+
button.show();
|
|
549
|
+
// Clicking on a flyout button or label is a lot like clicking on the
|
|
550
|
+
// flyout background.
|
|
551
|
+
this.listeners_.push(Blockly.bindEventWithChecks_(
|
|
552
|
+
buttonSvg, 'mousedown', this, this.onMouseDown_));
|
|
553
|
+
|
|
554
|
+
this.buttons_.push(button);
|
|
555
|
+
cursorY += button.height + gaps[i];
|
|
556
|
+
}
|
|
557
|
+
}
|
|
558
|
+
};
|
|
559
|
+
|
|
560
|
+
/**
|
|
561
|
+
* Create and place a rectangle corresponding to the given block.
|
|
562
|
+
* @param {!Blockly.Block} block The block to associate the rect to.
|
|
563
|
+
* @param {number} x The x position of the cursor during this layout pass.
|
|
564
|
+
* @param {number} y The y position of the cursor during this layout pass.
|
|
565
|
+
* @param {!{height: number, width: number}} blockHW The height and width of the
|
|
566
|
+
* block.
|
|
567
|
+
* @param {number} index The index into the background buttons list where this
|
|
568
|
+
* rect should be placed.
|
|
569
|
+
* @return {!SVGElement} Newly created SVG element for the rectangle behind the
|
|
570
|
+
* block.
|
|
571
|
+
* @private
|
|
572
|
+
*/
|
|
573
|
+
Blockly.VerticalFlyout.prototype.createRect_ = function(block, x, y,
|
|
574
|
+
blockHW, index) {
|
|
575
|
+
// Create an invisible rectangle under the block to act as a button. Just
|
|
576
|
+
// using the block as a button is poor, since blocks have holes in them.
|
|
577
|
+
var rect = Blockly.utils.createSvgElement('rect',
|
|
578
|
+
{
|
|
579
|
+
'fill-opacity': 0,
|
|
580
|
+
'x': x,
|
|
581
|
+
'y': y,
|
|
582
|
+
'height': blockHW.height,
|
|
583
|
+
'width': blockHW.width
|
|
584
|
+
}, null);
|
|
585
|
+
rect.tooltip = block;
|
|
586
|
+
Blockly.Tooltip.bindMouseEvents(rect);
|
|
587
|
+
// Add the rectangles under the blocks, so that the blocks' tooltips work.
|
|
588
|
+
this.workspace_.getCanvas().insertBefore(rect, block.getSvgRoot());
|
|
589
|
+
|
|
590
|
+
block.flyoutRect_ = rect;
|
|
591
|
+
this.backgroundButtons_[index] = rect;
|
|
592
|
+
return rect;
|
|
593
|
+
};
|
|
594
|
+
|
|
595
|
+
/**
|
|
596
|
+
* Create and place a checkbox corresponding to the given block.
|
|
597
|
+
* @param {!Blockly.Block} block The block to associate the checkbox to.
|
|
598
|
+
* @param {number} cursorX The x position of the cursor during this layout pass.
|
|
599
|
+
* @param {number} cursorY The y position of the cursor during this layout pass.
|
|
600
|
+
* @param {!{height: number, width: number}} blockHW The height and width of the
|
|
601
|
+
* block.
|
|
602
|
+
* @private
|
|
603
|
+
*/
|
|
604
|
+
Blockly.VerticalFlyout.prototype.createCheckbox_ = function(block, cursorX,
|
|
605
|
+
cursorY, blockHW) {
|
|
606
|
+
var checkboxState = Blockly.VerticalFlyout.getCheckboxState(block.id);
|
|
607
|
+
var svgRoot = block.getSvgRoot();
|
|
608
|
+
var extraSpace = this.CHECKBOX_SIZE + this.CHECKBOX_MARGIN;
|
|
609
|
+
var width = this.RTL ? this.getWidth() / this.workspace_.scale - extraSpace : cursorX;
|
|
610
|
+
var height = cursorY + blockHW.height / 2 - this.CHECKBOX_SIZE / 2;
|
|
611
|
+
var touchMargin = this.CHECKBOX_TOUCH_PADDING;
|
|
612
|
+
var checkboxGroup = Blockly.utils.createSvgElement('g',
|
|
613
|
+
{
|
|
614
|
+
'transform': 'translate(' + width + ', ' + height + ')'
|
|
615
|
+
}, null);
|
|
616
|
+
Blockly.utils.createSvgElement('rect',
|
|
617
|
+
{
|
|
618
|
+
'class': 'blocklyFlyoutCheckbox',
|
|
619
|
+
'height': this.CHECKBOX_SIZE,
|
|
620
|
+
'width': this.CHECKBOX_SIZE,
|
|
621
|
+
'rx': this.CHECKBOX_CORNER_RADIUS,
|
|
622
|
+
'ry': this.CHECKBOX_CORNER_RADIUS
|
|
623
|
+
}, checkboxGroup);
|
|
624
|
+
Blockly.utils.createSvgElement('path',
|
|
625
|
+
{
|
|
626
|
+
'class': 'blocklyFlyoutCheckboxPath',
|
|
627
|
+
'd': this.CHECKMARK_PATH
|
|
628
|
+
}, checkboxGroup);
|
|
629
|
+
Blockly.utils.createSvgElement('rect',
|
|
630
|
+
{
|
|
631
|
+
'class': 'blocklyTouchTargetBackground',
|
|
632
|
+
'x': -touchMargin + 'px',
|
|
633
|
+
'y': -touchMargin + 'px',
|
|
634
|
+
'height': this.CHECKBOX_SIZE + 2 * touchMargin,
|
|
635
|
+
'width': this.CHECKBOX_SIZE + 2 * touchMargin,
|
|
636
|
+
}, checkboxGroup);
|
|
637
|
+
var checkboxObj = {svgRoot: checkboxGroup, clicked: checkboxState, block: block};
|
|
638
|
+
|
|
639
|
+
if (checkboxState) {
|
|
640
|
+
Blockly.utils.addClass((checkboxObj.svgRoot), 'checked');
|
|
641
|
+
}
|
|
642
|
+
|
|
643
|
+
block.flyoutCheckbox = checkboxObj;
|
|
644
|
+
this.workspace_.getCanvas().insertBefore(checkboxGroup, svgRoot);
|
|
645
|
+
this.checkboxes_[block.id] = checkboxObj;
|
|
646
|
+
};
|
|
647
|
+
|
|
648
|
+
/**
|
|
649
|
+
* Respond to a click on a checkbox in the flyout.
|
|
650
|
+
* @param {!Object} checkboxObj An object containing the svg element of the
|
|
651
|
+
* checkbox, a boolean for the state of the checkbox, and the block the
|
|
652
|
+
* checkbox is associated with.
|
|
653
|
+
* @return {!Function} Function to call when checkbox is clicked.
|
|
654
|
+
* @private
|
|
655
|
+
*/
|
|
656
|
+
Blockly.VerticalFlyout.prototype.checkboxClicked_ = function(checkboxObj) {
|
|
657
|
+
return function(e) {
|
|
658
|
+
this.setCheckboxState(checkboxObj.block.id, !checkboxObj.clicked);
|
|
659
|
+
// This event has been handled. No need to bubble up to the document.
|
|
660
|
+
e.stopPropagation();
|
|
661
|
+
e.preventDefault();
|
|
662
|
+
}.bind(this);
|
|
663
|
+
};
|
|
664
|
+
|
|
665
|
+
/**
|
|
666
|
+
* Set the state of a checkbox by block ID.
|
|
667
|
+
* @param {string} blockId ID of the block whose checkbox should be set
|
|
668
|
+
* @param {boolean} value Value to set the checkbox to.
|
|
669
|
+
* @public
|
|
670
|
+
*/
|
|
671
|
+
Blockly.VerticalFlyout.prototype.setCheckboxState = function(blockId, value) {
|
|
672
|
+
var checkboxObj = this.checkboxes_[blockId];
|
|
673
|
+
if (!checkboxObj || checkboxObj.clicked === value) {
|
|
674
|
+
return;
|
|
675
|
+
}
|
|
676
|
+
|
|
677
|
+
var oldValue = checkboxObj.clicked;
|
|
678
|
+
checkboxObj.clicked = value;
|
|
679
|
+
|
|
680
|
+
if (checkboxObj.clicked) {
|
|
681
|
+
Blockly.utils.addClass(checkboxObj.svgRoot, 'checked');
|
|
682
|
+
} else {
|
|
683
|
+
Blockly.utils.removeClass(checkboxObj.svgRoot, 'checked');
|
|
684
|
+
}
|
|
685
|
+
|
|
686
|
+
Blockly.Events.fire(new Blockly.Events.Change(
|
|
687
|
+
checkboxObj.block, 'checkbox', null, oldValue, value));
|
|
688
|
+
};
|
|
689
|
+
|
|
690
|
+
/**
|
|
691
|
+
* Determine if a drag delta is toward the workspace, based on the position
|
|
692
|
+
* and orientation of the flyout. This to decide if a new block should be
|
|
693
|
+
* created or if the flyout should scroll.
|
|
694
|
+
* @param {!goog.math.Coordinate} currentDragDeltaXY How far the pointer has
|
|
695
|
+
* moved from the position at mouse down, in pixel units.
|
|
696
|
+
* @return {boolean} true if the drag is toward the workspace.
|
|
697
|
+
* @package
|
|
698
|
+
*/
|
|
699
|
+
Blockly.VerticalFlyout.prototype.isDragTowardWorkspace = function(currentDragDeltaXY) {
|
|
700
|
+
var dx = currentDragDeltaXY.x;
|
|
701
|
+
var dy = currentDragDeltaXY.y;
|
|
702
|
+
// Direction goes from -180 to 180, with 0 toward the right and 90 on top.
|
|
703
|
+
var dragDirection = Math.atan2(dy, dx) / Math.PI * 180;
|
|
704
|
+
|
|
705
|
+
var draggingTowardWorkspace = false;
|
|
706
|
+
var range = this.dragAngleRange_;
|
|
707
|
+
if (this.toolboxPosition_ == Blockly.TOOLBOX_AT_LEFT) {
|
|
708
|
+
// Vertical at left.
|
|
709
|
+
if (dragDirection < range && dragDirection > -range) {
|
|
710
|
+
draggingTowardWorkspace = true;
|
|
711
|
+
}
|
|
712
|
+
} else {
|
|
713
|
+
// Vertical at right.
|
|
714
|
+
if (dragDirection < -180 + range || dragDirection > 180 - range) {
|
|
715
|
+
draggingTowardWorkspace = true;
|
|
716
|
+
}
|
|
717
|
+
}
|
|
718
|
+
return draggingTowardWorkspace;
|
|
719
|
+
};
|
|
720
|
+
|
|
721
|
+
/**
|
|
722
|
+
* Return the deletion rectangle for this flyout in viewport coordinates.
|
|
723
|
+
* Deletion area is the height of the flyout, but extends to the left (in LTR)
|
|
724
|
+
* by a lot in order to allow for deleting blocks when dragged beyond the left
|
|
725
|
+
* window edge. In RTL, the delete area extends off to the right.
|
|
726
|
+
* The top/bottom do not extend to allow dragging blocks outside of the workspace
|
|
727
|
+
* to be dropped (e.g. to the backpack).
|
|
728
|
+
* @return {goog.math.Rect} Rectangle in which to delete.
|
|
729
|
+
*/
|
|
730
|
+
Blockly.VerticalFlyout.prototype.getClientRect = function() {
|
|
731
|
+
if (!this.svgGroup_) {
|
|
732
|
+
return null;
|
|
733
|
+
}
|
|
734
|
+
|
|
735
|
+
var flyoutRect = this.svgGroup_.getBoundingClientRect();
|
|
736
|
+
// BIG_NUM is offscreen padding so that blocks dragged beyond the shown flyout
|
|
737
|
+
// area are still deleted. Must be larger than the largest screen size,
|
|
738
|
+
// but be smaller than half Number.MAX_SAFE_INTEGER (not available on IE).
|
|
739
|
+
var BIG_NUM = 1000000000;
|
|
740
|
+
var x = flyoutRect.left;
|
|
741
|
+
var y = flyoutRect.top;
|
|
742
|
+
var width = flyoutRect.width;
|
|
743
|
+
var height = flyoutRect.height;
|
|
744
|
+
|
|
745
|
+
if (this.toolboxPosition_ == Blockly.TOOLBOX_AT_LEFT) {
|
|
746
|
+
return new goog.math.Rect(x - BIG_NUM, y, BIG_NUM + width, height);
|
|
747
|
+
} else { // Right
|
|
748
|
+
return new goog.math.Rect(x, y, BIG_NUM + width, height);
|
|
749
|
+
}
|
|
750
|
+
};
|
|
751
|
+
|
|
752
|
+
/**
|
|
753
|
+
* Compute width of flyout. Position button under each block.
|
|
754
|
+
* For RTL: Lay out the blocks right-aligned.
|
|
755
|
+
* @param {!Array<!Blockly.Block>} blocks The blocks to reflow.
|
|
756
|
+
*/
|
|
757
|
+
Blockly.VerticalFlyout.prototype.reflowInternal_ = function(/* blocks */) {
|
|
758
|
+
// This is a no-op because the flyout is a fixed size.
|
|
759
|
+
return;
|
|
760
|
+
};
|
|
761
|
+
|
|
762
|
+
/**
|
|
763
|
+
* Gets the checkbox state for a block
|
|
764
|
+
* @param {string} blockId The ID of the block in question.
|
|
765
|
+
* @return {boolean} Whether the block is checked.
|
|
766
|
+
* @public
|
|
767
|
+
*/
|
|
768
|
+
Blockly.VerticalFlyout.getCheckboxState = function(/* blockId */) {
|
|
769
|
+
return false;
|
|
770
|
+
};
|