Merge pull request #4735 from google/rc_2021_3

Rc 2021 3
This commit is contained in:
Maribeth Bottorff
2021-03-25 10:04:06 -07:00
committed by GitHub
258 changed files with 10592 additions and 8382 deletions

3
.clang-format Normal file
View File

@@ -0,0 +1,3 @@
Language: JavaScript
BasedOnStyle: Google
ColumnLimit: 80

View File

@@ -3,7 +3,7 @@
name: Node.js CI
on: push
on: [pull_request]
jobs:
build:

View File

@@ -2,14 +2,12 @@
.*
*.soy
*.komodoproject
/deploy
deploy
/static/appengine/
/static/closure/
/static/demos/plane/soy/*.jar
/static/demos/plane/xlf/
/static/externs/
/static/msg/json/
/static/node_modules/
/static/scripts/
/static/typings/

View File

@@ -1,16 +0,0 @@
#!/bin/bash
# Script to deploy on GAE.
APP=./app.yaml
if ! [ -f $APP ] ; then
echo $APP not found 1>&2
exit 1
fi
PROJECT=blockly-demo
VERSION=37
echo 'Beginning deployment...'
gcloud app deploy --project $PROJECT --version $VERSION --no-promote
echo 'Deployment finished.'

File diff suppressed because it is too large Load Diff

File diff suppressed because one or more lines are too long

View File

@@ -21,26 +21,28 @@ this.BLOCKLY_DIR = (function(root) {
this.BLOCKLY_BOOT = function(root) {
// Execute after Closure has loaded.
goog.addDependency('../../core/block.js', ['Blockly.Block'], ['Blockly.ASTNode', 'Blockly.Blocks', 'Blockly.Connection', 'Blockly.Events', 'Blockly.Events.BlockChange', 'Blockly.Events.BlockCreate', 'Blockly.Events.BlockDelete', 'Blockly.Events.BlockMove', 'Blockly.Extensions', 'Blockly.Input', 'Blockly.Tooltip', 'Blockly.Workspace', 'Blockly.constants', 'Blockly.fieldRegistry', 'Blockly.navigation', 'Blockly.utils', 'Blockly.utils.Coordinate', 'Blockly.utils.deprecation', 'Blockly.utils.object', 'Blockly.utils.string'], {'lang': 'es5'});
goog.addDependency('../../core/block.js', ['Blockly.Block'], ['Blockly.ASTNode', 'Blockly.Blocks', 'Blockly.Connection', 'Blockly.Events', 'Blockly.Events.BlockChange', 'Blockly.Events.BlockCreate', 'Blockly.Events.BlockDelete', 'Blockly.Events.BlockMove', 'Blockly.Extensions', 'Blockly.Input', 'Blockly.Tooltip', 'Blockly.Workspace', 'Blockly.connectionTypes', 'Blockly.constants', 'Blockly.fieldRegistry', 'Blockly.inputTypes', 'Blockly.utils', 'Blockly.utils.Coordinate', 'Blockly.utils.Size', 'Blockly.utils.object'], {'lang': 'es5'});
goog.addDependency('../../core/block_animations.js', ['Blockly.blockAnimations'], ['Blockly.utils.Svg', 'Blockly.utils.dom'], {});
goog.addDependency('../../core/block_drag_surface.js', ['Blockly.BlockDragSurfaceSvg'], ['Blockly.utils', 'Blockly.utils.Coordinate', 'Blockly.utils.Svg', 'Blockly.utils.dom'], {});
goog.addDependency('../../core/block_dragger.js', ['Blockly.BlockDragger'], ['Blockly.Events', 'Blockly.Events.BlockDrag', 'Blockly.Events.BlockMove', 'Blockly.InsertionMarkerManager', 'Blockly.blockAnimations', 'Blockly.constants', 'Blockly.utils.Coordinate', 'Blockly.utils.dom'], {});
goog.addDependency('../../core/block_svg.js', ['Blockly.BlockSvg'], ['Blockly.ASTNode', 'Blockly.Block', 'Blockly.ContextMenu', 'Blockly.ContextMenuRegistry', 'Blockly.Events', 'Blockly.Events.BlockMove', 'Blockly.Events.Selected', 'Blockly.Msg', 'Blockly.RenderedConnection', 'Blockly.TabNavigateCursor', 'Blockly.Tooltip', 'Blockly.Touch', 'Blockly.blockAnimations', 'Blockly.blockRendering.IPathObject', 'Blockly.constants', 'Blockly.navigation', 'Blockly.utils', 'Blockly.utils.Coordinate', 'Blockly.utils.Rect', 'Blockly.utils.deprecation', 'Blockly.utils.dom', 'Blockly.utils.object', 'Blockly.utils.userAgent'], {});
goog.addDependency('../../core/blockly.js', ['Blockly'], ['Blockly.Events', 'Blockly.Events.Ui', 'Blockly.Events.UiBase', 'Blockly.Procedures', 'Blockly.ShortcutRegistry', 'Blockly.Tooltip', 'Blockly.Touch', 'Blockly.Variables', 'Blockly.WidgetDiv', 'Blockly.WorkspaceSvg', 'Blockly.Xml', 'Blockly.constants', 'Blockly.inject', 'Blockly.utils', 'Blockly.utils.Size', 'Blockly.utils.colour'], {});
goog.addDependency('../../core/block_svg.js', ['Blockly.BlockSvg'], ['Blockly.ASTNode', 'Blockly.Block', 'Blockly.ContextMenu', 'Blockly.ContextMenuRegistry', 'Blockly.Events', 'Blockly.Events.BlockMove', 'Blockly.Events.Selected', 'Blockly.Msg', 'Blockly.RenderedConnection', 'Blockly.TabNavigateCursor', 'Blockly.Tooltip', 'Blockly.Touch', 'Blockly.Xml', 'Blockly.blockAnimations', 'Blockly.blockRendering.IPathObject', 'Blockly.browserEvents', 'Blockly.connectionTypes', 'Blockly.constants', 'Blockly.utils', 'Blockly.utils.Coordinate', 'Blockly.utils.Rect', 'Blockly.utils.deprecation', 'Blockly.utils.dom', 'Blockly.utils.object', 'Blockly.utils.userAgent'], {});
goog.addDependency('../../core/blockly.js', ['Blockly'], ['Blockly.Events', 'Blockly.Events.BlockCreate', 'Blockly.Events.FinishedLoading', 'Blockly.Events.Ui', 'Blockly.Events.UiBase', 'Blockly.Events.VarCreate', 'Blockly.Procedures', 'Blockly.ShortcutRegistry', 'Blockly.Tooltip', 'Blockly.Touch', 'Blockly.Variables', 'Blockly.WidgetDiv', 'Blockly.WorkspaceSvg', 'Blockly.Xml', 'Blockly.browserEvents', 'Blockly.connectionTypes', 'Blockly.constants', 'Blockly.inject', 'Blockly.inputTypes', 'Blockly.utils', 'Blockly.utils.Size', 'Blockly.utils.colour', 'Blockly.utils.deprecation', 'Blockly.utils.toolbox'], {});
goog.addDependency('../../core/blocks.js', ['Blockly.Blocks'], [], {});
goog.addDependency('../../core/bubble.js', ['Blockly.Bubble'], ['Blockly.Scrollbar', 'Blockly.Touch', 'Blockly.Workspace', 'Blockly.utils', 'Blockly.utils.Coordinate', 'Blockly.utils.Svg', 'Blockly.utils.dom', 'Blockly.utils.math', 'Blockly.utils.userAgent'], {});
goog.addDependency('../../core/browser_events.js', ['Blockly.browserEvents'], ['Blockly.Touch'], {});
goog.addDependency('../../core/bubble.js', ['Blockly.Bubble'], ['Blockly.Scrollbar', 'Blockly.Touch', 'Blockly.Workspace', 'Blockly.browserEvents', 'Blockly.utils', 'Blockly.utils.Coordinate', 'Blockly.utils.Size', 'Blockly.utils.Svg', 'Blockly.utils.dom', 'Blockly.utils.math', 'Blockly.utils.userAgent'], {});
goog.addDependency('../../core/bubble_dragger.js', ['Blockly.BubbleDragger'], ['Blockly.Bubble', 'Blockly.Events', 'Blockly.Events.CommentMove', 'Blockly.constants', 'Blockly.utils', 'Blockly.utils.Coordinate'], {});
goog.addDependency('../../core/comment.js', ['Blockly.Comment'], ['Blockly.Bubble', 'Blockly.Css', 'Blockly.Events', 'Blockly.Events.BlockChange', 'Blockly.Events.BubbleOpen', 'Blockly.Icon', 'Blockly.Warning', 'Blockly.utils.Svg', 'Blockly.utils.deprecation', 'Blockly.utils.dom', 'Blockly.utils.object', 'Blockly.utils.userAgent'], {});
goog.addDependency('../../core/connection.js', ['Blockly.Connection'], ['Blockly.Events', 'Blockly.Events.BlockMove', 'Blockly.Xml', 'Blockly.constants', 'Blockly.utils.deprecation'], {});
goog.addDependency('../../core/connection_checker.js', ['Blockly.ConnectionChecker'], ['Blockly.constants', 'Blockly.registry'], {});
goog.addDependency('../../core/connection_db.js', ['Blockly.ConnectionDB'], ['Blockly.RenderedConnection', 'Blockly.constants'], {});
goog.addDependency('../../core/constants.js', ['Blockly.constants'], [], {});
goog.addDependency('../../core/contextmenu.js', ['Blockly.ContextMenu'], ['Blockly.Events', 'Blockly.Events.BlockCreate', 'Blockly.Menu', 'Blockly.MenuItem', 'Blockly.Msg', 'Blockly.Xml', 'Blockly.constants', 'Blockly.utils', 'Blockly.utils.Coordinate', 'Blockly.utils.Rect', 'Blockly.utils.dom', 'Blockly.utils.userAgent'], {});
goog.addDependency('../../core/contextmenu_items.js', ['Blockly.ContextMenuItems'], ['Blockly.constants'], {'lang': 'es5'});
goog.addDependency('../../core/contextmenu_registry.js', ['Blockly.ContextMenuRegistry'], ['Blockly.ContextMenuItems'], {'lang': 'es5'});
goog.addDependency('../../core/comment.js', ['Blockly.Comment'], ['Blockly.Bubble', 'Blockly.Css', 'Blockly.Events', 'Blockly.Events.BlockChange', 'Blockly.Events.BubbleOpen', 'Blockly.Icon', 'Blockly.Warning', 'Blockly.browserEvents', 'Blockly.utils.Svg', 'Blockly.utils.dom', 'Blockly.utils.object', 'Blockly.utils.userAgent'], {});
goog.addDependency('../../core/connection.js', ['Blockly.Connection'], ['Blockly.Events', 'Blockly.Events.BlockMove', 'Blockly.Xml', 'Blockly.connectionTypes', 'Blockly.constants', 'Blockly.utils.deprecation'], {});
goog.addDependency('../../core/connection_checker.js', ['Blockly.ConnectionChecker'], ['Blockly.Connection', 'Blockly.IConnectionChecker', 'Blockly.connectionTypes', 'Blockly.constants', 'Blockly.registry'], {});
goog.addDependency('../../core/connection_db.js', ['Blockly.ConnectionDB'], ['Blockly.RenderedConnection', 'Blockly.connectionTypes', 'Blockly.constants'], {});
goog.addDependency('../../core/connection_types.js', ['Blockly.connectionTypes'], [], {});
goog.addDependency('../../core/constants.js', ['Blockly.constants'], ['Blockly.connectionTypes'], {});
goog.addDependency('../../core/contextmenu.js', ['Blockly.ContextMenu'], ['Blockly.Events', 'Blockly.Events.BlockCreate', 'Blockly.Menu', 'Blockly.MenuItem', 'Blockly.Msg', 'Blockly.WidgetDiv', 'Blockly.Xml', 'Blockly.browserEvents', 'Blockly.constants', 'Blockly.utils', 'Blockly.utils.Coordinate', 'Blockly.utils.Rect', 'Blockly.utils.aria', 'Blockly.utils.dom', 'Blockly.utils.userAgent'], {});
goog.addDependency('../../core/contextmenu_items.js', ['Blockly.ContextMenuItems'], ['Blockly.ContextMenuRegistry', 'Blockly.Events', 'Blockly.constants', 'Blockly.inputTypes'], {'lang': 'es5'});
goog.addDependency('../../core/contextmenu_registry.js', ['Blockly.ContextMenuRegistry'], [], {'lang': 'es5'});
goog.addDependency('../../core/css.js', ['Blockly.Css'], [], {'lang': 'es5'});
goog.addDependency('../../core/dropdowndiv.js', ['Blockly.DropDownDiv'], ['Blockly.utils.dom', 'Blockly.utils.math', 'Blockly.utils.style'], {});
goog.addDependency('../../core/events/block_events.js', ['Blockly.Events.BlockBase', 'Blockly.Events.BlockChange', 'Blockly.Events.BlockCreate', 'Blockly.Events.BlockDelete', 'Blockly.Events.BlockMove', 'Blockly.Events.Change', 'Blockly.Events.Create', 'Blockly.Events.Delete', 'Blockly.Events.Move'], ['Blockly.Events', 'Blockly.Events.Abstract', 'Blockly.registry', 'Blockly.utils.Coordinate', 'Blockly.utils.object', 'Blockly.utils.xml'], {});
goog.addDependency('../../core/dropdowndiv.js', ['Blockly.DropDownDiv'], ['Blockly.utils.Rect', 'Blockly.utils.dom', 'Blockly.utils.math', 'Blockly.utils.style'], {});
goog.addDependency('../../core/events/block_events.js', ['Blockly.Events.BlockBase', 'Blockly.Events.BlockChange', 'Blockly.Events.BlockCreate', 'Blockly.Events.BlockDelete', 'Blockly.Events.BlockMove', 'Blockly.Events.Change', 'Blockly.Events.Create', 'Blockly.Events.Delete', 'Blockly.Events.Move'], ['Blockly.Events', 'Blockly.Events.Abstract', 'Blockly.Xml', 'Blockly.connectionTypes', 'Blockly.registry', 'Blockly.utils.Coordinate', 'Blockly.utils.object', 'Blockly.utils.xml'], {});
goog.addDependency('../../core/events/events.js', ['Blockly.Events'], ['Blockly.registry', 'Blockly.utils'], {});
goog.addDependency('../../core/events/events_abstract.js', ['Blockly.Events.Abstract'], ['Blockly.Events'], {});
goog.addDependency('../../core/events/events_block_drag.js', ['Blockly.Events.BlockDrag'], ['Blockly.Events', 'Blockly.Events.UiBase', 'Blockly.registry', 'Blockly.utils.object'], {});
@@ -55,34 +57,34 @@ goog.addDependency('../../core/events/events_viewport.js', ['Blockly.Events.View
goog.addDependency('../../core/events/ui_events.js', ['Blockly.Events.Ui', 'Blockly.Events.UiBase'], ['Blockly.Events', 'Blockly.Events.Abstract', 'Blockly.registry', 'Blockly.utils.object'], {});
goog.addDependency('../../core/events/variable_events.js', ['Blockly.Events.VarBase', 'Blockly.Events.VarCreate', 'Blockly.Events.VarDelete', 'Blockly.Events.VarRename'], ['Blockly.Events', 'Blockly.Events.Abstract', 'Blockly.registry', 'Blockly.utils.object'], {});
goog.addDependency('../../core/events/workspace_events.js', ['Blockly.Events.FinishedLoading'], ['Blockly.Events', 'Blockly.Events.Abstract', 'Blockly.registry', 'Blockly.utils.object'], {'lang': 'es5'});
goog.addDependency('../../core/events/ws_comment_events.js', ['Blockly.Events.CommentBase', 'Blockly.Events.CommentChange', 'Blockly.Events.CommentCreate', 'Blockly.Events.CommentDelete', 'Blockly.Events.CommentMove'], ['Blockly.Events', 'Blockly.Events.Abstract', 'Blockly.registry', 'Blockly.utils.Coordinate', 'Blockly.utils.object', 'Blockly.utils.xml'], {});
goog.addDependency('../../core/events/ws_comment_events.js', ['Blockly.Events.CommentBase', 'Blockly.Events.CommentChange', 'Blockly.Events.CommentCreate', 'Blockly.Events.CommentDelete', 'Blockly.Events.CommentMove'], ['Blockly.Events', 'Blockly.Events.Abstract', 'Blockly.Xml', 'Blockly.registry', 'Blockly.utils.Coordinate', 'Blockly.utils.object', 'Blockly.utils.xml'], {});
goog.addDependency('../../core/extensions.js', ['Blockly.Extensions'], ['Blockly.utils'], {});
goog.addDependency('../../core/field.js', ['Blockly.Field'], ['Blockly.Events', 'Blockly.Events.BlockChange', 'Blockly.Gesture', 'Blockly.Tooltip', 'Blockly.utils', 'Blockly.utils.Rect', 'Blockly.utils.Size', 'Blockly.utils.Svg', 'Blockly.utils.dom', 'Blockly.utils.style', 'Blockly.utils.userAgent'], {'lang': 'es5'});
goog.addDependency('../../core/field_angle.js', ['Blockly.FieldAngle'], ['Blockly.Css', 'Blockly.DropDownDiv', 'Blockly.FieldTextInput', 'Blockly.fieldRegistry', 'Blockly.utils.Svg', 'Blockly.utils.dom', 'Blockly.utils.math', 'Blockly.utils.object', 'Blockly.utils.userAgent'], {});
goog.addDependency('../../core/field_checkbox.js', ['Blockly.FieldCheckbox'], ['Blockly.Events', 'Blockly.Events.BlockChange', 'Blockly.Field', 'Blockly.fieldRegistry', 'Blockly.utils.Size', 'Blockly.utils.dom', 'Blockly.utils.object'], {});
goog.addDependency('../../core/field_colour.js', ['Blockly.FieldColour'], ['Blockly.Css', 'Blockly.DropDownDiv', 'Blockly.Events', 'Blockly.Events.BlockChange', 'Blockly.Field', 'Blockly.fieldRegistry', 'Blockly.navigation', 'Blockly.utils.IdGenerator', 'Blockly.utils.KeyCodes', 'Blockly.utils.Size', 'Blockly.utils.aria', 'Blockly.utils.colour', 'Blockly.utils.dom', 'Blockly.utils.object'], {});
goog.addDependency('../../core/field_dropdown.js', ['Blockly.FieldDropdown'], ['Blockly.Events', 'Blockly.Events.BlockChange', 'Blockly.Field', 'Blockly.Menu', 'Blockly.MenuItem', 'Blockly.fieldRegistry', 'Blockly.navigation', 'Blockly.utils', 'Blockly.utils.Coordinate', 'Blockly.utils.Size', 'Blockly.utils.Svg', 'Blockly.utils.aria', 'Blockly.utils.dom', 'Blockly.utils.object', 'Blockly.utils.string', 'Blockly.utils.userAgent'], {});
goog.addDependency('../../core/field.js', ['Blockly.Field'], ['Blockly.Events', 'Blockly.Events.BlockChange', 'Blockly.Gesture', 'Blockly.Tooltip', 'Blockly.browserEvents', 'Blockly.utils', 'Blockly.utils.Rect', 'Blockly.utils.Size', 'Blockly.utils.Svg', 'Blockly.utils.dom', 'Blockly.utils.style', 'Blockly.utils.userAgent'], {'lang': 'es5'});
goog.addDependency('../../core/field_angle.js', ['Blockly.FieldAngle'], ['Blockly.Css', 'Blockly.DropDownDiv', 'Blockly.FieldTextInput', 'Blockly.browserEvents', 'Blockly.fieldRegistry', 'Blockly.utils.Svg', 'Blockly.utils.dom', 'Blockly.utils.math', 'Blockly.utils.object', 'Blockly.utils.userAgent'], {});
goog.addDependency('../../core/field_checkbox.js', ['Blockly.FieldCheckbox'], ['Blockly.Events.BlockChange', 'Blockly.Field', 'Blockly.fieldRegistry', 'Blockly.utils.dom', 'Blockly.utils.object'], {});
goog.addDependency('../../core/field_colour.js', ['Blockly.FieldColour'], ['Blockly.Css', 'Blockly.DropDownDiv', 'Blockly.Events.BlockChange', 'Blockly.Field', 'Blockly.browserEvents', 'Blockly.fieldRegistry', 'Blockly.utils.IdGenerator', 'Blockly.utils.KeyCodes', 'Blockly.utils.Size', 'Blockly.utils.aria', 'Blockly.utils.colour', 'Blockly.utils.dom', 'Blockly.utils.object'], {});
goog.addDependency('../../core/field_dropdown.js', ['Blockly.FieldDropdown'], ['Blockly.Field', 'Blockly.Menu', 'Blockly.MenuItem', 'Blockly.fieldRegistry', 'Blockly.utils', 'Blockly.utils.Coordinate', 'Blockly.utils.Svg', 'Blockly.utils.aria', 'Blockly.utils.dom', 'Blockly.utils.object', 'Blockly.utils.string', 'Blockly.utils.userAgent'], {});
goog.addDependency('../../core/field_image.js', ['Blockly.FieldImage'], ['Blockly.Field', 'Blockly.fieldRegistry', 'Blockly.utils', 'Blockly.utils.Size', 'Blockly.utils.Svg', 'Blockly.utils.dom', 'Blockly.utils.object'], {});
goog.addDependency('../../core/field_label.js', ['Blockly.FieldLabel'], ['Blockly.Field', 'Blockly.fieldRegistry', 'Blockly.utils', 'Blockly.utils.Size', 'Blockly.utils.dom', 'Blockly.utils.object'], {});
goog.addDependency('../../core/field_label.js', ['Blockly.FieldLabel'], ['Blockly.Field', 'Blockly.fieldRegistry', 'Blockly.utils', 'Blockly.utils.dom', 'Blockly.utils.object'], {});
goog.addDependency('../../core/field_label_serializable.js', ['Blockly.FieldLabelSerializable'], ['Blockly.FieldLabel', 'Blockly.fieldRegistry', 'Blockly.utils', 'Blockly.utils.object'], {});
goog.addDependency('../../core/field_multilineinput.js', ['Blockly.FieldMultilineInput'], ['Blockly.Css', 'Blockly.DropDownDiv', 'Blockly.FieldTextInput', 'Blockly.utils', 'Blockly.utils.Coordinate', 'Blockly.utils.KeyCodes', 'Blockly.utils.Svg', 'Blockly.utils.aria', 'Blockly.utils.dom', 'Blockly.utils.object', 'Blockly.utils.userAgent'], {'lang': 'es5'});
goog.addDependency('../../core/field_multilineinput.js', ['Blockly.FieldMultilineInput'], ['Blockly.Css', 'Blockly.FieldTextInput', 'Blockly.utils', 'Blockly.utils.KeyCodes', 'Blockly.utils.Svg', 'Blockly.utils.aria', 'Blockly.utils.dom', 'Blockly.utils.object', 'Blockly.utils.userAgent'], {'lang': 'es5'});
goog.addDependency('../../core/field_number.js', ['Blockly.FieldNumber'], ['Blockly.FieldTextInput', 'Blockly.fieldRegistry', 'Blockly.utils.aria', 'Blockly.utils.object'], {});
goog.addDependency('../../core/field_registry.js', ['Blockly.fieldRegistry'], ['Blockly.registry'], {});
goog.addDependency('../../core/field_textinput.js', ['Blockly.FieldTextInput'], ['Blockly.Events', 'Blockly.Events.BlockChange', 'Blockly.Field', 'Blockly.Msg', 'Blockly.fieldRegistry', 'Blockly.utils', 'Blockly.utils.Coordinate', 'Blockly.utils.KeyCodes', 'Blockly.utils.Size', 'Blockly.utils.aria', 'Blockly.utils.dom', 'Blockly.utils.object', 'Blockly.utils.userAgent'], {});
goog.addDependency('../../core/field_variable.js', ['Blockly.FieldVariable'], ['Blockly.Events', 'Blockly.Events.BlockChange', 'Blockly.FieldDropdown', 'Blockly.Msg', 'Blockly.VariableModel', 'Blockly.Variables', 'Blockly.Xml', 'Blockly.constants', 'Blockly.fieldRegistry', 'Blockly.utils', 'Blockly.utils.Size', 'Blockly.utils.object'], {});
goog.addDependency('../../core/flyout_base.js', ['Blockly.Flyout'], ['Blockly.Block', 'Blockly.Events', 'Blockly.Events.BlockCreate', 'Blockly.Events.VarCreate', 'Blockly.FlyoutCursor', 'Blockly.Gesture', 'Blockly.Marker', 'Blockly.Scrollbar', 'Blockly.Tooltip', 'Blockly.Touch', 'Blockly.WorkspaceSvg', 'Blockly.Xml', 'Blockly.blockRendering', 'Blockly.utils', 'Blockly.utils.Coordinate', 'Blockly.utils.Svg', 'Blockly.utils.dom', 'Blockly.utils.toolbox'], {});
goog.addDependency('../../core/flyout_button.js', ['Blockly.FlyoutButton'], ['Blockly.Css', 'Blockly.utils', 'Blockly.utils.Coordinate', 'Blockly.utils.Svg', 'Blockly.utils.dom'], {'lang': 'es5'});
goog.addDependency('../../core/flyout_dragger.js', ['Blockly.FlyoutDragger'], ['Blockly.WorkspaceDragger', 'Blockly.utils.object'], {});
goog.addDependency('../../core/flyout_horizontal.js', ['Blockly.HorizontalFlyout'], ['Blockly.Block', 'Blockly.Flyout', 'Blockly.Scrollbar', 'Blockly.WidgetDiv', 'Blockly.constants', 'Blockly.registry', 'Blockly.utils', 'Blockly.utils.Rect', 'Blockly.utils.object'], {});
goog.addDependency('../../core/flyout_vertical.js', ['Blockly.VerticalFlyout'], ['Blockly.Block', 'Blockly.Flyout', 'Blockly.Scrollbar', 'Blockly.WidgetDiv', 'Blockly.constants', 'Blockly.registry', 'Blockly.utils', 'Blockly.utils.Rect', 'Blockly.utils.object', 'Blockly.utils.userAgent'], {});
goog.addDependency('../../core/field_textinput.js', ['Blockly.FieldTextInput'], ['Blockly.Events', 'Blockly.Events.BlockChange', 'Blockly.Field', 'Blockly.Msg', 'Blockly.browserEvents', 'Blockly.fieldRegistry', 'Blockly.utils', 'Blockly.utils.Coordinate', 'Blockly.utils.KeyCodes', 'Blockly.utils.aria', 'Blockly.utils.dom', 'Blockly.utils.object', 'Blockly.utils.userAgent'], {});
goog.addDependency('../../core/field_variable.js', ['Blockly.FieldVariable'], ['Blockly.Events.BlockChange', 'Blockly.FieldDropdown', 'Blockly.Msg', 'Blockly.VariableModel', 'Blockly.Variables', 'Blockly.Xml', 'Blockly.constants', 'Blockly.fieldRegistry', 'Blockly.utils', 'Blockly.utils.Size', 'Blockly.utils.object'], {});
goog.addDependency('../../core/flyout_base.js', ['Blockly.Flyout'], ['Blockly.Block', 'Blockly.Events', 'Blockly.Events.BlockCreate', 'Blockly.Events.VarCreate', 'Blockly.FlyoutMetricsManager', 'Blockly.Gesture', 'Blockly.ScrollbarPair', 'Blockly.Tooltip', 'Blockly.Touch', 'Blockly.WorkspaceSvg', 'Blockly.Xml', 'Blockly.blockRendering', 'Blockly.browserEvents', 'Blockly.utils', 'Blockly.utils.Coordinate', 'Blockly.utils.Svg', 'Blockly.utils.dom', 'Blockly.utils.toolbox', 'Blockly.utils.xml'], {});
goog.addDependency('../../core/flyout_button.js', ['Blockly.FlyoutButton'], ['Blockly.Css', 'Blockly.browserEvents', 'Blockly.utils', 'Blockly.utils.Coordinate', 'Blockly.utils.Svg', 'Blockly.utils.dom'], {'lang': 'es5'});
goog.addDependency('../../core/flyout_horizontal.js', ['Blockly.HorizontalFlyout'], ['Blockly.Block', 'Blockly.Flyout', 'Blockly.Scrollbar', 'Blockly.WidgetDiv', 'Blockly.constants', 'Blockly.registry', 'Blockly.utils', 'Blockly.utils.Rect', 'Blockly.utils.object', 'Blockly.utils.toolbox'], {});
goog.addDependency('../../core/flyout_vertical.js', ['Blockly.VerticalFlyout'], ['Blockly.Block', 'Blockly.Flyout', 'Blockly.Scrollbar', 'Blockly.WidgetDiv', 'Blockly.constants', 'Blockly.registry', 'Blockly.utils', 'Blockly.utils.Rect', 'Blockly.utils.object', 'Blockly.utils.toolbox'], {});
goog.addDependency('../../core/generator.js', ['Blockly.Generator'], ['Blockly.Block', 'Blockly.constants'], {});
goog.addDependency('../../core/gesture.js', ['Blockly.Gesture'], ['Blockly.ASTNode', 'Blockly.BlockDragger', 'Blockly.BubbleDragger', 'Blockly.Events', 'Blockly.Events.Click', 'Blockly.FlyoutDragger', 'Blockly.Tooltip', 'Blockly.Touch', 'Blockly.WorkspaceDragger', 'Blockly.blockAnimations', 'Blockly.constants', 'Blockly.navigation', 'Blockly.utils', 'Blockly.utils.Coordinate'], {});
goog.addDependency('../../core/gesture.js', ['Blockly.Gesture'], ['Blockly.BlockDragger', 'Blockly.BubbleDragger', 'Blockly.Events', 'Blockly.Events.Click', 'Blockly.Tooltip', 'Blockly.Touch', 'Blockly.WorkspaceDragger', 'Blockly.blockAnimations', 'Blockly.browserEvents', 'Blockly.constants', 'Blockly.utils', 'Blockly.utils.Coordinate'], {});
goog.addDependency('../../core/grid.js', ['Blockly.Grid'], ['Blockly.utils.Svg', 'Blockly.utils.dom', 'Blockly.utils.userAgent'], {});
goog.addDependency('../../core/icon.js', ['Blockly.Icon'], ['Blockly.utils', 'Blockly.utils.Coordinate', 'Blockly.utils.Size', 'Blockly.utils.Svg', 'Blockly.utils.dom'], {});
goog.addDependency('../../core/inject.js', ['Blockly.inject'], ['Blockly.BlockDragSurfaceSvg', 'Blockly.Css', 'Blockly.DropDownDiv', 'Blockly.Events', 'Blockly.Grid', 'Blockly.Msg', 'Blockly.Options', 'Blockly.ScrollbarPair', 'Blockly.Tooltip', 'Blockly.WorkspaceDragSurfaceSvg', 'Blockly.WorkspaceSvg', 'Blockly.utils', 'Blockly.utils.Svg', 'Blockly.utils.dom', 'Blockly.utils.userAgent'], {});
goog.addDependency('../../core/input.js', ['Blockly.Input'], ['Blockly.Connection', 'Blockly.FieldLabel', 'Blockly.constants'], {});
goog.addDependency('../../core/insertion_marker_manager.js', ['Blockly.InsertionMarkerManager'], ['Blockly.Events', 'Blockly.blockAnimations', 'Blockly.constants'], {'lang': 'es5'});
goog.addDependency('../../core/interfaces/i_accessibility.js', ['Blockly.IASTNodeLocation', 'Blockly.IASTNodeLocationSvg', 'Blockly.IASTNodeLocationWithBlock', 'Blockly.IBlocklyActionable'], [], {});
goog.addDependency('../../core/icon.js', ['Blockly.Icon'], ['Blockly.browserEvents', 'Blockly.utils', 'Blockly.utils.Coordinate', 'Blockly.utils.Size', 'Blockly.utils.Svg', 'Blockly.utils.dom'], {});
goog.addDependency('../../core/inject.js', ['Blockly.inject'], ['Blockly.BlockDragSurfaceSvg', 'Blockly.Css', 'Blockly.DropDownDiv', 'Blockly.Events', 'Blockly.Grid', 'Blockly.Msg', 'Blockly.Options', 'Blockly.ScrollbarPair', 'Blockly.Tooltip', 'Blockly.WorkspaceDragSurfaceSvg', 'Blockly.WorkspaceSvg', 'Blockly.browserEvents', 'Blockly.utils', 'Blockly.utils.Svg', 'Blockly.utils.aria', 'Blockly.utils.dom', 'Blockly.utils.userAgent'], {});
goog.addDependency('../../core/input.js', ['Blockly.Input'], ['Blockly.Connection', 'Blockly.FieldLabel', 'Blockly.constants', 'Blockly.fieldRegistry', 'Blockly.inputTypes'], {'lang': 'es5'});
goog.addDependency('../../core/input_types.js', ['Blockly.inputTypes'], ['Blockly.connectionTypes'], {});
goog.addDependency('../../core/insertion_marker_manager.js', ['Blockly.InsertionMarkerManager'], ['Blockly.Events', 'Blockly.blockAnimations', 'Blockly.connectionTypes', 'Blockly.constants'], {'lang': 'es5'});
goog.addDependency('../../core/interfaces/i_accessibility.js', ['Blockly.IASTNodeLocation', 'Blockly.IASTNodeLocationSvg', 'Blockly.IASTNodeLocationWithBlock', 'Blockly.IKeyboardAccessible'], [], {});
goog.addDependency('../../core/interfaces/i_bounded_element.js', ['Blockly.IBoundedElement'], [], {});
goog.addDependency('../../core/interfaces/i_bubble.js', ['Blockly.IBubble'], [], {});
goog.addDependency('../../core/interfaces/i_connection_checker.js', ['Blockly.IConnectionChecker'], [], {});
@@ -91,50 +93,54 @@ goog.addDependency('../../core/interfaces/i_copyable.js', ['Blockly.ICopyable'],
goog.addDependency('../../core/interfaces/i_deletable.js', ['Blockly.IDeletable'], [], {});
goog.addDependency('../../core/interfaces/i_deletearea.js', ['Blockly.IDeleteArea'], [], {});
goog.addDependency('../../core/interfaces/i_flyout.js', ['Blockly.IFlyout'], [], {});
goog.addDependency('../../core/interfaces/i_metrics_manager.js', ['Blockly.IMetricsManager'], [], {});
goog.addDependency('../../core/interfaces/i_movable.js', ['Blockly.IMovable'], [], {});
goog.addDependency('../../core/interfaces/i_plugin.js', ['Blockly.IPlugin'], [], {});
goog.addDependency('../../core/interfaces/i_positionable.js', ['Blockly.IPositionable'], ['Blockly.IPlugin'], {});
goog.addDependency('../../core/interfaces/i_registrable.js', ['Blockly.IRegistrable'], [], {});
goog.addDependency('../../core/interfaces/i_registrable_field.js', ['Blockly.IRegistrableField'], [], {});
goog.addDependency('../../core/interfaces/i_selectable.js', ['Blockly.ISelectable'], [], {});
goog.addDependency('../../core/interfaces/i_styleable.js', ['Blockly.IStyleable'], [], {});
goog.addDependency('../../core/interfaces/i_toolbox.js', ['Blockly.IToolbox'], [], {});
goog.addDependency('../../core/interfaces/i_toolbox_item.js', ['Blockly.ICollapsibleToolboxItem', 'Blockly.ISelectableToolboxItem', 'Blockly.IToolboxItem'], [], {});
goog.addDependency('../../core/keyboard_nav/ast_node.js', ['Blockly.ASTNode'], ['Blockly.constants', 'Blockly.utils.Coordinate'], {'lang': 'es5'});
goog.addDependency('../../core/keyboard_nav/basic_cursor.js', ['Blockly.BasicCursor'], ['Blockly.ASTNode', 'Blockly.Cursor'], {'lang': 'es5'});
goog.addDependency('../../core/keyboard_nav/cursor.js', ['Blockly.Cursor'], ['Blockly.ASTNode', 'Blockly.Marker', 'Blockly.navigation', 'Blockly.utils.object'], {'lang': 'es5'});
goog.addDependency('../../core/keyboard_nav/flyout_cursor.js', ['Blockly.FlyoutCursor'], ['Blockly.Cursor', 'Blockly.navigation', 'Blockly.utils.object'], {'lang': 'es5'});
goog.addDependency('../../core/keyboard_nav/marker.js', ['Blockly.Marker'], ['Blockly.ASTNode', 'Blockly.navigation'], {});
goog.addDependency('../../core/keyboard_nav/navigation.js', ['Blockly.navigation'], ['Blockly.ASTNode', 'Blockly.constants', 'Blockly.utils.Coordinate'], {});
goog.addDependency('../../core/interfaces/i_workspace_plugin.js', ['Blockly.IWorkspacePlugin'], [], {});
goog.addDependency('../../core/keyboard_nav/ast_node.js', ['Blockly.ASTNode'], ['Blockly.connectionTypes', 'Blockly.constants', 'Blockly.utils.Coordinate'], {'lang': 'es5'});
goog.addDependency('../../core/keyboard_nav/basic_cursor.js', ['Blockly.BasicCursor'], ['Blockly.ASTNode', 'Blockly.Cursor', 'Blockly.registry'], {'lang': 'es5'});
goog.addDependency('../../core/keyboard_nav/cursor.js', ['Blockly.Cursor'], ['Blockly.ASTNode', 'Blockly.Marker', 'Blockly.registry', 'Blockly.utils.object'], {'lang': 'es5'});
goog.addDependency('../../core/keyboard_nav/marker.js', ['Blockly.Marker'], ['Blockly.ASTNode'], {});
goog.addDependency('../../core/keyboard_nav/tab_navigate_cursor.js', ['Blockly.TabNavigateCursor'], ['Blockly.ASTNode', 'Blockly.BasicCursor', 'Blockly.utils.object'], {});
goog.addDependency('../../core/marker_manager.js', ['Blockly.MarkerManager'], ['Blockly.Cursor', 'Blockly.Marker'], {});
goog.addDependency('../../core/menu.js', ['Blockly.Menu'], ['Blockly.utils.Coordinate', 'Blockly.utils.KeyCodes', 'Blockly.utils.aria', 'Blockly.utils.dom', 'Blockly.utils.style'], {});
goog.addDependency('../../core/menu.js', ['Blockly.Menu'], ['Blockly.browserEvents', 'Blockly.utils.Coordinate', 'Blockly.utils.KeyCodes', 'Blockly.utils.aria', 'Blockly.utils.dom', 'Blockly.utils.style'], {});
goog.addDependency('../../core/menuitem.js', ['Blockly.MenuItem'], ['Blockly.utils.IdGenerator', 'Blockly.utils.aria', 'Blockly.utils.dom'], {});
goog.addDependency('../../core/metrics_manager.js', ['Blockly.FlyoutMetricsManager', 'Blockly.MetricsManager'], ['Blockly.IMetricsManager', 'Blockly.registry', 'Blockly.utils.Size', 'Blockly.utils.toolbox'], {'lang': 'es5'});
goog.addDependency('../../core/msg.js', ['Blockly.Msg'], ['Blockly.utils.global'], {});
goog.addDependency('../../core/mutator.js', ['Blockly.Mutator'], ['Blockly.Bubble', 'Blockly.Events', 'Blockly.Events.BlockChange', 'Blockly.Events.BubbleOpen', 'Blockly.Icon', 'Blockly.WorkspaceSvg', 'Blockly.Xml', 'Blockly.navigation', 'Blockly.utils', 'Blockly.utils.Svg', 'Blockly.utils.dom', 'Blockly.utils.global', 'Blockly.utils.object', 'Blockly.utils.toolbox', 'Blockly.utils.xml'], {});
goog.addDependency('../../core/mutator.js', ['Blockly.Mutator'], ['Blockly.Bubble', 'Blockly.Events', 'Blockly.Events.BlockChange', 'Blockly.Events.BubbleOpen', 'Blockly.Icon', 'Blockly.WorkspaceSvg', 'Blockly.Xml', 'Blockly.utils', 'Blockly.utils.Svg', 'Blockly.utils.dom', 'Blockly.utils.object', 'Blockly.utils.toolbox', 'Blockly.utils.xml'], {});
goog.addDependency('../../core/names.js', ['Blockly.Names'], ['Blockly.Msg', 'Blockly.constants'], {});
goog.addDependency('../../core/options.js', ['Blockly.Options'], ['Blockly.Theme', 'Blockly.Themes.Classic', 'Blockly.Xml', 'Blockly.registry', 'Blockly.utils.IdGenerator', 'Blockly.utils.Metrics', 'Blockly.utils.toolbox', 'Blockly.utils.userAgent'], {});
goog.addDependency('../../core/options.js', ['Blockly.Options'], ['Blockly.Theme', 'Blockly.Themes.Classic', 'Blockly.registry', 'Blockly.utils.IdGenerator', 'Blockly.utils.Metrics', 'Blockly.utils.toolbox'], {});
goog.addDependency('../../core/plugin_manager.js', ['Blockly.PluginManager'], [], {});
goog.addDependency('../../core/procedures.js', ['Blockly.Procedures'], ['Blockly.Blocks', 'Blockly.Events', 'Blockly.Events.BlockChange', 'Blockly.Field', 'Blockly.Msg', 'Blockly.Names', 'Blockly.Workspace', 'Blockly.Xml', 'Blockly.constants', 'Blockly.utils.xml'], {});
goog.addDependency('../../core/registry.js', ['Blockly.registry'], [], {});
goog.addDependency('../../core/rendered_connection.js', ['Blockly.RenderedConnection'], ['Blockly.Connection', 'Blockly.Events', 'Blockly.constants', 'Blockly.utils', 'Blockly.utils.Coordinate', 'Blockly.utils.Svg', 'Blockly.utils.deprecation', 'Blockly.utils.dom', 'Blockly.utils.object'], {});
goog.addDependency('../../core/renderers/common/block_rendering.js', ['Blockly.blockRendering'], ['Blockly.registry', 'Blockly.utils.object'], {});
goog.addDependency('../../core/renderers/common/constants.js', ['Blockly.blockRendering.ConstantProvider'], ['Blockly.constants', 'Blockly.utils', 'Blockly.utils.Svg', 'Blockly.utils.colour', 'Blockly.utils.dom', 'Blockly.utils.svgPaths', 'Blockly.utils.userAgent'], {'lang': 'es5'});
goog.addDependency('../../core/renderers/common/debugger.js', ['Blockly.blockRendering.Debug'], ['Blockly.blockRendering.BottomRow', 'Blockly.blockRendering.InputRow', 'Blockly.blockRendering.Measurable', 'Blockly.blockRendering.RenderInfo', 'Blockly.blockRendering.Row', 'Blockly.blockRendering.SpacerRow', 'Blockly.blockRendering.TopRow', 'Blockly.blockRendering.Types', 'Blockly.constants', 'Blockly.utils.Svg', 'Blockly.utils.dom'], {'lang': 'es5'});
goog.addDependency('../../core/renderers/common/drawer.js', ['Blockly.blockRendering.Drawer'], ['Blockly.blockRendering.BottomRow', 'Blockly.blockRendering.InputRow', 'Blockly.blockRendering.Measurable', 'Blockly.blockRendering.RenderInfo', 'Blockly.blockRendering.Row', 'Blockly.blockRendering.SpacerRow', 'Blockly.blockRendering.TopRow', 'Blockly.blockRendering.Types', 'Blockly.utils.svgPaths'], {});
goog.addDependency('../../core/rendered_connection.js', ['Blockly.RenderedConnection'], ['Blockly.Connection', 'Blockly.connectionTypes', 'Blockly.constants', 'Blockly.utils', 'Blockly.utils.Coordinate', 'Blockly.utils.Svg', 'Blockly.utils.deprecation', 'Blockly.utils.dom', 'Blockly.utils.object'], {});
goog.addDependency('../../core/renderers/common/block_rendering.js', ['Blockly.blockRendering'], ['Blockly.registry'], {});
goog.addDependency('../../core/renderers/common/constants.js', ['Blockly.blockRendering.ConstantProvider'], ['Blockly.connectionTypes', 'Blockly.constants', 'Blockly.utils', 'Blockly.utils.Svg', 'Blockly.utils.colour', 'Blockly.utils.dom', 'Blockly.utils.svgPaths', 'Blockly.utils.userAgent'], {'lang': 'es5'});
goog.addDependency('../../core/renderers/common/debugger.js', ['Blockly.blockRendering.Debug'], ['Blockly.blockRendering.Measurable', 'Blockly.blockRendering.RenderInfo', 'Blockly.blockRendering.Row', 'Blockly.blockRendering.Types', 'Blockly.connectionTypes', 'Blockly.constants', 'Blockly.utils.Svg', 'Blockly.utils.dom'], {'lang': 'es5'});
goog.addDependency('../../core/renderers/common/drawer.js', ['Blockly.blockRendering.Drawer'], ['Blockly.blockRendering.RenderInfo', 'Blockly.blockRendering.Row', 'Blockly.blockRendering.Types', 'Blockly.utils.svgPaths'], {});
goog.addDependency('../../core/renderers/common/i_path_object.js', ['Blockly.blockRendering.IPathObject'], [], {});
goog.addDependency('../../core/renderers/common/info.js', ['Blockly.blockRendering.RenderInfo'], ['Blockly.blockRendering.BottomRow', 'Blockly.blockRendering.ExternalValueInput', 'Blockly.blockRendering.Hat', 'Blockly.blockRendering.InRowSpacer', 'Blockly.blockRendering.InlineInput', 'Blockly.blockRendering.InputRow', 'Blockly.blockRendering.Measurable', 'Blockly.blockRendering.NextConnection', 'Blockly.blockRendering.OutputConnection', 'Blockly.blockRendering.PreviousConnection', 'Blockly.blockRendering.RoundCorner', 'Blockly.blockRendering.Row', 'Blockly.blockRendering.SpacerRow', 'Blockly.blockRendering.SquareCorner', 'Blockly.blockRendering.StatementInput', 'Blockly.blockRendering.TopRow', 'Blockly.blockRendering.Types', 'Blockly.constants'], {});
goog.addDependency('../../core/renderers/common/marker_svg.js', ['Blockly.blockRendering.MarkerSvg'], ['Blockly.ASTNode', 'Blockly.Events.MarkerMove', 'Blockly.constants', 'Blockly.utils.Svg', 'Blockly.utils.dom'], {});
goog.addDependency('../../core/renderers/common/info.js', ['Blockly.blockRendering.RenderInfo'], ['Blockly.blockRendering.BottomRow', 'Blockly.blockRendering.ExternalValueInput', 'Blockly.blockRendering.Hat', 'Blockly.blockRendering.InRowSpacer', 'Blockly.blockRendering.InlineInput', 'Blockly.blockRendering.InputRow', 'Blockly.blockRendering.Measurable', 'Blockly.blockRendering.NextConnection', 'Blockly.blockRendering.OutputConnection', 'Blockly.blockRendering.PreviousConnection', 'Blockly.blockRendering.RoundCorner', 'Blockly.blockRendering.Row', 'Blockly.blockRendering.SpacerRow', 'Blockly.blockRendering.SquareCorner', 'Blockly.blockRendering.StatementInput', 'Blockly.blockRendering.TopRow', 'Blockly.blockRendering.Types', 'Blockly.constants', 'Blockly.inputTypes'], {});
goog.addDependency('../../core/renderers/common/marker_svg.js', ['Blockly.blockRendering.MarkerSvg'], ['Blockly.ASTNode', 'Blockly.Events', 'Blockly.Events.MarkerMove', 'Blockly.connectionTypes', 'Blockly.constants', 'Blockly.utils.Svg', 'Blockly.utils.dom'], {});
goog.addDependency('../../core/renderers/common/path_object.js', ['Blockly.blockRendering.PathObject'], ['Blockly.Theme', 'Blockly.blockRendering.ConstantProvider', 'Blockly.blockRendering.IPathObject', 'Blockly.utils.Svg', 'Blockly.utils.dom'], {});
goog.addDependency('../../core/renderers/common/renderer.js', ['Blockly.blockRendering.Renderer'], ['Blockly.InsertionMarkerManager', 'Blockly.blockRendering.ConstantProvider', 'Blockly.blockRendering.Drawer', 'Blockly.blockRendering.IPathObject', 'Blockly.blockRendering.MarkerSvg', 'Blockly.blockRendering.PathObject', 'Blockly.blockRendering.RenderInfo', 'Blockly.constants'], {});
goog.addDependency('../../core/renderers/common/renderer.js', ['Blockly.blockRendering.Renderer'], ['Blockly.IRegistrable', 'Blockly.InsertionMarkerManager', 'Blockly.blockRendering.ConstantProvider', 'Blockly.blockRendering.Debug', 'Blockly.blockRendering.Drawer', 'Blockly.blockRendering.IPathObject', 'Blockly.blockRendering.MarkerSvg', 'Blockly.blockRendering.PathObject', 'Blockly.blockRendering.RenderInfo', 'Blockly.connectionTypes', 'Blockly.constants'], {});
goog.addDependency('../../core/renderers/geras/constants.js', ['Blockly.geras.ConstantProvider'], ['Blockly.blockRendering.ConstantProvider', 'Blockly.utils.object'], {'lang': 'es5'});
goog.addDependency('../../core/renderers/geras/drawer.js', ['Blockly.geras.Drawer'], ['Blockly.blockRendering.ConstantProvider', 'Blockly.blockRendering.Drawer', 'Blockly.geras.Highlighter', 'Blockly.geras.RenderInfo', 'Blockly.utils.object', 'Blockly.utils.svgPaths'], {});
goog.addDependency('../../core/renderers/geras/drawer.js', ['Blockly.geras.Drawer'], ['Blockly.blockRendering.Drawer', 'Blockly.geras.Highlighter', 'Blockly.geras.RenderInfo', 'Blockly.utils.object', 'Blockly.utils.svgPaths'], {});
goog.addDependency('../../core/renderers/geras/highlight_constants.js', ['Blockly.geras.HighlightConstantProvider'], ['Blockly.blockRendering.ConstantProvider', 'Blockly.utils.svgPaths'], {'lang': 'es5'});
goog.addDependency('../../core/renderers/geras/highlighter.js', ['Blockly.geras.Highlighter'], ['Blockly.blockRendering.BottomRow', 'Blockly.blockRendering.InputRow', 'Blockly.blockRendering.Measurable', 'Blockly.blockRendering.RenderInfo', 'Blockly.blockRendering.Row', 'Blockly.blockRendering.SpacerRow', 'Blockly.blockRendering.TopRow', 'Blockly.blockRendering.Types', 'Blockly.utils.svgPaths'], {});
goog.addDependency('../../core/renderers/geras/info.js', ['Blockly.geras', 'Blockly.geras.RenderInfo'], ['Blockly.blockRendering.BottomRow', 'Blockly.blockRendering.BottomRow', 'Blockly.blockRendering.ExternalValueInput', 'Blockly.blockRendering.InputRow', 'Blockly.blockRendering.InputRow', 'Blockly.blockRendering.Measurable', 'Blockly.blockRendering.Measurable', 'Blockly.blockRendering.NextConnection', 'Blockly.blockRendering.NextConnection', 'Blockly.blockRendering.OutputConnection', 'Blockly.blockRendering.OutputConnection', 'Blockly.blockRendering.PreviousConnection', 'Blockly.blockRendering.PreviousConnection', 'Blockly.blockRendering.RenderInfo', 'Blockly.blockRendering.Types', 'Blockly.constants', 'Blockly.geras.InlineInput', 'Blockly.geras.StatementInput', 'Blockly.utils.object'], {});
goog.addDependency('../../core/renderers/geras/measurables/inputs.js', ['Blockly.geras.InlineInput', 'Blockly.geras.StatementInput'], ['Blockly.utils.object'], {});
goog.addDependency('../../core/renderers/geras/path_object.js', ['Blockly.geras.PathObject'], ['Blockly.Theme', 'Blockly.blockRendering.PathObject', 'Blockly.geras.ConstantProvider', 'Blockly.utils.Svg', 'Blockly.utils.dom', 'Blockly.utils.object'], {});
goog.addDependency('../../core/renderers/geras/highlighter.js', ['Blockly.geras.Highlighter'], ['Blockly.blockRendering.Types', 'Blockly.utils.svgPaths'], {});
goog.addDependency('../../core/renderers/geras/info.js', ['Blockly.geras', 'Blockly.geras.RenderInfo'], ['Blockly.blockRendering.ExternalValueInput', 'Blockly.blockRendering.InRowSpacer', 'Blockly.blockRendering.InputRow', 'Blockly.blockRendering.RenderInfo', 'Blockly.blockRendering.Types', 'Blockly.constants', 'Blockly.geras.InlineInput', 'Blockly.geras.StatementInput', 'Blockly.inputTypes', 'Blockly.utils.object'], {});
goog.addDependency('../../core/renderers/geras/measurables/inputs.js', ['Blockly.geras.InlineInput', 'Blockly.geras.StatementInput'], ['Blockly.blockRendering.InlineInput', 'Blockly.blockRendering.StatementInput', 'Blockly.utils.object'], {});
goog.addDependency('../../core/renderers/geras/path_object.js', ['Blockly.geras.PathObject'], ['Blockly.Theme', 'Blockly.blockRendering.PathObject', 'Blockly.geras.ConstantProvider', 'Blockly.utils.Svg', 'Blockly.utils.colour', 'Blockly.utils.dom', 'Blockly.utils.object'], {});
goog.addDependency('../../core/renderers/geras/renderer.js', ['Blockly.geras.Renderer'], ['Blockly.blockRendering', 'Blockly.blockRendering.Renderer', 'Blockly.geras.ConstantProvider', 'Blockly.geras.Drawer', 'Blockly.geras.HighlightConstantProvider', 'Blockly.geras.PathObject', 'Blockly.geras.RenderInfo', 'Blockly.utils.object'], {});
goog.addDependency('../../core/renderers/measurables/base.js', ['Blockly.blockRendering.Measurable'], ['Blockly.blockRendering.Types'], {});
goog.addDependency('../../core/renderers/measurables/connections.js', ['Blockly.blockRendering.Connection', 'Blockly.blockRendering.NextConnection', 'Blockly.blockRendering.OutputConnection', 'Blockly.blockRendering.PreviousConnection'], ['Blockly.blockRendering.Measurable', 'Blockly.blockRendering.Types', 'Blockly.utils.object'], {});
goog.addDependency('../../core/renderers/measurables/inputs.js', ['Blockly.blockRendering.ExternalValueInput', 'Blockly.blockRendering.InlineInput', 'Blockly.blockRendering.InputConnection', 'Blockly.blockRendering.StatementInput'], ['Blockly.blockRendering.Connection', 'Blockly.blockRendering.Measurable', 'Blockly.blockRendering.Types', 'Blockly.utils.object'], {});
goog.addDependency('../../core/renderers/measurables/inputs.js', ['Blockly.blockRendering.ExternalValueInput', 'Blockly.blockRendering.InlineInput', 'Blockly.blockRendering.InputConnection', 'Blockly.blockRendering.StatementInput'], ['Blockly.blockRendering.Connection', 'Blockly.blockRendering.Types', 'Blockly.utils.object'], {});
goog.addDependency('../../core/renderers/measurables/row_elements.js', ['Blockly.blockRendering.Field', 'Blockly.blockRendering.Hat', 'Blockly.blockRendering.Icon', 'Blockly.blockRendering.InRowSpacer', 'Blockly.blockRendering.JaggedEdge', 'Blockly.blockRendering.RoundCorner', 'Blockly.blockRendering.SquareCorner'], ['Blockly.blockRendering.Measurable', 'Blockly.blockRendering.Types', 'Blockly.utils.object'], {});
goog.addDependency('../../core/renderers/measurables/rows.js', ['Blockly.blockRendering.BottomRow', 'Blockly.blockRendering.InputRow', 'Blockly.blockRendering.Row', 'Blockly.blockRendering.SpacerRow', 'Blockly.blockRendering.TopRow'], ['Blockly.blockRendering.InRowSpacer', 'Blockly.blockRendering.InputConnection', 'Blockly.blockRendering.Measurable', 'Blockly.blockRendering.NextConnection', 'Blockly.blockRendering.PreviousConnection', 'Blockly.blockRendering.Types', 'Blockly.utils.object'], {});
goog.addDependency('../../core/renderers/measurables/types.js', ['Blockly.blockRendering.Types'], [], {});
@@ -142,22 +148,22 @@ goog.addDependency('../../core/renderers/minimalist/constants.js', ['Blockly.min
goog.addDependency('../../core/renderers/minimalist/drawer.js', ['Blockly.minimalist.Drawer'], ['Blockly.blockRendering.Drawer', 'Blockly.minimalist.RenderInfo', 'Blockly.utils.object'], {});
goog.addDependency('../../core/renderers/minimalist/info.js', ['Blockly.minimalist', 'Blockly.minimalist.RenderInfo'], ['Blockly.utils.object'], {});
goog.addDependency('../../core/renderers/minimalist/renderer.js', ['Blockly.minimalist.Renderer'], ['Blockly.blockRendering', 'Blockly.blockRendering.Renderer', 'Blockly.minimalist.ConstantProvider', 'Blockly.minimalist.Drawer', 'Blockly.minimalist.RenderInfo', 'Blockly.utils.object'], {});
goog.addDependency('../../core/renderers/thrasos/info.js', ['Blockly.thrasos', 'Blockly.thrasos.RenderInfo'], ['Blockly.blockRendering.BottomRow', 'Blockly.blockRendering.ExternalValueInput', 'Blockly.blockRendering.InlineInput', 'Blockly.blockRendering.InputRow', 'Blockly.blockRendering.Measurable', 'Blockly.blockRendering.NextConnection', 'Blockly.blockRendering.OutputConnection', 'Blockly.blockRendering.PreviousConnection', 'Blockly.blockRendering.RenderInfo', 'Blockly.blockRendering.Row', 'Blockly.blockRendering.SpacerRow', 'Blockly.blockRendering.StatementInput', 'Blockly.blockRendering.TopRow', 'Blockly.blockRendering.Types', 'Blockly.utils.object'], {});
goog.addDependency('../../core/renderers/thrasos/info.js', ['Blockly.thrasos', 'Blockly.thrasos.RenderInfo'], ['Blockly.blockRendering.InRowSpacer', 'Blockly.blockRendering.RenderInfo', 'Blockly.blockRendering.Types', 'Blockly.utils.object'], {});
goog.addDependency('../../core/renderers/thrasos/renderer.js', ['Blockly.thrasos.Renderer'], ['Blockly.blockRendering', 'Blockly.blockRendering.Renderer', 'Blockly.thrasos.RenderInfo', 'Blockly.utils.object'], {});
goog.addDependency('../../core/renderers/zelos/constants.js', ['Blockly.zelos.ConstantProvider'], ['Blockly.blockRendering.ConstantProvider', 'Blockly.constants', 'Blockly.utils.Svg', 'Blockly.utils.dom', 'Blockly.utils.object', 'Blockly.utils.svgPaths'], {'lang': 'es5'});
goog.addDependency('../../core/renderers/zelos/drawer.js', ['Blockly.zelos.Drawer'], ['Blockly.blockRendering.ConstantProvider', 'Blockly.blockRendering.Drawer', 'Blockly.blockRendering.Types', 'Blockly.utils.object', 'Blockly.zelos.RenderInfo'], {});
goog.addDependency('../../core/renderers/zelos/info.js', ['Blockly.zelos', 'Blockly.zelos.RenderInfo'], ['Blockly.blockRendering.BottomRow', 'Blockly.blockRendering.ExternalValueInput', 'Blockly.blockRendering.InlineInput', 'Blockly.blockRendering.InputRow', 'Blockly.blockRendering.Measurable', 'Blockly.blockRendering.NextConnection', 'Blockly.blockRendering.OutputConnection', 'Blockly.blockRendering.PreviousConnection', 'Blockly.blockRendering.RenderInfo', 'Blockly.blockRendering.RoundCorner', 'Blockly.blockRendering.Row', 'Blockly.blockRendering.SpacerRow', 'Blockly.blockRendering.SquareCorner', 'Blockly.blockRendering.TopRow', 'Blockly.blockRendering.Types', 'Blockly.constants', 'Blockly.utils.object', 'Blockly.zelos.BottomRow', 'Blockly.zelos.RightConnectionShape', 'Blockly.zelos.StatementInput', 'Blockly.zelos.TopRow'], {});
goog.addDependency('../../core/renderers/zelos/constants.js', ['Blockly.zelos.ConstantProvider'], ['Blockly.blockRendering.ConstantProvider', 'Blockly.connectionTypes', 'Blockly.constants', 'Blockly.utils.Svg', 'Blockly.utils.colour', 'Blockly.utils.dom', 'Blockly.utils.object', 'Blockly.utils.svgPaths'], {'lang': 'es5'});
goog.addDependency('../../core/renderers/zelos/drawer.js', ['Blockly.zelos.Drawer'], ['Blockly.blockRendering.Drawer', 'Blockly.utils.object', 'Blockly.utils.svgPaths', 'Blockly.zelos.RenderInfo'], {});
goog.addDependency('../../core/renderers/zelos/info.js', ['Blockly.zelos', 'Blockly.zelos.RenderInfo'], ['Blockly.FieldImage', 'Blockly.FieldLabel', 'Blockly.FieldTextInput', 'Blockly.blockRendering.InRowSpacer', 'Blockly.blockRendering.Measurable', 'Blockly.blockRendering.RenderInfo', 'Blockly.blockRendering.Types', 'Blockly.constants', 'Blockly.inputTypes', 'Blockly.utils.object', 'Blockly.zelos.BottomRow', 'Blockly.zelos.RightConnectionShape', 'Blockly.zelos.TopRow'], {});
goog.addDependency('../../core/renderers/zelos/marker_svg.js', ['Blockly.zelos.MarkerSvg'], ['Blockly.blockRendering.MarkerSvg', 'Blockly.utils.Svg', 'Blockly.utils.dom'], {});
goog.addDependency('../../core/renderers/zelos/measurables/inputs.js', ['Blockly.zelos.StatementInput'], ['Blockly.blockRendering.StatementInput', 'Blockly.utils.object'], {});
goog.addDependency('../../core/renderers/zelos/measurables/row_elements.js', ['Blockly.zelos.RightConnectionShape'], ['Blockly.blockRendering.Measurable', 'Blockly.blockRendering.Types', 'Blockly.utils.object'], {});
goog.addDependency('../../core/renderers/zelos/measurables/rows.js', ['Blockly.zelos.BottomRow', 'Blockly.zelos.TopRow'], ['Blockly.blockRendering.BottomRow', 'Blockly.blockRendering.SpacerRow', 'Blockly.blockRendering.TopRow', 'Blockly.utils.object'], {});
goog.addDependency('../../core/renderers/zelos/measurables/rows.js', ['Blockly.zelos.BottomRow', 'Blockly.zelos.TopRow'], ['Blockly.blockRendering.BottomRow', 'Blockly.blockRendering.TopRow', 'Blockly.utils.object'], {});
goog.addDependency('../../core/renderers/zelos/path_object.js', ['Blockly.zelos.PathObject'], ['Blockly.blockRendering.PathObject', 'Blockly.utils.Svg', 'Blockly.utils.dom', 'Blockly.utils.object', 'Blockly.zelos.ConstantProvider'], {});
goog.addDependency('../../core/renderers/zelos/renderer.js', ['Blockly.zelos.Renderer'], ['Blockly.InsertionMarkerManager', 'Blockly.blockRendering', 'Blockly.blockRendering.Renderer', 'Blockly.constants', 'Blockly.utils.object', 'Blockly.zelos.ConstantProvider', 'Blockly.zelos.Drawer', 'Blockly.zelos.MarkerSvg', 'Blockly.zelos.PathObject', 'Blockly.zelos.RenderInfo'], {});
goog.addDependency('../../core/requires.js', ['Blockly.requires'], ['Blockly', 'Blockly.Comment', 'Blockly.FieldAngle', 'Blockly.FieldCheckbox', 'Blockly.FieldColour', 'Blockly.FieldDropdown', 'Blockly.FieldImage', 'Blockly.FieldLabelSerializable', 'Blockly.FieldMultilineInput', 'Blockly.FieldNumber', 'Blockly.FieldTextInput', 'Blockly.FieldVariable', 'Blockly.FlyoutButton', 'Blockly.Generator', 'Blockly.HorizontalFlyout', 'Blockly.Mutator', 'Blockly.Themes.Classic', 'Blockly.Themes.Dark', 'Blockly.Themes.Deuteranopia', 'Blockly.Themes.HighContrast', 'Blockly.Themes.Tritanopia', 'Blockly.Toolbox', 'Blockly.Trashcan', 'Blockly.VariablesDynamic', 'Blockly.VerticalFlyout', 'Blockly.Warning', 'Blockly.ZoomControls', 'Blockly.geras.Renderer', 'Blockly.thrasos.Renderer', 'Blockly.zelos.Renderer'], {});
goog.addDependency('../../core/scrollbar.js', ['Blockly.Scrollbar', 'Blockly.ScrollbarPair'], ['Blockly.Touch', 'Blockly.utils', 'Blockly.utils.Coordinate', 'Blockly.utils.Metrics', 'Blockly.utils.Svg', 'Blockly.utils.dom'], {});
goog.addDependency('../../core/shortcut_items.js', ['Blockly.ShortcutItems'], ['Blockly.utils.KeyCodes'], {});
goog.addDependency('../../core/shortcut_registry.js', ['Blockly.ShortcutRegistry'], ['Blockly.ShortcutItems', 'Blockly.navigation', 'Blockly.utils.object'], {});
goog.addDependency('../../core/theme.js', ['Blockly.Theme'], ['Blockly.registry', 'Blockly.utils', 'Blockly.utils.colour', 'Blockly.utils.object'], {});
goog.addDependency('../../core/renderers/zelos/renderer.js', ['Blockly.zelos.Renderer'], ['Blockly.InsertionMarkerManager', 'Blockly.blockRendering', 'Blockly.blockRendering.Renderer', 'Blockly.connectionTypes', 'Blockly.constants', 'Blockly.utils.object', 'Blockly.zelos.ConstantProvider', 'Blockly.zelos.Drawer', 'Blockly.zelos.MarkerSvg', 'Blockly.zelos.PathObject', 'Blockly.zelos.RenderInfo'], {});
goog.addDependency('../../core/requires.js', ['Blockly.requires'], ['Blockly', 'Blockly.Comment', 'Blockly.ContextMenuItems', 'Blockly.FieldAngle', 'Blockly.FieldCheckbox', 'Blockly.FieldColour', 'Blockly.FieldDropdown', 'Blockly.FieldImage', 'Blockly.FieldLabelSerializable', 'Blockly.FieldMultilineInput', 'Blockly.FieldNumber', 'Blockly.FieldTextInput', 'Blockly.FieldVariable', 'Blockly.FlyoutButton', 'Blockly.Generator', 'Blockly.HorizontalFlyout', 'Blockly.Mutator', 'Blockly.ShortcutItems', 'Blockly.Themes.Classic', 'Blockly.Themes.Dark', 'Blockly.Themes.Deuteranopia', 'Blockly.Themes.HighContrast', 'Blockly.Themes.Tritanopia', 'Blockly.Toolbox', 'Blockly.Trashcan', 'Blockly.VariablesDynamic', 'Blockly.VerticalFlyout', 'Blockly.Warning', 'Blockly.ZoomControls', 'Blockly.geras.Renderer', 'Blockly.thrasos.Renderer', 'Blockly.zelos.Renderer'], {});
goog.addDependency('../../core/scrollbar.js', ['Blockly.Scrollbar', 'Blockly.ScrollbarPair'], ['Blockly.Events', 'Blockly.Touch', 'Blockly.browserEvents', 'Blockly.utils', 'Blockly.utils.Coordinate', 'Blockly.utils.Metrics', 'Blockly.utils.Svg', 'Blockly.utils.dom'], {});
goog.addDependency('../../core/shortcut_items.js', ['Blockly.ShortcutItems'], ['Blockly.Gesture', 'Blockly.ShortcutRegistry', 'Blockly.utils.KeyCodes'], {});
goog.addDependency('../../core/shortcut_registry.js', ['Blockly.ShortcutRegistry'], ['Blockly.utils.KeyCodes', 'Blockly.utils.object'], {});
goog.addDependency('../../core/theme.js', ['Blockly.Theme'], ['Blockly.registry', 'Blockly.utils', 'Blockly.utils.object'], {});
goog.addDependency('../../core/theme/classic.js', ['Blockly.Themes.Classic'], ['Blockly.Theme'], {});
goog.addDependency('../../core/theme/dark.js', ['Blockly.Themes.Dark'], ['Blockly.Theme'], {});
goog.addDependency('../../core/theme/deuteranopia.js', ['Blockly.Themes.Deuteranopia'], ['Blockly.Theme'], {});
@@ -169,12 +175,12 @@ goog.addDependency('../../core/theme_manager.js', ['Blockly.ThemeManager'], ['Bl
goog.addDependency('../../core/toolbox/category.js', ['Blockly.ToolboxCategory'], ['Blockly.ToolboxItem', 'Blockly.registry', 'Blockly.utils', 'Blockly.utils.aria', 'Blockly.utils.dom', 'Blockly.utils.object', 'Blockly.utils.toolbox'], {'lang': 'es5'});
goog.addDependency('../../core/toolbox/collapsible_category.js', ['Blockly.CollapsibleToolboxCategory'], ['Blockly.ToolboxCategory', 'Blockly.ToolboxItem', 'Blockly.ToolboxSeparator', 'Blockly.registry', 'Blockly.utils.aria', 'Blockly.utils.dom', 'Blockly.utils.object', 'Blockly.utils.toolbox'], {});
goog.addDependency('../../core/toolbox/separator.js', ['Blockly.ToolboxSeparator'], ['Blockly.ToolboxItem', 'Blockly.registry', 'Blockly.utils.dom'], {'lang': 'es5'});
goog.addDependency('../../core/toolbox/toolbox.js', ['Blockly.Toolbox'], ['Blockly.CollapsibleToolboxCategory', 'Blockly.Css', 'Blockly.Events', 'Blockly.Events.ToolboxItemSelect', 'Blockly.Touch', 'Blockly.constants', 'Blockly.navigation', 'Blockly.registry', 'Blockly.utils', 'Blockly.utils.Rect', 'Blockly.utils.aria', 'Blockly.utils.dom', 'Blockly.utils.toolbox'], {'lang': 'es5'});
goog.addDependency('../../core/toolbox/toolbox.js', ['Blockly.Toolbox'], ['Blockly.CollapsibleToolboxCategory', 'Blockly.Css', 'Blockly.Events', 'Blockly.Events.ToolboxItemSelect', 'Blockly.Touch', 'Blockly.browserEvents', 'Blockly.constants', 'Blockly.registry', 'Blockly.utils', 'Blockly.utils.Rect', 'Blockly.utils.aria', 'Blockly.utils.dom', 'Blockly.utils.toolbox'], {'lang': 'es5'});
goog.addDependency('../../core/toolbox/toolbox_item.js', ['Blockly.ToolboxItem'], [], {});
goog.addDependency('../../core/tooltip.js', ['Blockly.Tooltip'], ['Blockly.utils.string'], {});
goog.addDependency('../../core/tooltip.js', ['Blockly.Tooltip'], ['Blockly.browserEvents', 'Blockly.utils.string'], {});
goog.addDependency('../../core/touch.js', ['Blockly.Touch'], ['Blockly.constants', 'Blockly.utils', 'Blockly.utils.global', 'Blockly.utils.string'], {});
goog.addDependency('../../core/touch_gesture.js', ['Blockly.TouchGesture'], ['Blockly.Gesture', 'Blockly.utils', 'Blockly.utils.Coordinate', 'Blockly.utils.object'], {});
goog.addDependency('../../core/trashcan.js', ['Blockly.Trashcan'], ['Blockly.Events.TrashcanOpen', 'Blockly.Scrollbar', 'Blockly.Xml', 'Blockly.constants', 'Blockly.utils.Rect', 'Blockly.utils.Svg', 'Blockly.utils.dom', 'Blockly.utils.toolbox'], {});
goog.addDependency('../../core/touch_gesture.js', ['Blockly.TouchGesture'], ['Blockly.Gesture', 'Blockly.browserEvents', 'Blockly.utils', 'Blockly.utils.Coordinate', 'Blockly.utils.object'], {});
goog.addDependency('../../core/trashcan.js', ['Blockly.Trashcan'], ['Blockly.Events', 'Blockly.Events.TrashcanOpen', 'Blockly.IPositionable', 'Blockly.Scrollbar', 'Blockly.Xml', 'Blockly.browserEvents', 'Blockly.constants', 'Blockly.registry', 'Blockly.utils.Rect', 'Blockly.utils.Svg', 'Blockly.utils.dom', 'Blockly.utils.math', 'Blockly.utils.toolbox'], {'lang': 'es5'});
goog.addDependency('../../core/utils.js', ['Blockly.utils'], ['Blockly.Msg', 'Blockly.constants', 'Blockly.utils.Coordinate', 'Blockly.utils.Rect', 'Blockly.utils.colour', 'Blockly.utils.global', 'Blockly.utils.string', 'Blockly.utils.style', 'Blockly.utils.userAgent'], {});
goog.addDependency('../../core/utils/aria.js', ['Blockly.utils.aria'], [], {});
goog.addDependency('../../core/utils/colour.js', ['Blockly.utils.colour'], [], {});
@@ -193,7 +199,7 @@ goog.addDependency('../../core/utils/string.js', ['Blockly.utils.string'], [], {
goog.addDependency('../../core/utils/style.js', ['Blockly.utils.style'], ['Blockly.utils.Coordinate', 'Blockly.utils.Size'], {});
goog.addDependency('../../core/utils/svg.js', ['Blockly.utils.Svg'], [], {});
goog.addDependency('../../core/utils/svg_paths.js', ['Blockly.utils.svgPaths'], [], {});
goog.addDependency('../../core/utils/toolbox.js', ['Blockly.utils.toolbox'], ['Blockly.constants'], {});
goog.addDependency('../../core/utils/toolbox.js', ['Blockly.utils.toolbox'], ['Blockly.Xml', 'Blockly.constants'], {});
goog.addDependency('../../core/utils/useragent.js', ['Blockly.utils.userAgent'], ['Blockly.utils.global'], {});
goog.addDependency('../../core/utils/xml.js', ['Blockly.utils.xml'], [], {});
goog.addDependency('../../core/variable_map.js', ['Blockly.VariableMap'], ['Blockly.Events', 'Blockly.Events.VarDelete', 'Blockly.Events.VarRename', 'Blockly.Msg', 'Blockly.utils', 'Blockly.utils.object'], {});
@@ -201,17 +207,17 @@ goog.addDependency('../../core/variable_model.js', ['Blockly.VariableModel'], ['
goog.addDependency('../../core/variables.js', ['Blockly.Variables'], ['Blockly.Blocks', 'Blockly.Msg', 'Blockly.VariableModel', 'Blockly.Xml', 'Blockly.constants', 'Blockly.utils', 'Blockly.utils.xml'], {});
goog.addDependency('../../core/variables_dynamic.js', ['Blockly.VariablesDynamic'], ['Blockly.Blocks', 'Blockly.Msg', 'Blockly.VariableModel', 'Blockly.Variables', 'Blockly.utils.xml'], {});
goog.addDependency('../../core/warning.js', ['Blockly.Warning'], ['Blockly.Bubble', 'Blockly.Events', 'Blockly.Events.BubbleOpen', 'Blockly.Icon', 'Blockly.utils.Svg', 'Blockly.utils.dom', 'Blockly.utils.object'], {});
goog.addDependency('../../core/widgetdiv.js', ['Blockly.WidgetDiv'], ['Blockly.utils.style'], {});
goog.addDependency('../../core/workspace.js', ['Blockly.Workspace'], ['Blockly.ConnectionChecker', 'Blockly.Events', 'Blockly.Options', 'Blockly.VariableMap', 'Blockly.utils', 'Blockly.utils.math'], {});
goog.addDependency('../../core/widgetdiv.js', ['Blockly.WidgetDiv'], ['Blockly.utils.dom'], {});
goog.addDependency('../../core/workspace.js', ['Blockly.Workspace'], ['Blockly.ConnectionChecker', 'Blockly.Events', 'Blockly.Options', 'Blockly.VariableMap', 'Blockly.registry', 'Blockly.utils', 'Blockly.utils.math'], {});
goog.addDependency('../../core/workspace_audio.js', ['Blockly.WorkspaceAudio'], ['Blockly.constants', 'Blockly.utils', 'Blockly.utils.global', 'Blockly.utils.userAgent'], {'lang': 'es5'});
goog.addDependency('../../core/workspace_comment.js', ['Blockly.WorkspaceComment'], ['Blockly.Events', 'Blockly.Events.CommentChange', 'Blockly.Events.CommentCreate', 'Blockly.Events.CommentDelete', 'Blockly.Events.CommentMove', 'Blockly.utils', 'Blockly.utils.Coordinate', 'Blockly.utils.xml'], {});
goog.addDependency('../../core/workspace_comment_render_svg.js', ['Blockly.WorkspaceCommentSvg.render'], ['Blockly.utils', 'Blockly.utils.Coordinate', 'Blockly.utils.Svg', 'Blockly.utils.dom'], {});
goog.addDependency('../../core/workspace_comment_svg.js', ['Blockly.WorkspaceCommentSvg'], ['Blockly.Css', 'Blockly.Events', 'Blockly.Events.CommentCreate', 'Blockly.Events.CommentDelete', 'Blockly.Events.CommentMove', 'Blockly.Events.Selected', 'Blockly.WorkspaceComment', 'Blockly.utils', 'Blockly.utils.Coordinate', 'Blockly.utils.Rect', 'Blockly.utils.Svg', 'Blockly.utils.dom', 'Blockly.utils.object'], {});
goog.addDependency('../../core/workspace_drag_surface_svg.js', ['Blockly.WorkspaceDragSurfaceSvg'], ['Blockly.utils', 'Blockly.utils.Svg', 'Blockly.utils.dom'], {});
goog.addDependency('../../core/workspace_dragger.js', ['Blockly.WorkspaceDragger'], ['Blockly.utils.Coordinate'], {});
goog.addDependency('../../core/workspace_svg.js', ['Blockly.WorkspaceSvg'], ['Blockly.BlockSvg', 'Blockly.ConnectionDB', 'Blockly.ContextMenuRegistry', 'Blockly.Events', 'Blockly.Events.BlockCreate', 'Blockly.Events.ThemeChange', 'Blockly.Events.ViewportChange', 'Blockly.Gesture', 'Blockly.Grid', 'Blockly.MarkerManager', 'Blockly.Msg', 'Blockly.Options', 'Blockly.ThemeManager', 'Blockly.Themes.Classic', 'Blockly.TouchGesture', 'Blockly.Workspace', 'Blockly.WorkspaceAudio', 'Blockly.WorkspaceDragSurfaceSvg', 'Blockly.Xml', 'Blockly.blockRendering', 'Blockly.constants', 'Blockly.navigation', 'Blockly.registry', 'Blockly.utils', 'Blockly.utils.Coordinate', 'Blockly.utils.Metrics', 'Blockly.utils.Rect', 'Blockly.utils.Svg', 'Blockly.utils.dom', 'Blockly.utils.object', 'Blockly.utils.toolbox'], {});
goog.addDependency('../../core/xml.js', ['Blockly.Xml'], ['Blockly.Events', 'Blockly.Events.BlockCreate', 'Blockly.Events.FinishedLoading', 'Blockly.Events.VarCreate', 'Blockly.constants', 'Blockly.utils', 'Blockly.utils.dom', 'Blockly.utils.global', 'Blockly.utils.xml'], {});
goog.addDependency('../../core/zoom_controls.js', ['Blockly.ZoomControls'], ['Blockly.Css', 'Blockly.Scrollbar', 'Blockly.Touch', 'Blockly.constants', 'Blockly.utils.Svg', 'Blockly.utils.dom'], {'lang': 'es5'});
goog.addDependency('../../core/workspace_svg.js', ['Blockly.WorkspaceSvg'], ['Blockly.BlockSvg', 'Blockly.ConnectionDB', 'Blockly.ContextMenu', 'Blockly.ContextMenuRegistry', 'Blockly.Events', 'Blockly.Events.BlockCreate', 'Blockly.Events.ThemeChange', 'Blockly.Events.ViewportChange', 'Blockly.Gesture', 'Blockly.Grid', 'Blockly.MarkerManager', 'Blockly.MetricsManager', 'Blockly.Msg', 'Blockly.Options', 'Blockly.PluginManager', 'Blockly.ThemeManager', 'Blockly.Themes.Classic', 'Blockly.TouchGesture', 'Blockly.Workspace', 'Blockly.WorkspaceAudio', 'Blockly.WorkspaceDragSurfaceSvg', 'Blockly.Xml', 'Blockly.blockRendering', 'Blockly.browserEvents', 'Blockly.constants', 'Blockly.registry', 'Blockly.utils', 'Blockly.utils.Coordinate', 'Blockly.utils.Metrics', 'Blockly.utils.Rect', 'Blockly.utils.Size', 'Blockly.utils.Svg', 'Blockly.utils.dom', 'Blockly.utils.object', 'Blockly.utils.toolbox'], {'lang': 'es5'});
goog.addDependency('../../core/xml.js', ['Blockly.Xml'], ['Blockly.Events', 'Blockly.constants', 'Blockly.inputTypes', 'Blockly.utils', 'Blockly.utils.Size', 'Blockly.utils.dom', 'Blockly.utils.xml'], {});
goog.addDependency('../../core/zoom_controls.js', ['Blockly.ZoomControls'], ['Blockly.Css', 'Blockly.Events', 'Blockly.Events.Click', 'Blockly.IPositionable', 'Blockly.Scrollbar', 'Blockly.Touch', 'Blockly.browserEvents', 'Blockly.constants', 'Blockly.utils.Rect', 'Blockly.utils.Svg', 'Blockly.utils.dom', 'Blockly.utils.toolbox'], {'lang': 'es5'});
goog.addDependency("base.js", [], []);
// Load Blockly.

File diff suppressed because one or more lines are too long

View File

@@ -15,25 +15,36 @@ goog.provide('Blockly.Block');
goog.require('Blockly.ASTNode');
goog.require('Blockly.Blocks');
goog.require('Blockly.Connection');
goog.require('Blockly.connectionTypes');
/** @suppress {extraRequire} */
goog.require('Blockly.constants');
goog.require('Blockly.Events');
/** @suppress {extraRequire} */
goog.require('Blockly.Events.BlockChange');
/** @suppress {extraRequire} */
goog.require('Blockly.Events.BlockCreate');
/** @suppress {extraRequire} */
goog.require('Blockly.Events.BlockDelete');
/** @suppress {extraRequire} */
goog.require('Blockly.Events.BlockMove');
goog.require('Blockly.Extensions');
goog.require('Blockly.fieldRegistry');
goog.require('Blockly.Input');
goog.require('Blockly.navigation');
goog.require('Blockly.inputTypes');
goog.require('Blockly.Tooltip');
goog.require('Blockly.utils');
goog.require('Blockly.utils.deprecation');
goog.require('Blockly.utils.Coordinate');
goog.require('Blockly.utils.object');
goog.require('Blockly.utils.string');
goog.require('Blockly.utils.Size');
goog.require('Blockly.Workspace');
goog.requireType('Blockly.Comment');
goog.requireType('Blockly.Events.Abstract');
goog.requireType('Blockly.Field');
goog.requireType('Blockly.IASTNodeLocation');
goog.requireType('Blockly.Mutator');
goog.requireType('Blockly.utils.Size');
goog.requireType('Blockly.VariableModel');
/**
@@ -220,7 +231,8 @@ Blockly.Block = function(workspace, prototypeName, opt_id) {
// Fire a create event.
if (Blockly.Events.isEnabled()) {
Blockly.Events.fire(new Blockly.Events.BlockCreate(this));
Blockly.Events.fire(new (Blockly.Events.get(Blockly.Events.BLOCK_CREATE))(
this));
}
} finally {
@@ -254,12 +266,13 @@ Blockly.Block.CommentModel;
* The language-neutral id given to the collapsed input.
* @const {string}
*/
Blockly.Block.COLLAPSED_INPUT_NAME = '_TEMP_COLLAPSED_INPUT';
Blockly.Block.COLLAPSED_INPUT_NAME = Blockly.constants.COLLAPSED_INPUT_NAME;
/**
* The language-neutral id given to the collapsed field.
* @const {string}
*/
Blockly.Block.COLLAPSED_FIELD_NAME = '_TEMP_COLLAPSED_FIELD';
Blockly.Block.COLLAPSED_FIELD_NAME = Blockly.constants.COLLAPSED_FIELD_NAME;
/**
* Optional text data that round-trips between blocks and XML.
@@ -359,7 +372,8 @@ Blockly.Block.prototype.dispose = function(healStack) {
this.unplug(healStack);
if (Blockly.Events.isEnabled()) {
Blockly.Events.fire(new Blockly.Events.BlockDelete(this));
Blockly.Events.fire(new (Blockly.Events.get(Blockly.Events.BLOCK_DELETE))(
this));
}
Blockly.Events.disable();
@@ -491,7 +505,8 @@ Blockly.Block.prototype.getOnlyValueConnection_ = function() {
var connection = null;
for (var i = 0; i < this.inputList.length; i++) {
var thisConnection = this.inputList[i].connection;
if (thisConnection && thisConnection.type == Blockly.INPUT_VALUE &&
if (thisConnection &&
thisConnection.type == Blockly.connectionTypes.INPUT_VALUE &&
thisConnection.targetConnection) {
if (connection) {
return null; // More than one value input found.
@@ -652,7 +667,8 @@ Blockly.Block.prototype.getPreviousBlock = function() {
*/
Blockly.Block.prototype.getFirstStatementConnection = function() {
for (var i = 0, input; (input = this.inputList[i]); i++) {
if (input.connection && input.connection.type == Blockly.NEXT_STATEMENT) {
if (input.connection &&
input.connection.type == Blockly.connectionTypes.NEXT_STATEMENT) {
return input.connection;
}
}
@@ -1132,7 +1148,7 @@ Blockly.Block.prototype.setPreviousStatement = function(newBoolean, opt_check) {
'connection.');
}
this.previousConnection =
this.makeConnection_(Blockly.PREVIOUS_STATEMENT);
this.makeConnection_(Blockly.connectionTypes.PREVIOUS_STATEMENT);
}
this.previousConnection.setCheck(opt_check);
} else {
@@ -1159,7 +1175,8 @@ Blockly.Block.prototype.setNextStatement = function(newBoolean, opt_check) {
opt_check = null;
}
if (!this.nextConnection) {
this.nextConnection = this.makeConnection_(Blockly.NEXT_STATEMENT);
this.nextConnection =
this.makeConnection_(Blockly.connectionTypes.NEXT_STATEMENT);
}
this.nextConnection.setCheck(opt_check);
} else {
@@ -1191,7 +1208,8 @@ Blockly.Block.prototype.setOutput = function(newBoolean, opt_check) {
throw Error('Remove previous connection prior to adding output ' +
'connection.');
}
this.outputConnection = this.makeConnection_(Blockly.OUTPUT_VALUE);
this.outputConnection =
this.makeConnection_(Blockly.connectionTypes.OUTPUT_VALUE);
}
this.outputConnection.setCheck(opt_check);
} else {
@@ -1211,7 +1229,7 @@ Blockly.Block.prototype.setOutput = function(newBoolean, opt_check) {
*/
Blockly.Block.prototype.setInputsInline = function(newBoolean) {
if (this.inputsInline != newBoolean) {
Blockly.Events.fire(new Blockly.Events.BlockChange(
Blockly.Events.fire(new (Blockly.Events.get(Blockly.Events.BLOCK_CHANGE))(
this, 'inline', null, this.inputsInline, newBoolean));
this.inputsInline = newBoolean;
}
@@ -1228,15 +1246,15 @@ Blockly.Block.prototype.getInputsInline = function() {
}
// Not defined explicitly. Figure out what would look best.
for (var i = 1; i < this.inputList.length; i++) {
if (this.inputList[i - 1].type == Blockly.DUMMY_INPUT &&
this.inputList[i].type == Blockly.DUMMY_INPUT) {
if (this.inputList[i - 1].type == Blockly.inputTypes.DUMMY &&
this.inputList[i].type == Blockly.inputTypes.DUMMY) {
// Two dummy inputs in a row. Don't inline them.
return false;
}
}
for (var i = 1; i < this.inputList.length; i++) {
if (this.inputList[i - 1].type == Blockly.INPUT_VALUE &&
this.inputList[i].type == Blockly.DUMMY_INPUT) {
if (this.inputList[i - 1].type == Blockly.inputTypes.VALUE &&
this.inputList[i].type == Blockly.inputTypes.DUMMY) {
// Dummy input after a value input. Inline them.
return true;
}
@@ -1274,7 +1292,7 @@ Blockly.Block.prototype.isEnabled = function() {
*/
Blockly.Block.prototype.setEnabled = function(enabled) {
if (this.isEnabled() != enabled) {
Blockly.Events.fire(new Blockly.Events.BlockChange(
Blockly.Events.fire(new (Blockly.Events.get(Blockly.Events.BLOCK_CHANGE))(
this, 'disabled', null, this.disabled, !enabled));
this.disabled = !enabled;
}
@@ -1311,7 +1329,7 @@ Blockly.Block.prototype.isCollapsed = function() {
*/
Blockly.Block.prototype.setCollapsed = function(collapsed) {
if (this.collapsed_ != collapsed) {
Blockly.Events.fire(new Blockly.Events.BlockChange(
Blockly.Events.fire(new (Blockly.Events.get(Blockly.Events.BLOCK_CHANGE))(
this, 'collapsed', null, this.collapsed_, collapsed));
this.collapsed_ = collapsed;
}
@@ -1372,7 +1390,7 @@ Blockly.Block.prototype.toString = function(opt_maxLength, opt_emptyToken) {
break;
case Blockly.ASTNode.types.FIELD:
var field = /** @type {Blockly.Field} */ (node.getLocation());
if (field.name != Blockly.Block.COLLAPSED_FIELD_NAME) {
if (field.name != Blockly.constants.COLLAPSED_FIELD_NAME) {
text.push(field.getText());
}
break;
@@ -1433,7 +1451,7 @@ Blockly.Block.prototype.toString = function(opt_maxLength, opt_emptyToken) {
* @return {!Blockly.Input} The input object created.
*/
Blockly.Block.prototype.appendValueInput = function(name) {
return this.appendInput_(Blockly.INPUT_VALUE, name);
return this.appendInput_(Blockly.inputTypes.VALUE, name);
};
/**
@@ -1443,7 +1461,7 @@ Blockly.Block.prototype.appendValueInput = function(name) {
* @return {!Blockly.Input} The input object created.
*/
Blockly.Block.prototype.appendStatementInput = function(name) {
return this.appendInput_(Blockly.NEXT_STATEMENT, name);
return this.appendInput_(Blockly.inputTypes.STATEMENT, name);
};
/**
@@ -1453,7 +1471,7 @@ Blockly.Block.prototype.appendStatementInput = function(name) {
* @return {!Blockly.Input} The input object created.
*/
Blockly.Block.prototype.appendDummyInput = function(opt_name) {
return this.appendInput_(Blockly.DUMMY_INPUT, opt_name || '');
return this.appendInput_(Blockly.inputTypes.DUMMY, opt_name || '');
};
/**
@@ -1623,117 +1641,212 @@ Blockly.Block.prototype.mixin = function(mixinObj, opt_disableCheck) {
Blockly.Block.prototype.interpolate_ = function(message, args, lastDummyAlign,
warningPrefix) {
var tokens = Blockly.utils.tokenizeInterpolation(message);
// Interpolate the arguments. Build a list of elements.
var indexDup = [];
var indexCount = 0;
var elements = [];
for (var i = 0; i < tokens.length; i++) {
var token = tokens[i];
if (typeof token == 'number') {
if (token <= 0 || token > args.length) {
throw Error('Block "' + this.type + '": ' +
'Message index %' + token + ' out of range.');
}
if (indexDup[token]) {
throw Error('Block "' + this.type + '": ' +
'Message index %' + token + ' duplicated.');
}
indexDup[token] = true;
indexCount++;
elements.push(args[token - 1]);
} else {
token = token.trim();
if (token) {
elements.push(token);
}
}
}
if (indexCount != args.length) {
throw Error('Block "' + this.type + '": ' +
'Message does not reference all ' + args.length + ' arg(s).');
}
// Add last dummy input if needed.
if (elements.length && (typeof elements[elements.length - 1] == 'string' ||
Blockly.utils.string.startsWith(
elements[elements.length - 1]['type'], 'field_'))) {
var dummyInput = {type: 'input_dummy'};
if (lastDummyAlign) {
dummyInput['align'] = lastDummyAlign;
}
elements.push(dummyInput);
}
// Lookup of alignment constants.
var alignmentLookup = {
'LEFT': Blockly.ALIGN_LEFT,
'RIGHT': Blockly.ALIGN_RIGHT,
'CENTRE': Blockly.ALIGN_CENTRE,
'CENTER': Blockly.ALIGN_CENTRE
};
// Populate block with inputs and fields.
var fieldStack = [];
for (var i = 0; i < elements.length; i++) {
var element = elements[i];
if (typeof element == 'string') {
fieldStack.push([element, undefined]);
} else {
var field = null;
var input = null;
do {
var altRepeat = false;
if (typeof element == 'string') {
field = new Blockly.FieldLabel(element);
} else {
switch (element['type']) {
case 'input_value':
input = this.appendValueInput(element['name']);
break;
case 'input_statement':
input = this.appendStatementInput(element['name']);
break;
case 'input_dummy':
input = this.appendDummyInput(element['name']);
break;
default:
// This should handle all field JSON parsing, including
// options that can be applied to any field type.
field = Blockly.fieldRegistry.fromJson(element);
this.validateTokens_(tokens, args.length);
var elements = this.interpolateArguments_(tokens, args, lastDummyAlign);
// Unknown field.
if (!field && element['alt']) {
element = element['alt'];
altRepeat = true;
}
}
}
} while (altRepeat);
if (field) {
fieldStack.push([field, element['name']]);
} else if (input) {
if (element['check']) {
input.setCheck(element['check']);
}
if (element['align']) {
var alignment = alignmentLookup[element['align'].toUpperCase()];
if (alignment === undefined) {
console.warn(warningPrefix + 'Illegal align value: ',
element['align']);
} else {
input.setAlign(alignment);
}
}
for (var j = 0; j < fieldStack.length; j++) {
input.appendField(fieldStack[j][0], fieldStack[j][1]);
// An array of [field, fieldName] tuples.
var fieldStack = [];
for (var i = 0, element; (element = elements[i]); i++) {
if (this.isInputKeyword_(element['type'])) {
var input = this.inputFromJson_(element, warningPrefix);
// Should never be null, but just in case.
if (input) {
for (var j = 0, tuple; (tuple = fieldStack[j]); j++) {
input.appendField(tuple[0], tuple[1]);
}
fieldStack.length = 0;
}
} else {
// All other types, including ones starting with 'input_' get routed here.
var field = this.fieldFromJson_(element);
if (field) {
fieldStack.push([field, element['name']]);
}
}
}
};
/**
* Validates that the tokens are within the correct bounds, with no duplicates,
* and that all of the arguments are referred to. Throws errors if any of these
* things are not true.
* @param {!Array<string|number>} tokens An array of tokens to validate
* @param {number} argsCount The number of args that need to be referred to.
* @private
*/
Blockly.Block.prototype.validateTokens_ = function(tokens, argsCount) {
var visitedArgsHash = [];
var visitedArgsCount = 0;
for (var i = 0; i < tokens.length; i++) {
var token = tokens[i];
if (typeof token != 'number') {
continue;
}
if (token < 1 || token > argsCount) {
throw Error('Block "' + this.type + '": ' +
'Message index %' + token + ' out of range.');
}
if (visitedArgsHash[token]) {
throw Error('Block "' + this.type + '": ' +
'Message index %' + token + ' duplicated.');
}
visitedArgsHash[token] = true;
visitedArgsCount++;
}
if (visitedArgsCount != argsCount) {
throw Error('Block "' + this.type + '": ' +
'Message does not reference all ' + argsCount + ' arg(s).');
}
};
/**
* Inserts args in place of numerical tokens. String args are converted to json
* that defines a label field. If necessary an extra dummy input is added to
* the end of the elements.
* @param {!Array<!string|number>} tokens The tokens to interpolate
* @param {!Array<!Object|string>} args The arguments to insert.
* @param {string|undefined} lastDummyAlign The alignment the added dummy input
* should have, if we are required to add one.
* @return {!Array<!Object>} The JSON definitions of field and inputs to add
* to the block.
* @private
*/
Blockly.Block.prototype.interpolateArguments_ =
function(tokens, args, lastDummyAlign) {
var elements = [];
for (var i = 0; i < tokens.length; i++) {
var element = tokens[i];
if (typeof element == 'number') {
element = args[element - 1];
}
// Args can be strings, which is why this isn't elseif.
if (typeof element == 'string') {
element = this.stringToFieldJson_(element);
if (!element) {
continue;
}
}
elements.push(element);
}
var length = elements.length;
if (length && !this.isInputKeyword_(elements[length - 1]['type'])) {
var dummyInput = {'type': 'input_dummy'};
if (lastDummyAlign) {
dummyInput['align'] = lastDummyAlign;
}
elements.push(dummyInput);
}
return elements;
};
/**
* Creates a field from the json definition of a field. If a field with the
* given type cannot be found, this attempts to create a different field using
* the 'alt' property of the json definition (if it exists).
* @param {{alt:(string|undefined)}} element The element to try to turn into a
* field.
* @return {?Blockly.Field} The field defined by the JSON, or null if one
* couldn't be created.
* @private
*/
Blockly.Block.prototype.fieldFromJson_ = function(element) {
var field = Blockly.fieldRegistry.fromJson(element);
if (!field && element['alt']) {
if (typeof element['alt'] == 'string') {
var json = this.stringToFieldJson_(element['alt']);
return json ? this.fieldFromJson_(json) : null;
}
return this.fieldFromJson_(element['alt']);
}
return field;
};
/**
* Creates an input from the json definition of an input. Sets the input's check
* and alignment if they are provided.
* @param {!Object} element The JSON to turn into an input.
* @param {string} warningPrefix The prefix to add to warnings to help the
* developer debug.
* @return {?Blockly.Input} The input that has been created, or null if one
* could not be created for some reason (should never happen).
* @private
*/
Blockly.Block.prototype.inputFromJson_ = function(element, warningPrefix) {
var alignmentLookup = {
'LEFT': Blockly.constants.ALIGN.LEFT,
'RIGHT': Blockly.constants.ALIGN.RIGHT,
'CENTRE': Blockly.constants.ALIGN.CENTRE,
'CENTER': Blockly.constants.ALIGN.CENTRE
};
var input = null;
switch (element['type']) {
case 'input_value':
input = this.appendValueInput(element['name']);
break;
case 'input_statement':
input = this.appendStatementInput(element['name']);
break;
case 'input_dummy':
input = this.appendDummyInput(element['name']);
break;
}
// Should never be hit because of interpolate_'s checks, but just in case.
if (!input) {
return null;
}
if (element['check']) {
input.setCheck(element['check']);
}
if (element['align']) {
var alignment = alignmentLookup[element['align'].toUpperCase()];
if (alignment === undefined) {
console.warn(warningPrefix + 'Illegal align value: ',
element['align']);
} else {
input.setAlign(alignment);
}
}
return input;
};
/**
* Returns true if the given string matches one of the input keywords.
* @param {string} str The string to check.
* @return {boolean} True if the given string matches one of the input keywords,
* false otherwise.
* @private
*/
Blockly.Block.prototype.isInputKeyword_ = function(str) {
return str == 'input_value' ||
str == 'input_statement' ||
str == 'input_dummy';
};
/**
* Turns a string into the JSON definition of a label field. If the string
* becomes an empty string when trimmed, this returns null.
* @param {string} str String to turn into the JSON definition of a label field.
* @return {?{text: string, type: string}} The JSON definition or null.
* @private
*/
Blockly.Block.prototype.stringToFieldJson_ = function(str) {
str = str.trim();
if (str) {
return {
'type': 'field_label',
'text': str,
};
}
return null;
};
/**
* Add a value input, statement input or local variable to this block.
* @param {number} type Either Blockly.INPUT_VALUE or Blockly.NEXT_STATEMENT or
* Blockly.DUMMY_INPUT.
* @param {number} type One of Blockly.inputTypes.
* @param {string} name Language-neutral identifier which may used to find this
* input again. Should be unique to this block.
* @return {!Blockly.Input} The input object created.
@@ -1741,10 +1854,11 @@ Blockly.Block.prototype.interpolate_ = function(message, args, lastDummyAlign,
*/
Blockly.Block.prototype.appendInput_ = function(type, name) {
var connection = null;
if (type == Blockly.INPUT_VALUE || type == Blockly.NEXT_STATEMENT) {
if (type == Blockly.inputTypes.VALUE ||
type == Blockly.inputTypes.STATEMENT) {
connection = this.makeConnection_(type);
}
if (type == Blockly.NEXT_STATEMENT) {
if (type == Blockly.inputTypes.STATEMENT) {
this.statementInputCount++;
}
var input = new Blockly.Input(type, name, this, connection);
@@ -1825,7 +1939,7 @@ Blockly.Block.prototype.moveNumberedInputBefore = function(
Blockly.Block.prototype.removeInput = function(name, opt_quiet) {
for (var i = 0, input; (input = this.inputList[i]); i++) {
if (input.name == name) {
if (input.type == Blockly.NEXT_STATEMENT) {
if (input.type == Blockly.inputTypes.STATEMENT) {
this.statementInputCount--;
}
input.dispose();
@@ -1882,7 +1996,7 @@ Blockly.Block.prototype.setCommentText = function(text) {
if (this.commentModel.text == text) {
return;
}
Blockly.Events.fire(new Blockly.Events.BlockChange(
Blockly.Events.fire(new (Blockly.Events.get(Blockly.Events.BLOCK_CHANGE))(
this, 'comment', null, this.commentModel.text, text));
this.commentModel.text = text;
this.comment = text; // For backwards compatibility.
@@ -1925,7 +2039,7 @@ Blockly.Block.prototype.moveBy = function(dx, dy) {
if (this.parentBlock_) {
throw Error('Block has parent.');
}
var event = new Blockly.Events.BlockMove(this);
var event = new (Blockly.Events.get(Blockly.Events.BLOCK_MOVE))(this);
this.xy_.translate(dx, dy);
event.recordNew();
Blockly.Events.fire(event);

View File

@@ -15,6 +15,8 @@ goog.provide('Blockly.blockAnimations');
goog.require('Blockly.utils.dom');
goog.require('Blockly.utils.Svg');
goog.requireType('Blockly.BlockSvg');
/**
* PID of disconnect UI animation. There can only be one at a time.

View File

@@ -13,14 +13,20 @@
goog.provide('Blockly.BlockDragger');
goog.require('Blockly.blockAnimations');
/** @suppress {extraRequire} */
goog.require('Blockly.constants');
goog.require('Blockly.Events');
goog.require('Blockly.Events.BlockMove');
/** @suppress {extraRequire} */
goog.require('Blockly.Events.BlockDrag');
/** @suppress {extraRequire} */
goog.require('Blockly.Events.BlockMove');
goog.require('Blockly.InsertionMarkerManager');
goog.require('Blockly.utils.Coordinate');
goog.require('Blockly.utils.dom');
goog.requireType('Blockly.BlockSvg');
goog.requireType('Blockly.WorkspaceSvg');
/**
* Class for a block dragger. It moves blocks around the workspace when they
@@ -184,8 +190,8 @@ Blockly.BlockDragger.prototype.startBlockDrag = function(currentDragDeltaXY,
* @private
*/
Blockly.BlockDragger.prototype.fireDragStartEvent_ = function() {
var event = new Blockly.Events.BlockDrag(this.draggingBlock_, true,
this.draggingBlock_.getDescendants(false));
var event = new (Blockly.Events.get(Blockly.Events.BLOCK_DRAG))(
this.draggingBlock_, true, this.draggingBlock_.getDescendants(false));
Blockly.Events.fire(event);
};
@@ -261,8 +267,8 @@ Blockly.BlockDragger.prototype.endBlockDrag = function(e, currentDragDeltaXY) {
* @private
*/
Blockly.BlockDragger.prototype.fireDragEndEvent_ = function() {
var event = new Blockly.Events.BlockDrag(this.draggingBlock_, false,
this.draggingBlock_.getDescendants(false));
var event = new (Blockly.Events.get(Blockly.Events.BLOCK_DRAG))(
this.draggingBlock_, false, this.draggingBlock_.getDescendants(false));
Blockly.Events.fire(event);
};
@@ -271,7 +277,8 @@ Blockly.BlockDragger.prototype.fireDragEndEvent_ = function() {
* @private
*/
Blockly.BlockDragger.prototype.fireMoveEvent_ = function() {
var event = new Blockly.Events.BlockMove(this.draggingBlock_);
var event = new (Blockly.Events.get(Blockly.Events.BLOCK_MOVE))(
this.draggingBlock_);
event.oldCoordinate = this.startXY_;
event.recordNew();
Blockly.Events.fire(event);

View File

@@ -16,29 +16,44 @@ goog.require('Blockly.ASTNode');
goog.require('Blockly.Block');
goog.require('Blockly.blockAnimations');
goog.require('Blockly.blockRendering.IPathObject');
goog.require('Blockly.browserEvents');
goog.require('Blockly.connectionTypes');
/** @suppress {extraRequire} */
goog.require('Blockly.constants');
goog.require('Blockly.ContextMenu');
goog.require('Blockly.ContextMenuRegistry');
goog.require('Blockly.Events');
/** @suppress {extraRequire} */
goog.require('Blockly.Events.BlockMove');
/** @suppress {extraRequire} */
goog.require('Blockly.Events.Selected');
goog.require('Blockly.Msg');
goog.require('Blockly.navigation');
goog.require('Blockly.RenderedConnection');
goog.require('Blockly.TabNavigateCursor');
goog.require('Blockly.Tooltip');
/** @suppress {extraRequire} */
goog.require('Blockly.Touch');
goog.require('Blockly.utils');
goog.require('Blockly.utils.deprecation');
goog.require('Blockly.utils.Coordinate');
goog.require('Blockly.utils.deprecation');
goog.require('Blockly.utils.dom');
goog.require('Blockly.utils.object');
goog.require('Blockly.utils.Rect');
goog.require('Blockly.utils.userAgent');
goog.require('Blockly.Xml');
goog.requireType('Blockly.blockRendering.Debug');
goog.requireType('Blockly.Comment');
goog.requireType('Blockly.Connection');
goog.requireType('Blockly.Field');
goog.requireType('Blockly.IASTNodeLocationSvg');
goog.requireType('Blockly.IBoundedElement');
goog.requireType('Blockly.ICopyable');
goog.requireType('Blockly.Input');
goog.requireType('Blockly.Mutator');
goog.requireType('Blockly.Theme');
goog.requireType('Blockly.Warning');
goog.requireType('Blockly.WorkspaceSvg');
/**
@@ -148,7 +163,7 @@ Blockly.BlockSvg.prototype.warningTextDb_ = null;
/**
* Constant for identifying rows that are to be rendered inline.
* Don't collide with Blockly.INPUT_VALUE and friends.
* Don't collide with Blockly.inputTypes.
* @const
*/
Blockly.BlockSvg.INLINE = -1;
@@ -214,7 +229,7 @@ Blockly.BlockSvg.prototype.initSvg = function() {
this.pathObject.updateMovable(this.isMovable());
var svg = this.getSvgRoot();
if (!this.workspace.options.readOnly && !this.eventsInit_ && svg) {
Blockly.bindEventWithChecks_(
Blockly.browserEvents.conditionalBind(
svg, 'mousedown', this, this.onMouseDown_);
}
this.eventsInit_ = true;
@@ -300,7 +315,8 @@ Blockly.BlockSvg.prototype.select = function() {
Blockly.Events.enable();
}
}
var event = new Blockly.Events.Selected(oldId, this.id, this.workspace.id);
var event = new (Blockly.Events.get(Blockly.Events.SELECTED))(oldId, this.id,
this.workspace.id);
Blockly.Events.fire(event);
Blockly.selected = this;
this.addSelect();
@@ -313,7 +329,8 @@ Blockly.BlockSvg.prototype.unselect = function() {
if (Blockly.selected != this) {
return;
}
var event = new Blockly.Events.Selected(this.id, null, this.workspace.id);
var event = new (Blockly.Events.get(Blockly.Events.SELECTED))(this.id, null,
this.workspace.id);
event.workspaceId = this.workspace.id;
Blockly.Events.fire(event);
Blockly.selected = null;
@@ -454,7 +471,7 @@ Blockly.BlockSvg.prototype.moveBy = function(dx, dy) {
}
var eventsEnabled = Blockly.Events.isEnabled();
if (eventsEnabled) {
var event = new Blockly.Events.BlockMove(this);
var event = new (Blockly.Events.get(Blockly.Events.BLOCK_MOVE))(this);
}
var xy = this.getRelativeToSurfaceXY();
this.translate(xy.x + dx, xy.y + dy);
@@ -645,8 +662,8 @@ Blockly.BlockSvg.prototype.setCollapsed = function(collapsed) {
*/
Blockly.BlockSvg.prototype.updateCollapsed_ = function() {
var collapsed = this.isCollapsed();
var collapsedInputName = Blockly.Block.COLLAPSED_INPUT_NAME;
var collapsedFieldName = Blockly.Block.COLLAPSED_FIELD_NAME;
var collapsedInputName = Blockly.constants.COLLAPSED_INPUT_NAME;
var collapsedFieldName = Blockly.constants.COLLAPSED_FIELD_NAME;
for (var i = 0, input; (input = this.inputList[i]); i++) {
if (input.name != collapsedInputName) {
@@ -655,6 +672,7 @@ Blockly.BlockSvg.prototype.updateCollapsed_ = function() {
}
if (!collapsed) {
this.updateDisabled();
this.removeInput(collapsedInputName);
return;
}
@@ -684,11 +702,12 @@ Blockly.BlockSvg.prototype.tab = function(start, forward) {
var tabCursor = new Blockly.TabNavigateCursor();
tabCursor.setCurNode(Blockly.ASTNode.createFieldNode(start));
var currentNode = tabCursor.getCurNode();
var actionName = forward ?
Blockly.navigation.actionNames.NEXT : Blockly.navigation.actionNames.PREVIOUS;
tabCursor.onBlocklyAction(
/** @type {!Blockly.ShortcutRegistry.KeyboardShortcut} */ ({name: actionName}));
if (forward) {
tabCursor.next();
} else {
tabCursor.prev();
}
var nextNode = tabCursor.getCurNode();
if (nextNode && nextNode !== currentNode) {
@@ -899,10 +918,6 @@ Blockly.BlockSvg.prototype.dispose = function(healStack, animate) {
Blockly.ContextMenu.hide();
}
if (this.workspace.keyboardAccessibilityMode) {
Blockly.navigation.moveCursorOnBlockDelete(this);
}
if (animate && this.rendered) {
this.unplug(healStack);
Blockly.blockAnimations.disposeUiEffect(this);
@@ -1361,8 +1376,7 @@ Blockly.BlockSvg.prototype.moveNumberedInputBefore = function(
/**
* Add a value input, statement input or local variable to this block.
* @param {number} type Either Blockly.INPUT_VALUE or Blockly.NEXT_STATEMENT or
* Blockly.DUMMY_INPUT.
* @param {number} type One of Blockly.inputTypes.
* @param {string} name Language-neutral identifier which may used to find this
* input again. Should be unique to this block.
* @return {!Blockly.Input} The input object created.
@@ -1576,8 +1590,8 @@ Blockly.BlockSvg.prototype.positionNearConnection = function(sourceConnection,
targetConnection) {
// We only need to position the new block if it's before the existing one,
// otherwise its position is set by the previous block.
if (sourceConnection.type == Blockly.NEXT_STATEMENT ||
sourceConnection.type == Blockly.INPUT_VALUE) {
if (sourceConnection.type == Blockly.connectionTypes.NEXT_STATEMENT ||
sourceConnection.type == Blockly.connectionTypes.INPUT_VALUE) {
var dx = targetConnection.x - sourceConnection.x;
var dy = targetConnection.y - sourceConnection.y;
@@ -1652,7 +1666,8 @@ Blockly.BlockSvg.prototype.updateMarkers_ = function() {
this.workspace.getCursor().draw();
}
if (this.workspace.keyboardAccessibilityMode && this.pathObject.markerSvg) {
this.workspace.getMarker(Blockly.navigation.MARKER_NAME).draw();
// TODO(#4592): Update all markers on the block.
this.workspace.getMarker(Blockly.MarkerManager.LOCAL_MARKER).draw();
}
};

View File

@@ -16,23 +16,47 @@
*/
goog.provide('Blockly');
goog.require('Blockly.browserEvents');
/** @suppress {extraRequire} */
goog.require('Blockly.constants');
goog.require('Blockly.connectionTypes');
goog.require('Blockly.Events');
/** @suppress {extraRequire} */
goog.require('Blockly.Events.BlockCreate');
/** @suppress {extraRequire} */
goog.require('Blockly.Events.FinishedLoading');
/** @suppress {extraRequire} */
goog.require('Blockly.Events.Ui');
/** @suppress {extraRequire} */
goog.require('Blockly.Events.UiBase');
/** @suppress {extraRequire} */
goog.require('Blockly.Events.VarCreate');
/** @suppress {extraRequire} */
goog.require('Blockly.inject');
goog.require('Blockly.inputTypes');
/** @suppress {extraRequire} */
goog.require('Blockly.Procedures');
goog.require('Blockly.ShortcutRegistry');
goog.require('Blockly.Tooltip');
/** @suppress {extraRequire} */
goog.require('Blockly.Touch');
goog.require('Blockly.utils');
goog.require('Blockly.utils.colour');
goog.require('Blockly.utils.deprecation');
goog.require('Blockly.utils.Size');
goog.require('Blockly.utils.toolbox');
/** @suppress {extraRequire} */
goog.require('Blockly.Variables');
goog.require('Blockly.WidgetDiv');
goog.require('Blockly.WorkspaceSvg');
/** @suppress {extraRequire} */
goog.require('Blockly.Xml');
goog.requireType('Blockly.BlockSvg');
goog.requireType('Blockly.Connection');
goog.requireType('Blockly.ICopyable');
goog.requireType('Blockly.Workspace');
/**
* Blockly core version.
@@ -99,19 +123,20 @@ Blockly.cache3dSupported_ = null;
*/
Blockly.parentContainer = null;
/**
* Blockly opaque event data used to unbind events when using
* `Blockly.bindEvent_` and `Blockly.bindEventWithChecks_`.
* @typedef {!Array.<!Array>}
*/
Blockly.EventData;
/**
* Returns the dimensions of the specified SVG image.
* @param {!SVGElement} svg SVG image.
* @return {!Blockly.utils.Size} Contains width and height properties.
* @deprecated Use workspace.setCachedParentSvgSize. (2021 March 5)
*/
Blockly.svgSize = function(svg) {
// When removing this function, remove svg.cachedWidth_ and svg.cachedHeight_
// from setCachedParentSvgSize.
Blockly.utils.deprecation.warn(
'Blockly.svgSize',
'March 2021',
'March 2022',
'workspace.getCachedParentSvgSize');
svg = /** @type {?} */ (svg);
return new Blockly.utils.Size(svg.cachedWidth_, svg.cachedHeight_);
};
@@ -139,6 +164,7 @@ Blockly.svgResize = function(workspace) {
mainWorkspace = mainWorkspace.options.parentWorkspace;
}
var svg = mainWorkspace.getParentSvg();
var cachedSize = mainWorkspace.getCachedParentSvgSize();
var div = svg.parentNode;
if (!div) {
// Workspace deleted, or something.
@@ -146,13 +172,13 @@ Blockly.svgResize = function(workspace) {
}
var width = div.offsetWidth;
var height = div.offsetHeight;
if (svg.cachedWidth_ != width) {
if (cachedSize.width != width) {
svg.setAttribute('width', width + 'px');
svg.cachedWidth_ = width;
mainWorkspace.setCachedParentSvgSize(width, null);
}
if (svg.cachedHeight_ != height) {
if (cachedSize.height != height) {
svg.setAttribute('height', height + 'px');
svg.cachedHeight_ = height;
mainWorkspace.setCachedParentSvgSize(null, height);
}
mainWorkspace.resize();
};
@@ -383,149 +409,6 @@ Blockly.defineBlocksWithJsonArray = function(jsonArray) {
}
};
/**
* Bind an event to a function call. When calling the function, verifies that
* it belongs to the touch stream that is currently being processed, and splits
* multitouch events into multiple events as needed.
* @param {!EventTarget} node Node upon which to listen.
* @param {string} name Event name to listen to (e.g. 'mousedown').
* @param {Object} thisObject The value of 'this' in the function.
* @param {!Function} func Function to call when event is triggered.
* @param {boolean=} opt_noCaptureIdentifier True if triggering on this event
* should not block execution of other event handlers on this touch or
* other simultaneous touches. False by default.
* @param {boolean=} opt_noPreventDefault True if triggering on this event
* should prevent the default handler. False by default. If
* opt_noPreventDefault is provided, opt_noCaptureIdentifier must also be
* provided.
* @return {!Blockly.EventData} Opaque data that can be passed to unbindEvent_.
*/
Blockly.bindEventWithChecks_ = function(node, name, thisObject, func,
opt_noCaptureIdentifier, opt_noPreventDefault) {
var handled = false;
var wrapFunc = function(e) {
var captureIdentifier = !opt_noCaptureIdentifier;
// Handle each touch point separately. If the event was a mouse event, this
// will hand back an array with one element, which we're fine handling.
var events = Blockly.Touch.splitEventByTouches(e);
for (var i = 0, event; (event = events[i]); i++) {
if (captureIdentifier && !Blockly.Touch.shouldHandleEvent(event)) {
continue;
}
Blockly.Touch.setClientFromTouch(event);
if (thisObject) {
func.call(thisObject, event);
} else {
func(event);
}
handled = true;
}
};
var bindData = [];
if (Blockly.utils.global['PointerEvent'] &&
(name in Blockly.Touch.TOUCH_MAP)) {
for (var i = 0, type; (type = Blockly.Touch.TOUCH_MAP[name][i]); i++) {
node.addEventListener(type, wrapFunc, false);
bindData.push([node, type, wrapFunc]);
}
} else {
node.addEventListener(name, wrapFunc, false);
bindData.push([node, name, wrapFunc]);
// Add equivalent touch event.
if (name in Blockly.Touch.TOUCH_MAP) {
var touchWrapFunc = function(e) {
wrapFunc(e);
// Calling preventDefault stops the browser from scrolling/zooming the
// page.
var preventDef = !opt_noPreventDefault;
if (handled && preventDef) {
e.preventDefault();
}
};
for (var i = 0, type; (type = Blockly.Touch.TOUCH_MAP[name][i]); i++) {
node.addEventListener(type, touchWrapFunc, false);
bindData.push([node, type, touchWrapFunc]);
}
}
}
return bindData;
};
/**
* Bind an event to a function call. Handles multitouch events by using the
* coordinates of the first changed touch, and doesn't do any safety checks for
* simultaneous event processing. In most cases prefer is to use
* `Blockly.bindEventWithChecks_`.
* @param {!EventTarget} node Node upon which to listen.
* @param {string} name Event name to listen to (e.g. 'mousedown').
* @param {Object} thisObject The value of 'this' in the function.
* @param {!Function} func Function to call when event is triggered.
* @return {!Blockly.EventData} Opaque data that can be passed to unbindEvent_.
*/
Blockly.bindEvent_ = function(node, name, thisObject, func) {
var wrapFunc = function(e) {
if (thisObject) {
func.call(thisObject, e);
} else {
func(e);
}
};
var bindData = [];
if (Blockly.utils.global['PointerEvent'] &&
(name in Blockly.Touch.TOUCH_MAP)) {
for (var i = 0, type; (type = Blockly.Touch.TOUCH_MAP[name][i]); i++) {
node.addEventListener(type, wrapFunc, false);
bindData.push([node, type, wrapFunc]);
}
} else {
node.addEventListener(name, wrapFunc, false);
bindData.push([node, name, wrapFunc]);
// Add equivalent touch event.
if (name in Blockly.Touch.TOUCH_MAP) {
var touchWrapFunc = function(e) {
// Punt on multitouch events.
if (e.changedTouches && e.changedTouches.length == 1) {
// Map the touch event's properties to the event.
var touchPoint = e.changedTouches[0];
e.clientX = touchPoint.clientX;
e.clientY = touchPoint.clientY;
}
wrapFunc(e);
// Stop the browser from scrolling/zooming the page.
e.preventDefault();
};
for (var i = 0, type; (type = Blockly.Touch.TOUCH_MAP[name][i]); i++) {
node.addEventListener(type, touchWrapFunc, false);
bindData.push([node, type, touchWrapFunc]);
}
}
}
return bindData;
};
/**
* Unbind one or more events event from a function call.
* @param {!Array.<!Array>} bindData Opaque data from bindEvent_.
* This list is emptied during the course of calling this function.
* @return {!Function} The function call.
*/
Blockly.unbindEvent_ = function(bindData) {
while (bindData.length) {
var bindDatum = bindData.pop();
var node = bindDatum[0];
var name = bindDatum[1];
var func = bindDatum[2];
node.removeEventListener(name, func, false);
}
return func;
};
/**
* Is the given string a number (includes negative and decimals).
* @param {string} str Input string.
@@ -627,3 +510,89 @@ Blockly.checkBlockColourConstant_ = function(
Blockly.setParentContainer = function(container) {
Blockly.parentContainer = container;
};
/** Aliases. */
/**
* @see Blockly.browserEvents.bind
*/
Blockly.bindEvent_ = Blockly.browserEvents.bind;
/**
* @see Blockly.browserEvents.unbind
*/
Blockly.unbindEvent_ = Blockly.browserEvents.unbind;
/**
* @see Blockly.browserEvents.conditionalBind
*/
Blockly.bindEventWithChecks_ = Blockly.browserEvents.conditionalBind;
/**
* @see Blockly.constants.ALIGN.LEFT
*/
Blockly.ALIGN_LEFT = Blockly.constants.ALIGN.LEFT;
/**
* @see Blockly.constants.ALIGN.CENTRE
*/
Blockly.ALIGN_CENTRE = Blockly.constants.ALIGN.CENTRE;
/**
* @see Blockly.constants.ALIGN.RIGHT
*/
Blockly.ALIGN_RIGHT = Blockly.constants.ALIGN.RIGHT;
/**
* Aliases for constants used for connection and input types.
*/
/**
* @see Blockly.connectionTypes.INPUT_VALUE
*/
Blockly.INPUT_VALUE = Blockly.connectionTypes.INPUT_VALUE;
/**
* @see Blockly.connectionTypes.OUTPUT_VALUE
*/
Blockly.OUTPUT_VALUE = Blockly.connectionTypes.OUTPUT_VALUE;
/**
* @see Blockly.connectionTypes.NEXT_STATEMENT
*/
Blockly.NEXT_STATEMENT = Blockly.connectionTypes.NEXT_STATEMENT;
/**
* @see Blockly.connectionTypes.PREVIOUS_STATEMENT
*/
Blockly.PREVIOUS_STATEMENT = Blockly.connectionTypes.PREVIOUS_STATEMENT;
/**
* @see Blockly.inputTypes.DUMMY_INPUT
*/
Blockly.DUMMY_INPUT = Blockly.inputTypes.DUMMY;
/**
* Aliases for toolbox positions.
*/
/**
* @see Blockly.utils.toolbox.Position.TOP
*/
Blockly.TOOLBOX_AT_TOP = Blockly.utils.toolbox.Position.TOP;
/**
* @see Blockly.utils.toolbox.Position.BOTTOM
*/
Blockly.TOOLBOX_AT_BOTTOM = Blockly.utils.toolbox.Position.BOTTOM;
/**
* @see Blockly.utils.toolbox.Position.LEFT
*/
Blockly.TOOLBOX_AT_LEFT = Blockly.utils.toolbox.Position.LEFT;
/**
* @see Blockly.utils.toolbox.Position.RIGHT
*/
Blockly.TOOLBOX_AT_RIGHT = Blockly.utils.toolbox.Position.RIGHT;

174
core/browser_events.js Normal file
View File

@@ -0,0 +1,174 @@
/**
* @license
* Copyright 2021 Google LLC
* SPDX-License-Identifier: Apache-2.0
*/
/**
* @fileoverview Browser event handling.
* @author fenichel@google.com (Rachel Fenichel)
*/
'use strict';
goog.provide('Blockly.browserEvents');
goog.require('Blockly.Touch');
/**
* Blockly opaque event data used to unbind events when using
* `Blockly.browserEvents.bind` and
* `Blockly.browserEvents.conditionalBind`.
* @typedef {!Array.<!Array>}
*/
Blockly.browserEvents.Data;
/**
* Bind an event handler that can be ignored if it is not part of the active
* touch stream.
* Use this for events that either start or continue a multi-part gesture (e.g.
* mousedown or mousemove, which may be part of a drag or click).
* @param {!EventTarget} node Node upon which to listen.
* @param {string} name Event name to listen to (e.g. 'mousedown').
* @param {Object} thisObject The value of 'this' in the function.
* @param {!Function} func Function to call when event is triggered.
* @param {boolean=} opt_noCaptureIdentifier True if triggering on this event
* should not block execution of other event handlers on this touch or
* other simultaneous touches. False by default.
* @param {boolean=} opt_noPreventDefault True if triggering on this event
* should prevent the default handler. False by default. If
* opt_noPreventDefault is provided, opt_noCaptureIdentifier must also be
* provided.
* @return {!Blockly.browserEvents.Data} Opaque data that can be passed to
* unbindEvent_.
* @public
*/
Blockly.browserEvents.conditionalBind = function(
node, name, thisObject, func, opt_noCaptureIdentifier,
opt_noPreventDefault) {
var handled = false;
var wrapFunc = function(e) {
var captureIdentifier = !opt_noCaptureIdentifier;
// Handle each touch point separately. If the event was a mouse event, this
// will hand back an array with one element, which we're fine handling.
var events = Blockly.Touch.splitEventByTouches(e);
for (var i = 0, event; (event = events[i]); i++) {
if (captureIdentifier && !Blockly.Touch.shouldHandleEvent(event)) {
continue;
}
Blockly.Touch.setClientFromTouch(event);
if (thisObject) {
func.call(thisObject, event);
} else {
func(event);
}
handled = true;
}
};
var bindData = [];
if (Blockly.utils.global['PointerEvent'] &&
(name in Blockly.Touch.TOUCH_MAP)) {
for (var i = 0, type; (type = Blockly.Touch.TOUCH_MAP[name][i]); i++) {
node.addEventListener(type, wrapFunc, false);
bindData.push([node, type, wrapFunc]);
}
} else {
node.addEventListener(name, wrapFunc, false);
bindData.push([node, name, wrapFunc]);
// Add equivalent touch event.
if (name in Blockly.Touch.TOUCH_MAP) {
var touchWrapFunc = function(e) {
wrapFunc(e);
// Calling preventDefault stops the browser from scrolling/zooming the
// page.
var preventDef = !opt_noPreventDefault;
if (handled && preventDef) {
e.preventDefault();
}
};
for (var i = 0, type; (type = Blockly.Touch.TOUCH_MAP[name][i]); i++) {
node.addEventListener(type, touchWrapFunc, false);
bindData.push([node, type, touchWrapFunc]);
}
}
}
return bindData;
};
/**
* Bind an event handler that should be called regardless of whether it is part
* of the active touch stream.
* Use this for events that are not part of a multi-part gesture (e.g.
* mouseover for tooltips).
* @param {!EventTarget} node Node upon which to listen.
* @param {string} name Event name to listen to (e.g. 'mousedown').
* @param {Object} thisObject The value of 'this' in the function.
* @param {!Function} func Function to call when event is triggered.
* @return {!Blockly.browserEvents.Data} Opaque data that can be passed to
* unbindEvent_.
* @public
*/
Blockly.browserEvents.bind = function(node, name, thisObject, func) {
var wrapFunc = function(e) {
if (thisObject) {
func.call(thisObject, e);
} else {
func(e);
}
};
var bindData = [];
if (Blockly.utils.global['PointerEvent'] &&
(name in Blockly.Touch.TOUCH_MAP)) {
for (var i = 0, type; (type = Blockly.Touch.TOUCH_MAP[name][i]); i++) {
node.addEventListener(type, wrapFunc, false);
bindData.push([node, type, wrapFunc]);
}
} else {
node.addEventListener(name, wrapFunc, false);
bindData.push([node, name, wrapFunc]);
// Add equivalent touch event.
if (name in Blockly.Touch.TOUCH_MAP) {
var touchWrapFunc = function(e) {
// Punt on multitouch events.
if (e.changedTouches && e.changedTouches.length == 1) {
// Map the touch event's properties to the event.
var touchPoint = e.changedTouches[0];
e.clientX = touchPoint.clientX;
e.clientY = touchPoint.clientY;
}
wrapFunc(e);
// Stop the browser from scrolling/zooming the page.
e.preventDefault();
};
for (var i = 0, type; (type = Blockly.Touch.TOUCH_MAP[name][i]); i++) {
node.addEventListener(type, touchWrapFunc, false);
bindData.push([node, type, touchWrapFunc]);
}
}
}
return bindData;
};
/**
* Unbind one or more events event from a function call.
* @param {!Blockly.browserEvents.Data} bindData Opaque data from bindEvent_.
* This list is emptied during the course of calling this function.
* @return {!Function} The function call.
* @public
*/
Blockly.browserEvents.unbind = function(bindData) {
while (bindData.length) {
var bindDatum = bindData.pop();
var node = bindDatum[0];
var name = bindDatum[1];
var func = bindDatum[2];
node.removeEventListener(name, func, false);
}
return func;
};

View File

@@ -12,18 +12,24 @@
goog.provide('Blockly.Bubble');
goog.require('Blockly.browserEvents');
goog.require('Blockly.Scrollbar');
goog.require('Blockly.Touch');
goog.require('Blockly.utils');
goog.require('Blockly.utils.Coordinate');
goog.require('Blockly.utils.dom');
goog.require('Blockly.utils.math');
goog.require('Blockly.utils.Size');
goog.require('Blockly.utils.Svg');
goog.require('Blockly.utils.userAgent');
/** @suppress {extraRequire} */
goog.require('Blockly.Workspace');
goog.requireType('Blockly.BlockDragSurfaceSvg');
goog.requireType('Blockly.BlockSvg');
goog.requireType('Blockly.IBubble');
goog.requireType('Blockly.utils.Metrics');
goog.requireType('Blockly.MetricsManager');
goog.requireType('Blockly.WorkspaceSvg');
/**
@@ -61,14 +67,14 @@ Blockly.Bubble = function(
/**
* Mouse down on bubbleBack_ event data.
* @type {?Blockly.EventData}
* @type {?Blockly.browserEvents.Data}
* @private
*/
this.onMouseDownBubbleWrapper_ = null;
/**
* Mouse down on resizeGroup_ event data.
* @type {?Blockly.EventData}
* @type {?Blockly.browserEvents.Data}
* @private
*/
this.onMouseDownResizeWrapper_ = null;
@@ -132,14 +138,14 @@ Blockly.Bubble.ANCHOR_RADIUS = 8;
/**
* Mouse up event data.
* @type {?Blockly.EventData}
* @type {?Blockly.browserEvents.Data}
* @private
*/
Blockly.Bubble.onMouseUpWrapper_ = null;
/**
* Mouse move event data.
* @type {?Blockly.EventData}
* @type {?Blockly.browserEvents.Data}
* @private
*/
Blockly.Bubble.onMouseMoveWrapper_ = null;
@@ -150,11 +156,11 @@ Blockly.Bubble.onMouseMoveWrapper_ = null;
*/
Blockly.Bubble.unbindDragEvents_ = function() {
if (Blockly.Bubble.onMouseUpWrapper_) {
Blockly.unbindEvent_(Blockly.Bubble.onMouseUpWrapper_);
Blockly.browserEvents.unbind(Blockly.Bubble.onMouseUpWrapper_);
Blockly.Bubble.onMouseUpWrapper_ = null;
}
if (Blockly.Bubble.onMouseMoveWrapper_) {
Blockly.unbindEvent_(Blockly.Bubble.onMouseMoveWrapper_);
Blockly.browserEvents.unbind(Blockly.Bubble.onMouseMoveWrapper_);
Blockly.Bubble.onMouseMoveWrapper_ = null;
}
};
@@ -237,8 +243,8 @@ Blockly.Bubble.prototype.createDom_ = function(content, hasResize) {
[...content goes here...]
</g>
*/
this.bubbleGroup_ = Blockly.utils.dom.createSvgElement(
Blockly.utils.Svg.G, {}, null);
this.bubbleGroup_ =
Blockly.utils.dom.createSvgElement(Blockly.utils.Svg.G, {}, null);
var filter = {
'filter': 'url(#' +
this.workspace_.getRenderer().getConstants().embossFilterId + ')'
@@ -294,10 +300,10 @@ Blockly.Bubble.prototype.createDom_ = function(content, hasResize) {
}
if (!this.workspace_.options.readOnly) {
this.onMouseDownBubbleWrapper_ = Blockly.bindEventWithChecks_(
this.onMouseDownBubbleWrapper_ = Blockly.browserEvents.conditionalBind(
this.bubbleBack_, 'mousedown', this, this.bubbleMouseDown_);
if (this.resizeGroup_) {
this.onMouseDownResizeWrapper_ = Blockly.bindEventWithChecks_(
this.onMouseDownResizeWrapper_ = Blockly.browserEvents.conditionalBind(
this.resizeGroup_, 'mousedown', this, this.resizeMouseDown_);
}
}
@@ -382,9 +388,9 @@ Blockly.Bubble.prototype.resizeMouseDown_ = function(e) {
new Blockly.utils.Coordinate(
this.workspace_.RTL ? -this.width_ : this.width_, this.height_));
Blockly.Bubble.onMouseUpWrapper_ = Blockly.bindEventWithChecks_(
Blockly.Bubble.onMouseUpWrapper_ = Blockly.browserEvents.conditionalBind(
document, 'mouseup', this, Blockly.Bubble.bubbleMouseUp_);
Blockly.Bubble.onMouseMoveWrapper_ = Blockly.bindEventWithChecks_(
Blockly.Bubble.onMouseMoveWrapper_ = Blockly.browserEvents.conditionalBind(
document, 'mousemove', this, this.resizeMouseMove_);
Blockly.hideChaff();
// This event has been handled. No need to bubble up to the document.
@@ -454,14 +460,10 @@ Blockly.Bubble.prototype.setAnchorLocation = function(xy) {
*/
Blockly.Bubble.prototype.layoutBubble_ = function() {
// Get the metrics in workspace units.
var metrics = this.workspace_.getMetrics();
metrics.viewLeft /= this.workspace_.scale;
metrics.viewWidth /= this.workspace_.scale;
metrics.viewTop /= this.workspace_.scale;
metrics.viewHeight /= this.workspace_.scale;
var viewMetrics = this.workspace_.getMetricsManager().getViewMetrics(true);
var optimalLeft = this.getOptimalRelativeLeft_(metrics);
var optimalTop = this.getOptimalRelativeTop_(metrics);
var optimalLeft = this.getOptimalRelativeLeft_(viewMetrics);
var optimalTop = this.getOptimalRelativeTop_(viewMetrics);
var bbox = this.shape_.getBBox();
var topPosition = {
@@ -476,10 +478,10 @@ Blockly.Bubble.prototype.layoutBubble_ = function() {
var closerPosition = bbox.width < bbox.height ? endPosition : bottomPosition;
var fartherPosition = bbox.width < bbox.height ? bottomPosition : endPosition;
var topPositionOverlap = this.getOverlap_(topPosition, metrics);
var startPositionOverlap = this.getOverlap_(startPosition, metrics);
var closerPositionOverlap = this.getOverlap_(closerPosition, metrics);
var fartherPositionOverlap = this.getOverlap_(fartherPosition, metrics);
var topPositionOverlap = this.getOverlap_(topPosition, viewMetrics);
var startPositionOverlap = this.getOverlap_(startPosition, viewMetrics);
var closerPositionOverlap = this.getOverlap_(closerPosition, viewMetrics);
var fartherPositionOverlap = this.getOverlap_(fartherPosition, viewMetrics);
// Set the position to whichever position shows the most of the bubble,
// with tiebreaks going in the order: top > start > close > far.
@@ -513,12 +515,12 @@ Blockly.Bubble.prototype.layoutBubble_ = function() {
* workspace (what percentage of the bubble is visible).
* @param {!{x: number, y: number}} relativeMin The position of the top-left
* corner of the bubble relative to the anchor point.
* @param {!Blockly.utils.Metrics} metrics The metrics of the workspace the
* bubble will appear in.
* @param {!Blockly.MetricsManager.ContainerRegion} viewMetrics The view metrics
* of the workspace the bubble will appear in.
* @return {number} The percentage of the bubble that is visible.
* @private
*/
Blockly.Bubble.prototype.getOverlap_ = function(relativeMin, metrics) {
Blockly.Bubble.prototype.getOverlap_ = function(relativeMin, viewMetrics) {
// The position of the top-left corner of the bubble in workspace units.
var bubbleMin = {
x: this.workspace_.RTL ? (this.anchorXY_.x - relativeMin.x - this.width_) :
@@ -534,11 +536,11 @@ Blockly.Bubble.prototype.getOverlap_ = function(relativeMin, metrics) {
// calculation.
// The position of the top-left corner of the workspace.
var workspaceMin = {x: metrics.viewLeft, y: metrics.viewTop};
var workspaceMin = {x: viewMetrics.left, y: viewMetrics.top};
// The position of the bottom-right corner of the workspace.
var workspaceMax = {
x: metrics.viewLeft + metrics.viewWidth,
y: metrics.viewTop + metrics.viewHeight
x: viewMetrics.left + viewMetrics.width,
y: viewMetrics.top + viewMetrics.height
};
var overlapWidth = Math.min(bubbleMax.x, workspaceMax.x) -
@@ -555,17 +557,17 @@ Blockly.Bubble.prototype.getOverlap_ = function(relativeMin, metrics) {
* Calculate what the optimal horizontal position of the top-left corner of the
* bubble is (relative to the anchor point) so that the most area of the
* bubble is shown.
* @param {!Blockly.utils.Metrics} metrics The metrics of the workspace the
* bubble will appear in.
* @param {!Blockly.MetricsManager.ContainerRegion} viewMetrics The view metrics
* of the workspace the bubble will appear in.
* @return {number} The optimal horizontal position of the top-left corner
* of the bubble.
* @private
*/
Blockly.Bubble.prototype.getOptimalRelativeLeft_ = function(metrics) {
Blockly.Bubble.prototype.getOptimalRelativeLeft_ = function(viewMetrics) {
var relativeLeft = -this.width_ / 4;
// No amount of sliding left or right will give us a better overlap.
if (this.width_ > metrics.viewWidth) {
if (this.width_ > viewMetrics.width) {
return relativeLeft;
}
@@ -574,16 +576,16 @@ Blockly.Bubble.prototype.getOptimalRelativeLeft_ = function(metrics) {
var bubbleRight = this.anchorXY_.x - relativeLeft;
var bubbleLeft = bubbleRight - this.width_;
var workspaceRight = metrics.viewLeft + metrics.viewWidth;
var workspaceLeft = metrics.viewLeft +
var workspaceRight = viewMetrics.left + viewMetrics.width;
var workspaceLeft = viewMetrics.left +
// Thickness in workspace units.
(Blockly.Scrollbar.scrollbarThickness / this.workspace_.scale);
} else {
var bubbleLeft = relativeLeft + this.anchorXY_.x;
var bubbleRight = bubbleLeft + this.width_;
var workspaceLeft = metrics.viewLeft;
var workspaceRight = metrics.viewLeft + metrics.viewWidth -
var workspaceLeft = viewMetrics.left;
var workspaceRight = viewMetrics.left + viewMetrics.width -
// Thickness in workspace units.
(Blockly.Scrollbar.scrollbarThickness / this.workspace_.scale);
}
@@ -613,24 +615,24 @@ Blockly.Bubble.prototype.getOptimalRelativeLeft_ = function(metrics) {
* Calculate what the optimal vertical position of the top-left corner of
* the bubble is (relative to the anchor point) so that the most area of the
* bubble is shown.
* @param {!Blockly.utils.Metrics} metrics The metrics of the workspace the
* bubble will appear in.
* @param {!Blockly.MetricsManager.ContainerRegion} viewMetrics The view metrics
* of the workspace the bubble will appear in.
* @return {number} The optimal vertical position of the top-left corner
* of the bubble.
* @private
*/
Blockly.Bubble.prototype.getOptimalRelativeTop_ = function(metrics) {
Blockly.Bubble.prototype.getOptimalRelativeTop_ = function(viewMetrics) {
var relativeTop = -this.height_ / 4;
// No amount of sliding up or down will give us a better overlap.
if (this.height_ > metrics.viewHeight) {
if (this.height_ > viewMetrics.height) {
return relativeTop;
}
var bubbleTop = this.anchorXY_.y + relativeTop;
var bubbleBottom = bubbleTop + this.height_;
var workspaceTop = metrics.viewTop;
var workspaceBottom = metrics.viewTop + metrics.viewHeight -
var workspaceTop = viewMetrics.top;
var workspaceBottom = viewMetrics.top + viewMetrics.height -
// Thickness in workspace units.
(Blockly.Scrollbar.scrollbarThickness / this.workspace_.scale);
@@ -820,10 +822,10 @@ Blockly.Bubble.prototype.setColour = function(hexColour) {
*/
Blockly.Bubble.prototype.dispose = function() {
if (this.onMouseDownBubbleWrapper_) {
Blockly.unbindEvent_(this.onMouseDownBubbleWrapper_);
Blockly.browserEvents.unbind(this.onMouseDownBubbleWrapper_);
}
if (this.onMouseDownResizeWrapper_) {
Blockly.unbindEvent_(this.onMouseDownResizeWrapper_);
Blockly.browserEvents.unbind(this.onMouseDownResizeWrapper_);
}
Blockly.Bubble.unbindDragEvents_();
Blockly.utils.dom.removeNode(this.bubbleGroup_);
@@ -887,8 +889,7 @@ Blockly.Bubble.prototype.setAutoLayout = function(enable) {
*/
Blockly.Bubble.textToDom = function(text) {
var paragraph = Blockly.utils.dom.createSvgElement(
Blockly.utils.Svg.TEXT,
{
Blockly.utils.Svg.TEXT, {
'class': 'blocklyText blocklyBubbleText blocklyNoPointerEvents',
'y': Blockly.Bubble.BORDER_WIDTH
},
@@ -906,16 +907,18 @@ Blockly.Bubble.textToDom = function(text) {
/**
* Creates a bubble that can not be edited.
* @param {!SVGTextElement} paragraphElement The text element for the non editable bubble.
* @param {!SVGTextElement} paragraphElement The text element for the non
* editable bubble.
* @param {!Blockly.BlockSvg} block The block that the bubble is attached to.
* @param {!Blockly.utils.Coordinate} iconXY The coordinate of the icon.
* @return {!Blockly.Bubble} The non editable bubble.
* @package
*/
Blockly.Bubble.createNonEditableBubble = function(paragraphElement, block, iconXY) {
Blockly.Bubble.createNonEditableBubble = function(
paragraphElement, block, iconXY) {
var bubble = new Blockly.Bubble(
/** @type {!Blockly.WorkspaceSvg} */ (block.workspace),
paragraphElement, block.pathObject.svgPath,
/** @type {!Blockly.WorkspaceSvg} */ (block.workspace), paragraphElement,
block.pathObject.svgPath,
/** @type {!Blockly.utils.Coordinate} */ (iconXY), null, null);
// Expose this bubble's block's ID on its top-level SVG group.
bubble.setSvgId(block.id);
@@ -923,9 +926,8 @@ Blockly.Bubble.createNonEditableBubble = function(paragraphElement, block, iconX
// Right-align the paragraph.
// This cannot be done until the bubble is rendered on screen.
var maxWidth = paragraphElement.getBBox().width;
for (var i = 0, textElement;
(textElement = paragraphElement.childNodes[i]); i++) {
for (var i = 0, textElement; (textElement = paragraphElement.childNodes[i]);
i++) {
textElement.setAttribute('text-anchor', 'end');
textElement.setAttribute('x', maxWidth + Blockly.Bubble.BORDER_WIDTH);
}

View File

@@ -12,14 +12,19 @@
goog.provide('Blockly.BubbleDragger');
/** @suppress {extraRequire} */
goog.require('Blockly.Bubble');
/** @suppress {extraRequire} */
goog.require('Blockly.constants');
goog.require('Blockly.Events');
/** @suppress {extraRequire} */
goog.require('Blockly.Events.CommentMove');
goog.require('Blockly.utils');
goog.require('Blockly.utils.Coordinate');
goog.requireType('Blockly.BlockDragSurfaceSvg');
goog.requireType('Blockly.IBubble');
goog.requireType('Blockly.WorkspaceSvg');
/**
@@ -226,7 +231,7 @@ Blockly.BubbleDragger.prototype.endBubbleDrag = function(
*/
Blockly.BubbleDragger.prototype.fireMoveEvent_ = function() {
if (this.draggingBubble_.isComment) {
var event = new Blockly.Events.CommentMove(
var event = new (Blockly.Events.get(Blockly.Events.COMMENT_MOVE))(
/** @type {!Blockly.WorkspaceCommentSvg} */ (this.draggingBubble_));
event.setOldCoordinate(this.startXY_);
event.recordNew();

View File

@@ -12,19 +12,28 @@
goog.provide('Blockly.Comment');
goog.require('Blockly.browserEvents');
goog.require('Blockly.Bubble');
goog.require('Blockly.Css');
goog.require('Blockly.Events');
/** @suppress {extraRequire} */
goog.require('Blockly.Events.BlockChange');
/** @suppress {extraRequire} */
goog.require('Blockly.Events.BubbleOpen');
goog.require('Blockly.Icon');
goog.require('Blockly.utils.deprecation');
goog.require('Blockly.utils.dom');
goog.require('Blockly.utils.object');
goog.require('Blockly.utils.Svg');
goog.require('Blockly.utils.userAgent');
/** @suppress {extraRequire} */
goog.require('Blockly.Warning');
goog.requireType('Blockly.Block');
goog.requireType('Blockly.BlockSvg');
goog.requireType('Blockly.utils.Coordinate');
goog.requireType('Blockly.utils.Size');
goog.requireType('Blockly.WorkspaceSvg');
/**
* Class for a comment.
@@ -55,28 +64,28 @@ Blockly.Comment = function(block) {
/**
* Mouse up event data.
* @type {?Blockly.EventData}
* @type {?Blockly.browserEvents.Data}
* @private
*/
this.onMouseUpWrapper_ = null;
/**
* Wheel event data.
* @type {?Blockly.EventData}
* @type {?Blockly.browserEvents.Data}
* @private
*/
this.onWheelWrapper_ = null;
/**
* Change event data.
* @type {?Blockly.EventData}
* @type {?Blockly.browserEvents.Data}
* @private
*/
this.onChangeWrapper_ = null;
/**
* Input event data.
* @type {?Blockly.EventData}
* @type {?Blockly.browserEvents.Data}
* @private
*/
this.onInputWrapper_ = null;
@@ -161,21 +170,23 @@ Blockly.Comment.prototype.createEditor_ = function() {
// Ideally this would be hooked to the focus event for the comment.
// However doing so in Firefox swallows the cursor for unknown reasons.
// So this is hooked to mouseup instead. No big deal.
this.onMouseUpWrapper_ = Blockly.bindEventWithChecks_(
this.onMouseUpWrapper_ = Blockly.browserEvents.conditionalBind(
textarea, 'mouseup', this, this.startEdit_, true, true);
// Don't zoom with mousewheel.
this.onWheelWrapper_ = Blockly.bindEventWithChecks_(
this.onWheelWrapper_ = Blockly.browserEvents.conditionalBind(
textarea, 'wheel', this, function(e) {
e.stopPropagation();
});
this.onChangeWrapper_ = Blockly.bindEventWithChecks_(
this.onChangeWrapper_ = Blockly.browserEvents.conditionalBind(
textarea, 'change', this, function(_e) {
if (this.cachedText_ != this.model_.text) {
Blockly.Events.fire(new Blockly.Events.BlockChange(
this.block_, 'comment', null, this.cachedText_, this.model_.text));
Blockly.Events.fire(
new (Blockly.Events.get(Blockly.Events.BLOCK_CHANGE))(
this.block_, 'comment', null, this.cachedText_,
this.model_.text));
}
});
this.onInputWrapper_ = Blockly.bindEventWithChecks_(
this.onInputWrapper_ = Blockly.browserEvents.conditionalBind(
textarea, 'input', this, function(_e) {
this.model_.text = textarea.value;
});
@@ -235,8 +246,8 @@ Blockly.Comment.prototype.setVisible = function(visible) {
if (visible == this.isVisible()) {
return;
}
Blockly.Events.fire(
new Blockly.Events.BubbleOpen(this.block_, visible, 'comment'));
Blockly.Events.fire(new (Blockly.Events.get(Blockly.Events.BUBBLE_OPEN))(
this.block_, visible, 'comment'));
this.model_.pinned = visible;
if (visible) {
this.createBubble_();
@@ -297,19 +308,19 @@ Blockly.Comment.prototype.createNonEditableBubble_ = function() {
*/
Blockly.Comment.prototype.disposeBubble_ = function() {
if (this.onMouseUpWrapper_) {
Blockly.unbindEvent_(this.onMouseUpWrapper_);
Blockly.browserEvents.unbind(this.onMouseUpWrapper_);
this.onMouseUpWrapper_ = null;
}
if (this.onWheelWrapper_) {
Blockly.unbindEvent_(this.onWheelWrapper_);
Blockly.browserEvents.unbind(this.onWheelWrapper_);
this.onWheelWrapper_ = null;
}
if (this.onChangeWrapper_) {
Blockly.unbindEvent_(this.onChangeWrapper_);
Blockly.browserEvents.unbind(this.onChangeWrapper_);
this.onChangeWrapper_ = null;
}
if (this.onInputWrapper_) {
Blockly.unbindEvent_(this.onInputWrapper_);
Blockly.browserEvents.unbind(this.onInputWrapper_);
this.onInputWrapper_ = null;
}
this.bubble_.dispose();

View File

@@ -12,14 +12,19 @@
goog.provide('Blockly.Connection');
goog.require('Blockly.connectionTypes');
/** @suppress {extraRequire} */
goog.require('Blockly.constants');
goog.require('Blockly.Events');
/** @suppress {extraRequire} */
goog.require('Blockly.Events.BlockMove');
goog.require('Blockly.utils.deprecation');
goog.require('Blockly.Xml');
goog.requireType('Blockly.Block');
goog.requireType('Blockly.IASTNodeLocationWithBlock');
goog.requireType('Blockly.IConnectionChecker');
goog.requireType('Blockly.Input');
/**
@@ -120,7 +125,7 @@ Blockly.Connection.prototype.connect_ = function(childConnection) {
shadowDom = /** @type {!Element} */ (Blockly.Xml.blockToDom(orphanBlock));
orphanBlock.dispose(false);
orphanBlock = null;
} else if (parentConnection.type == Blockly.INPUT_VALUE) {
} else if (parentConnection.type == Blockly.connectionTypes.INPUT_VALUE) {
// Value connections.
// If female block is already connected, disconnect and bump the male.
if (!orphanBlock.outputConnection) {
@@ -135,7 +140,8 @@ Blockly.Connection.prototype.connect_ = function(childConnection) {
orphanBlock.outputConnection.connect(connection);
orphanBlock = null;
}
} else if (parentConnection.type == Blockly.NEXT_STATEMENT) {
} else if (
parentConnection.type == Blockly.connectionTypes.NEXT_STATEMENT) {
// Statement connections.
// Statement blocks may be inserted into the middle of a stack.
// Split the stack.
@@ -186,7 +192,7 @@ Blockly.Connection.prototype.connect_ = function(childConnection) {
var event;
if (Blockly.Events.isEnabled()) {
event = new Blockly.Events.BlockMove(childBlock);
event = new (Blockly.Events.get(Blockly.Events.BLOCK_MOVE))(childBlock);
}
// Establish the connections.
Blockly.Connection.connectReciprocally_(parentConnection, childConnection);
@@ -232,8 +238,8 @@ Blockly.Connection.prototype.getSourceBlock = function() {
* @return {boolean} True if connection faces down or right.
*/
Blockly.Connection.prototype.isSuperior = function() {
return this.type == Blockly.INPUT_VALUE ||
this.type == Blockly.NEXT_STATEMENT;
return this.type == Blockly.connectionTypes.INPUT_VALUE ||
this.type == Blockly.connectionTypes.NEXT_STATEMENT;
};
/**
@@ -380,7 +386,8 @@ Blockly.Connection.singleConnection_ = function(block, orphanBlock) {
for (var i = 0; i < block.inputList.length; i++) {
var thisConnection = block.inputList[i].connection;
var typeChecker = output.getConnectionChecker();
if (thisConnection && thisConnection.type == Blockly.INPUT_VALUE &&
if (thisConnection &&
thisConnection.type == Blockly.connectionTypes.INPUT_VALUE &&
typeChecker.canConnect(output, thisConnection, false)) {
if (connection) {
return null; // More than one connection.
@@ -464,7 +471,7 @@ Blockly.Connection.prototype.disconnectInternal_ = function(parentBlock,
childBlock) {
var event;
if (Blockly.Events.isEnabled()) {
event = new Blockly.Events.BlockMove(childBlock);
event = new (Blockly.Events.get(Blockly.Events.BLOCK_MOVE))(childBlock);
}
var otherConnection = this.targetConnection;
otherConnection.targetConnection = null;

View File

@@ -13,11 +13,14 @@
goog.provide('Blockly.ConnectionChecker');
goog.require('Blockly.Connection');
goog.require('Blockly.connectionTypes');
/** @suppress {extraRequire} */
goog.require('Blockly.constants');
goog.require('Blockly.IConnectionChecker');
goog.require('Blockly.registry');
goog.requireType('Blockly.Connection');
goog.requireType('Blockly.IConnectionChecker');
goog.requireType('Blockly.RenderedConnection');
/**
@@ -197,9 +200,9 @@ Blockly.ConnectionChecker.prototype.doDragChecks = function(a, b, distance) {
}
switch (b.type) {
case Blockly.PREVIOUS_STATEMENT:
case Blockly.connectionTypes.PREVIOUS_STATEMENT:
return this.canConnectToPrevious_(a, b);
case Blockly.OUTPUT_VALUE: {
case Blockly.connectionTypes.OUTPUT_VALUE: {
// Don't offer to connect an already connected left (male) value plug to
// an available right (female) value plug.
if ((b.isConnected() &&
@@ -209,7 +212,7 @@ Blockly.ConnectionChecker.prototype.doDragChecks = function(a, b, distance) {
}
break;
}
case Blockly.INPUT_VALUE: {
case Blockly.connectionTypes.INPUT_VALUE: {
// Offering to connect the left (male) of a value block to an already
// connected value pair is ok, we'll splice it in.
// However, don't offer to splice into an immovable block.
@@ -220,7 +223,7 @@ Blockly.ConnectionChecker.prototype.doDragChecks = function(a, b, distance) {
}
break;
}
case Blockly.NEXT_STATEMENT: {
case Blockly.connectionTypes.NEXT_STATEMENT: {
// Don't let a block with no next connection bump other blocks out of the
// stack. But covering up a shadow block or stack of shadow blocks is
// fine. Similarly, replacing a terminal statement with another terminal

View File

@@ -14,10 +14,13 @@
goog.provide('Blockly.ConnectionDB');
goog.require('Blockly.connectionTypes');
/** @suppress {extraRequire} */
goog.require('Blockly.constants');
goog.require('Blockly.RenderedConnection');
goog.requireType('Blockly.IConnectionChecker');
goog.requireType('Blockly.utils.Coordinate');
/**
@@ -288,9 +291,13 @@ Blockly.ConnectionDB.prototype.searchForClosest = function(conn, maxRadius,
Blockly.ConnectionDB.init = function(checker) {
// Create four databases, one for each connection type.
var dbList = [];
dbList[Blockly.INPUT_VALUE] = new Blockly.ConnectionDB(checker);
dbList[Blockly.OUTPUT_VALUE] = new Blockly.ConnectionDB(checker);
dbList[Blockly.NEXT_STATEMENT] = new Blockly.ConnectionDB(checker);
dbList[Blockly.PREVIOUS_STATEMENT] = new Blockly.ConnectionDB(checker);
dbList[Blockly.connectionTypes.INPUT_VALUE] =
new Blockly.ConnectionDB(checker);
dbList[Blockly.connectionTypes.OUTPUT_VALUE] =
new Blockly.ConnectionDB(checker);
dbList[Blockly.connectionTypes.NEXT_STATEMENT] =
new Blockly.ConnectionDB(checker);
dbList[Blockly.connectionTypes.PREVIOUS_STATEMENT] =
new Blockly.ConnectionDB(checker);
return dbList;
};

29
core/connection_types.js Normal file
View File

@@ -0,0 +1,29 @@
/**
* @license
* Copyright 2021 Google LLC
* SPDX-License-Identifier: Apache-2.0
*/
/**
* @fileoverview An enum for the possible types of connections.
* @author fenichel@google.com (Rachel Fenichel)
*/
'use strict';
goog.provide('Blockly.connectionTypes');
/**
* Enum for the type of a connection or input.
* @enum {number}
*/
Blockly.connectionTypes = {
// A right-facing value input. E.g. 'set item to' or 'return'.
INPUT_VALUE: 1,
// A left-facing value output. E.g. 'random fraction'.
OUTPUT_VALUE: 2,
// A down-facing block stack. E.g. 'if-do' or 'else'.
NEXT_STATEMENT: 3,
// An up-facing block stack. E.g. 'break out of loop'.
PREVIOUS_STATEMENT: 4
};

View File

@@ -12,6 +12,9 @@
goog.provide('Blockly.constants');
goog.require('Blockly.connectionTypes');
/**
* The multiplier for scroll wheel deltas using the line delta mode.
* @type {number}
@@ -110,52 +113,14 @@ Blockly.SPRITE = {
// Constants below this point are not intended to be changed.
/**
* ENUM for a right-facing value input. E.g. 'set item to' or 'return'.
* @const
* Enum for alignment of inputs.
* @enum {number}
*/
Blockly.INPUT_VALUE = 1;
/**
* ENUM for a left-facing value output. E.g. 'random fraction'.
* @const
*/
Blockly.OUTPUT_VALUE = 2;
/**
* ENUM for a down-facing block stack. E.g. 'if-do' or 'else'.
* @const
*/
Blockly.NEXT_STATEMENT = 3;
/**
* ENUM for an up-facing block stack. E.g. 'break out of loop'.
* @const
*/
Blockly.PREVIOUS_STATEMENT = 4;
/**
* ENUM for an dummy input. Used to add field(s) with no input.
* @const
*/
Blockly.DUMMY_INPUT = 5;
/**
* ENUM for left alignment.
* @const
*/
Blockly.ALIGN_LEFT = -1;
/**
* ENUM for centre alignment.
* @const
*/
Blockly.ALIGN_CENTRE = 0;
/**
* ENUM for right alignment.
* @const
*/
Blockly.ALIGN_RIGHT = 1;
Blockly.constants.ALIGN = {
LEFT: -1,
CENTRE: 0,
RIGHT: 1
};
/**
* ENUM for no drag operation.
@@ -187,35 +152,14 @@ Blockly.DRAG_FREE = 2;
* @const
*/
Blockly.OPPOSITE_TYPE = [];
Blockly.OPPOSITE_TYPE[Blockly.INPUT_VALUE] = Blockly.OUTPUT_VALUE;
Blockly.OPPOSITE_TYPE[Blockly.OUTPUT_VALUE] = Blockly.INPUT_VALUE;
Blockly.OPPOSITE_TYPE[Blockly.NEXT_STATEMENT] = Blockly.PREVIOUS_STATEMENT;
Blockly.OPPOSITE_TYPE[Blockly.PREVIOUS_STATEMENT] = Blockly.NEXT_STATEMENT;
/**
* ENUM for toolbox and flyout at top of screen.
* @const
*/
Blockly.TOOLBOX_AT_TOP = 0;
/**
* ENUM for toolbox and flyout at bottom of screen.
* @const
*/
Blockly.TOOLBOX_AT_BOTTOM = 1;
/**
* ENUM for toolbox and flyout at left of screen.
* @const
*/
Blockly.TOOLBOX_AT_LEFT = 2;
/**
* ENUM for toolbox and flyout at right of screen.
* @const
*/
Blockly.TOOLBOX_AT_RIGHT = 3;
Blockly.OPPOSITE_TYPE[Blockly.connectionTypes.INPUT_VALUE] =
Blockly.connectionTypes.OUTPUT_VALUE;
Blockly.OPPOSITE_TYPE[Blockly.connectionTypes.OUTPUT_VALUE] =
Blockly.connectionTypes.INPUT_VALUE;
Blockly.OPPOSITE_TYPE[Blockly.connectionTypes.NEXT_STATEMENT] =
Blockly.connectionTypes.PREVIOUS_STATEMENT;
Blockly.OPPOSITE_TYPE[Blockly.connectionTypes.PREVIOUS_STATEMENT] =
Blockly.connectionTypes.NEXT_STATEMENT;
/**
* ENUM representing that an event is not in any delete areas.
@@ -275,3 +219,15 @@ Blockly.RENAME_VARIABLE_ID = 'RENAME_VARIABLE_ID';
* @const {string}
*/
Blockly.DELETE_VARIABLE_ID = 'DELETE_VARIABLE_ID';
/**
* The language-neutral id given to the collapsed input.
* @const {string}
*/
Blockly.constants.COLLAPSED_INPUT_NAME = '_TEMP_COLLAPSED_INPUT';
/**
* The language-neutral id given to the collapsed field.
* @const {string}
*/
Blockly.constants.COLLAPSED_FIELD_NAME = '_TEMP_COLLAPSED_FIELD';

View File

@@ -16,19 +16,27 @@
*/
goog.provide('Blockly.ContextMenu');
goog.require('Blockly.browserEvents');
/** @suppress {extraRequire} */
goog.require('Blockly.constants');
goog.require('Blockly.Events');
/** @suppress {extraRequire} */
goog.require('Blockly.Events.BlockCreate');
goog.require('Blockly.Menu');
goog.require('Blockly.MenuItem');
goog.require('Blockly.Msg');
goog.require('Blockly.utils');
goog.require('Blockly.utils.aria');
goog.require('Blockly.utils.Coordinate');
goog.require('Blockly.utils.dom');
goog.require('Blockly.utils.Rect');
goog.require('Blockly.utils.userAgent');
goog.require('Blockly.WidgetDiv');
goog.require('Blockly.Xml');
goog.requireType('Blockly.Block');
goog.requireType('Blockly.WorkspaceSvg');
/**
* Which block is the context menu attached to?
@@ -147,8 +155,9 @@ Blockly.ContextMenu.createWidget_ = function(menu) {
Blockly.utils.dom.addClass(
/** @type {!Element} */ (menuDom), 'blocklyContextMenu');
// Prevent system context menu when right-clicking a Blockly context menu.
Blockly.bindEventWithChecks_(/** @type {!EventTarget} */ (menuDom),
'contextmenu', null, Blockly.utils.noEvent);
Blockly.browserEvents.conditionalBind(
/** @type {!EventTarget} */ (menuDom), 'contextmenu', null,
Blockly.utils.noEvent);
// Focus only after the initial render to avoid issue #1329.
menu.focus();
};
@@ -196,7 +205,8 @@ Blockly.ContextMenu.callbackFactory = function(block, xml) {
Blockly.Events.enable();
}
if (Blockly.Events.isEnabled() && !newBlock.isShadow()) {
Blockly.Events.fire(new Blockly.Events.BlockCreate(newBlock));
Blockly.Events.fire(
new (Blockly.Events.get(Blockly.Events.BLOCK_CREATE))(newBlock));
}
newBlock.select();
};

View File

@@ -16,10 +16,15 @@
*/
goog.provide('Blockly.ContextMenuItems');
/** @suppress {extraRequire} */
goog.require('Blockly.constants');
goog.require('Blockly.ContextMenuRegistry');
goog.require('Blockly.Events');
goog.require('Blockly.inputTypes');
goog.requireType('Blockly.BlockSvg');
/** Option to undo previous action. */
Blockly.ContextMenuItems.registerUndo = function() {
/** @type {!Blockly.ContextMenuRegistry.RegistryItem} */
@@ -63,7 +68,7 @@ Blockly.ContextMenuItems.registerRedo = function() {
};
Blockly.ContextMenuRegistry.registry.register(redoOption);
};
/** Option to clean up blocks. */
Blockly.ContextMenuItems.registerCleanup = function() {
/** @type {!Blockly.ContextMenuRegistry.RegistryItem} */
@@ -89,7 +94,7 @@ Blockly.ContextMenuItems.registerCleanup = function() {
};
Blockly.ContextMenuRegistry.registry.register(cleanOption);
};
/**
* Creates a callback to collapse or expand top blocks.
* @param {boolean} shouldCollapse Whether a block should collapse.
@@ -141,7 +146,7 @@ Blockly.ContextMenuItems.registerCollapse = function() {
};
Blockly.ContextMenuRegistry.registry.register(collapseOption);
};
/** Option to expand all blocks. */
Blockly.ContextMenuItems.registerExpand = function() {
/** @type {!Blockly.ContextMenuRegistry.RegistryItem} */
@@ -174,7 +179,7 @@ Blockly.ContextMenuItems.registerExpand = function() {
};
Blockly.ContextMenuRegistry.registry.register(expandOption);
};
/**
* Adds a block and its children to a list of deletable blocks.
* @param {!Blockly.BlockSvg} block to delete.
@@ -192,7 +197,7 @@ Blockly.ContextMenuItems.addDeletableBlocks_ = function(block, deleteList) {
}
}
};
/**
* Constructs a list of blocks that can be deleted in the given workspace.
* @param {!Blockly.WorkspaceSvg} workspace to delete all blocks from.
@@ -207,7 +212,7 @@ Blockly.ContextMenuItems.getDeletableBlocks_ = function(workspace) {
}
return deleteList;
};
/** Deletes the given blocks. Used to delete all blocks in the workspace.
* @param {!Array.<!Blockly.BlockSvg>} deleteList list of blocks to delete.
* @param {string} eventGroup event group id with which all delete events should be associated.
@@ -227,7 +232,7 @@ Blockly.ContextMenuItems.deleteNext_ = function(deleteList, eventGroup) {
}
Blockly.Events.setGroup(false);
};
/** Option to delete all blocks. */
Blockly.ContextMenuItems.registerDeleteAll = function() {
/** @type {!Blockly.ContextMenuRegistry.RegistryItem} */
@@ -369,8 +374,8 @@ Blockly.ContextMenuItems.registerInline = function() {
if (!block.isInFlyout && block.isMovable() && !block.isCollapsed()) {
for (var i = 1; i < block.inputList.length; i++) {
// Only display this option if there are two value or dummy inputs next to each other.
if (block.inputList[i - 1].type != Blockly.NEXT_STATEMENT &&
block.inputList[i].type != Blockly.NEXT_STATEMENT) {
if (block.inputList[i - 1].type != Blockly.inputTypes.STATEMENT &&
block.inputList[i].type != Blockly.inputTypes.STATEMENT) {
return 'enabled';
}
}
@@ -533,4 +538,5 @@ Blockly.ContextMenuItems.registerDefaultOptions = function() {
Blockly.ContextMenuItems.registerWorkspaceOptions_();
Blockly.ContextMenuItems.registerBlockOptions_();
};
Blockly.ContextMenuItems.registerDefaultOptions();

View File

@@ -16,15 +16,17 @@
*/
goog.provide('Blockly.ContextMenuRegistry');
goog.require('Blockly.ContextMenuItems');
goog.requireType('Blockly.BlockSvg');
goog.requireType('Blockly.WorkspaceSvg');
/**
* Class for the registry of context menu items. This is intended to be a singleton. You should
* not create a new instance, and only access this class from Blockly.ContextMenuRegistry.registry.
* Class for the registry of context menu items. This is intended to be a
* singleton. You should not create a new instance, and only access this class
* from Blockly.ContextMenuRegistry.registry.
* @constructor
*/
Blockly.ContextMenuRegistry = function() {
// Singleton instance should be registered once.
Blockly.ContextMenuRegistry.registry = this;
@@ -34,7 +36,6 @@ Blockly.ContextMenuRegistry = function() {
* @private
*/
this.registry_ = {};
Blockly.ContextMenuItems.registerDefaultOptions();
};
/**
@@ -83,7 +84,8 @@ Blockly.ContextMenuRegistry.RegistryItem;
Blockly.ContextMenuRegistry.ContextMenuOption;
/**
* Singleton instance of this class. All interactions with this class should be done on this object.
* Singleton instance of this class. All interactions with this class should be
* done on this object.
* @type {?Blockly.ContextMenuRegistry}
*/
Blockly.ContextMenuRegistry.registry = null;

View File

@@ -17,10 +17,13 @@ goog.provide('Blockly.DropDownDiv');
goog.require('Blockly.utils.dom');
goog.require('Blockly.utils.math');
goog.require('Blockly.utils.Rect');
goog.require('Blockly.utils.style');
goog.requireType('Blockly.utils.Rect');
goog.requireType('Blockly.BlockSvg');
goog.requireType('Blockly.Field');
goog.requireType('Blockly.utils.Size');
goog.requireType('Blockly.WorkspaceSvg');
/**
@@ -148,7 +151,7 @@ Blockly.DropDownDiv.BoundsInfo;
* }}
*/
Blockly.DropDownDiv.PositionMetrics;
/**
* Create and insert the DOM element for this div.
* @package

View File

@@ -22,12 +22,14 @@ goog.provide('Blockly.Events.Move'); // Deprecated.
goog.require('Blockly.Events');
goog.require('Blockly.Events.Abstract');
goog.require('Blockly.connectionTypes');
goog.require('Blockly.registry');
goog.require('Blockly.utils.Coordinate');
goog.require('Blockly.utils.object');
goog.require('Blockly.utils.xml');
// TODO: Fix recursive dependency.
// goog.require('Blockly.Xml');
goog.require('Blockly.Xml');
goog.requireType('Blockly.Block');
/**
@@ -200,7 +202,7 @@ Blockly.Events.Change.prototype.run = function(forward) {
var dom = Blockly.Xml.textToDom(/** @type {string} */ (value) || '<mutation/>');
block.domToMutation(dom);
}
Blockly.Events.fire(new Blockly.Events.Change(
Blockly.Events.fire(new (Blockly.Events.get(Blockly.Events.CHANGE))(
block, 'mutation', null, oldMutation, value));
break;
default:
@@ -544,12 +546,13 @@ Blockly.Events.Move.prototype.run = function(forward) {
} else {
var blockConnection = block.outputConnection || block.previousConnection;
var parentConnection;
var connectionType = blockConnection.type;
if (inputName) {
var input = parentBlock.getInput(inputName);
if (input) {
parentConnection = input.connection;
}
} else if (blockConnection.type == Blockly.PREVIOUS_STATEMENT) {
} else if (connectionType == Blockly.connectionTypes.PREVIOUS_STATEMENT) {
parentConnection = parentBlock.nextConnection;
}
if (parentConnection) {

View File

@@ -19,6 +19,10 @@ goog.provide('Blockly.Events');
goog.require('Blockly.registry');
goog.require('Blockly.utils');
goog.requireType('Blockly.Block');
goog.requireType('Blockly.Events.Abstract');
goog.requireType('Blockly.Workspace');
/**
* Group ID for new events. Grouped events are indivisible.
@@ -196,11 +200,22 @@ Blockly.Events.COMMENT_MOVE = 'comment_move';
Blockly.Events.FINISHED_LOADING = 'finished_loading';
/**
* List of events that cause objects to be bumped back into the visible
* portion of the workspace (only used for non-movable workspaces).
* Type of events that cause objects to be bumped back into the visible
* portion of the workspace.
*
* Not to be confused with bumping so that disconnected connections to do
* not appear connected.
* Not to be confused with bumping so that disconnected connections do not
* appear connected.
* @typedef {!Blockly.Events.BlockCreate|!Blockly.Events.BlockMove|
* !Blockly.Events.CommentCreate|!Blockly.Events.CommentMove}
*/
Blockly.Events.BumpEvent;
/**
* List of events that cause objects to be bumped back into the visible
* portion of the workspace.
*
* Not to be confused with bumping so that disconnected connections do not
* appear connected.
* @const
*/
Blockly.Events.BUMP_EVENTS = [
@@ -395,8 +410,7 @@ Blockly.Events.getDescendantIds = function(block) {
* @throws {Error} if an event type is not found in the registry.
*/
Blockly.Events.fromJson = function(json, workspace) {
var eventClass = Blockly.registry.getClass(Blockly.registry.Type.EVENT,
json.type);
var eventClass = Blockly.Events.get(json.type);
if (!eventClass) {
throw Error('Unknown event type.');
}
@@ -406,6 +420,16 @@ Blockly.Events.fromJson = function(json, workspace) {
return event;
};
/**
* Gets the class for a specific event type from the registry.
* @param {string} eventType The type of the event to get.
* @return {?function(new:Blockly.Events.Abstract, ...?)} The event class with
* the given type or null if none exists.
*/
Blockly.Events.get = function(eventType) {
return Blockly.registry.getClass(Blockly.registry.Type.EVENT, eventType);
};
/**
* Enable/disable a block depending on whether it is properly connected.
* Use this on applications where all blocks should be connected to a top block.

View File

@@ -15,6 +15,8 @@ goog.provide('Blockly.Events.Abstract');
goog.require('Blockly.Events');
goog.requireType('Blockly.Workspace');
/**
* Abstract class for an event.

View File

@@ -17,6 +17,9 @@ goog.require('Blockly.Events.UiBase');
goog.require('Blockly.registry');
goog.require('Blockly.utils.object');
goog.requireType('Blockly.Block');
/**
* Class for a block drag event.
* @param {!Blockly.Block=} opt_block The top block in the stack that is being

View File

@@ -17,6 +17,9 @@ goog.require('Blockly.Events.UiBase');
goog.require('Blockly.registry');
goog.require('Blockly.utils.object');
goog.requireType('Blockly.BlockSvg');
/**
* Class for a bubble open event.
* @param {Blockly.BlockSvg} opt_block The associated block. Undefined for a

View File

@@ -17,6 +17,9 @@ goog.require('Blockly.Events.UiBase');
goog.require('Blockly.registry');
goog.require('Blockly.utils.object');
goog.requireType('Blockly.Block');
/**
* Class for a click event.
* @param {?Blockly.Block=} opt_block The affected block. Null for click events

View File

@@ -17,6 +17,11 @@ goog.require('Blockly.Events.UiBase');
goog.require('Blockly.registry');
goog.require('Blockly.utils.object');
goog.requireType('Blockly.ASTNode');
goog.requireType('Blockly.Block');
goog.requireType('Blockly.Workspace');
/**
* Class for a marker move event.
* @param {?Blockly.Block=} opt_block The affected block. Null if current node

View File

@@ -17,6 +17,7 @@ goog.require('Blockly.Events.UiBase');
goog.require('Blockly.registry');
goog.require('Blockly.utils.object');
/**
* Class for a selected event.
* @param {?string=} opt_oldElementId The id of the previously selected

View File

@@ -17,6 +17,7 @@ goog.require('Blockly.Events.UiBase');
goog.require('Blockly.registry');
goog.require('Blockly.utils.object');
/**
* Class for a theme change event.
* @param {string=} opt_themeName The theme name. Undefined for a blank event.

View File

@@ -17,6 +17,7 @@ goog.require('Blockly.Events.UiBase');
goog.require('Blockly.registry');
goog.require('Blockly.utils.object');
/**
* Class for a toolbox item select event.
* @param {?string=} opt_oldItem The previously selected toolbox item. Undefined

View File

@@ -17,6 +17,7 @@ goog.require('Blockly.Events.UiBase');
goog.require('Blockly.registry');
goog.require('Blockly.utils.object');
/**
* Class for a trashcan open event.
* @param {boolean=} opt_isOpen Whether the trashcan flyout is opening (false if

View File

@@ -17,6 +17,7 @@ goog.require('Blockly.Events.UiBase');
goog.require('Blockly.registry');
goog.require('Blockly.utils.object');
/**
* Class for a viewport change event.
* @param {number=} opt_top Top-edge of the visible portion of the workspace,
@@ -27,11 +28,13 @@ goog.require('Blockly.utils.object');
* event.
* @param {string=} opt_workspaceId The workspace identifier for this event.
* Undefined for a blank event.
* @param {number=} opt_oldScale The old scale of the workspace. Undefined for a
* blank event.
* @extends {Blockly.Events.UiBase}
* @constructor
*/
Blockly.Events.ViewportChange = function(opt_top, opt_left, opt_scale,
opt_workspaceId) {
opt_workspaceId, opt_oldScale) {
Blockly.Events.ViewportChange.superClass_.constructor.call(this, opt_workspaceId);
/**
@@ -53,6 +56,12 @@ Blockly.Events.ViewportChange = function(opt_top, opt_left, opt_scale,
* @type {number|undefined}
*/
this.scale = opt_scale;
/**
* The old scale of the workspace.
* @type {number|undefined}
*/
this.oldScale = opt_oldScale;
};
Blockly.utils.object.inherits(Blockly.Events.ViewportChange,
Blockly.Events.UiBase);
@@ -72,6 +81,7 @@ Blockly.Events.ViewportChange.prototype.toJson = function() {
json['viewTop'] = this.viewTop;
json['viewLeft'] = this.viewLeft;
json['scale'] = this.scale;
json['oldScale'] = this.oldScale;
return json;
};
@@ -84,6 +94,7 @@ Blockly.Events.ViewportChange.prototype.fromJson = function(json) {
this.viewTop = json['viewTop'];
this.viewLeft = json['viewLeft'];
this.scale = json['scale'];
this.oldScale = json['oldScale'];
};
Blockly.registry.register(Blockly.registry.Type.EVENT,

View File

@@ -18,6 +18,9 @@ goog.require('Blockly.Events.Abstract');
goog.require('Blockly.registry');
goog.require('Blockly.utils.object');
goog.requireType('Blockly.Block');
/**
* Base class for a UI event.
* UI events are events that don't need to be sent over the wire for multi-user

View File

@@ -20,6 +20,8 @@ goog.require('Blockly.Events.Abstract');
goog.require('Blockly.registry');
goog.require('Blockly.utils.object');
goog.requireType('Blockly.VariableModel');
/**
* Abstract class for a variable event.

View File

@@ -17,6 +17,8 @@ goog.require('Blockly.Events.Abstract');
goog.require('Blockly.registry');
goog.require('Blockly.utils.object');
goog.requireType('Blockly.Workspace');
/**
* Class for a finished loading event.

View File

@@ -22,8 +22,7 @@ goog.require('Blockly.registry');
goog.require('Blockly.utils.Coordinate');
goog.require('Blockly.utils.object');
goog.require('Blockly.utils.xml');
// TODO: Fix recursive dependency.
// goog.require('Blockly.Xml');
goog.require('Blockly.Xml');
/**
@@ -127,6 +126,7 @@ Blockly.Events.CommentChange.prototype.type = Blockly.Events.COMMENT_CHANGE;
*/
Blockly.Events.CommentChange.prototype.toJson = function() {
var json = Blockly.Events.CommentChange.superClass_.toJson.call(this);
json['oldContents'] = this.oldContents_;
json['newContents'] = this.newContents_;
return json;
};
@@ -137,7 +137,8 @@ Blockly.Events.CommentChange.prototype.toJson = function() {
*/
Blockly.Events.CommentChange.prototype.fromJson = function(json) {
Blockly.Events.CommentChange.superClass_.fromJson.call(this, json);
this.newContents_ = json['newValue'];
this.oldContents_ = json['oldContents'];
this.newContents_ = json['newContents'];
};
/**
@@ -359,6 +360,10 @@ Blockly.Events.CommentMove.prototype.setOldCoordinate = function(xy) {
// TODO (#1266): "Full" and "minimal" serialization.
Blockly.Events.CommentMove.prototype.toJson = function() {
var json = Blockly.Events.CommentMove.superClass_.toJson.call(this);
if (this.oldCoordinate_) {
json['oldCoordinate'] = Math.round(this.oldCoordinate_.x) + ',' +
Math.round(this.oldCoordinate_.y);
}
if (this.newCoordinate_) {
json['newCoordinate'] = Math.round(this.newCoordinate_.x) + ',' +
Math.round(this.newCoordinate_.y);
@@ -373,6 +378,11 @@ Blockly.Events.CommentMove.prototype.toJson = function() {
Blockly.Events.CommentMove.prototype.fromJson = function(json) {
Blockly.Events.CommentMove.superClass_.fromJson.call(this, json);
if (json['oldCoordinate']) {
var xy = json['oldCoordinate'].split(',');
this.oldCoordinate_ =
new Blockly.utils.Coordinate(Number(xy[0]), Number(xy[1]));
}
if (json['newCoordinate']) {
var xy = json['newCoordinate'].split(',');
this.newCoordinate_ =

View File

@@ -21,6 +21,8 @@ goog.provide('Blockly.Extensions');
goog.require('Blockly.utils');
goog.requireType('Blockly.Block');
/**
* The set of all registered extensions, keyed by extension name/id.

View File

@@ -14,8 +14,11 @@
goog.provide('Blockly.Field');
goog.require('Blockly.browserEvents');
goog.require('Blockly.Events');
/** @suppress {extraRequire} */
goog.require('Blockly.Events.BlockChange');
/** @suppress {extraRequire} */
goog.require('Blockly.Gesture');
goog.require('Blockly.Tooltip');
goog.require('Blockly.utils');
@@ -26,12 +29,17 @@ goog.require('Blockly.utils.style');
goog.require('Blockly.utils.Svg');
goog.require('Blockly.utils.userAgent');
goog.requireType('Blockly.Block');
goog.requireType('Blockly.blockRendering.ConstantProvider');
goog.requireType('Blockly.BlockSvg');
goog.requireType('Blockly.IASTNodeLocationSvg');
goog.requireType('Blockly.IASTNodeLocationWithBlock');
goog.requireType('Blockly.IBlocklyActionable');
goog.requireType('Blockly.IKeyboardAccessible');
goog.requireType('Blockly.Input');
goog.requireType('Blockly.IRegistrable');
goog.requireType('Blockly.ShortcutRegistry');
goog.requireType('Blockly.utils.Coordinate');
goog.requireType('Blockly.WorkspaceSvg');
/**
@@ -46,7 +54,7 @@ goog.requireType('Blockly.ShortcutRegistry');
* @constructor
* @implements {Blockly.IASTNodeLocationSvg}
* @implements {Blockly.IASTNodeLocationWithBlock}
* @implements {Blockly.IBlocklyActionable}
* @implements {Blockly.IKeyboardAccessible}
* @implements {Blockly.IRegistrable}
*/
Blockly.Field = function(value, opt_validator, opt_config) {
@@ -126,7 +134,7 @@ Blockly.Field = function(value, opt_validator, opt_config) {
/**
* Mouse down event listener data.
* @type {?Blockly.EventData}
* @type {?Blockly.browserEvents.Data}
* @private
*/
this.mouseDownWrapper_ = null;
@@ -376,9 +384,8 @@ Blockly.Field.prototype.createTextElement_ = function() {
*/
Blockly.Field.prototype.bindEvents_ = function() {
Blockly.Tooltip.bindMouseEvents(this.getClickTarget_());
this.mouseDownWrapper_ =
Blockly.bindEventWithChecks_(
this.getClickTarget_(), 'mousedown', this, this.onMouseDown_);
this.mouseDownWrapper_ = Blockly.browserEvents.conditionalBind(
this.getClickTarget_(), 'mousedown', this, this.onMouseDown_);
};
/**
@@ -414,7 +421,7 @@ Blockly.Field.prototype.dispose = function() {
Blockly.Tooltip.unbindMouseEvents(this.getClickTarget_());
if (this.mouseDownWrapper_) {
Blockly.unbindEvent_(this.mouseDownWrapper_);
Blockly.browserEvents.unbind(this.mouseDownWrapper_);
}
Blockly.utils.dom.removeNode(this.fieldGroup_);
@@ -826,7 +833,7 @@ Blockly.Field.prototype.setValue = function(newValue) {
}
if (source && Blockly.Events.isEnabled()) {
Blockly.Events.fire(new Blockly.Events.BlockChange(
Blockly.Events.fire(new (Blockly.Events.get(Blockly.Events.BLOCK_CHANGE))(
source, 'field', this.name || null, oldValue, newValue));
}
this.doValueUpdate_(newValue);
@@ -1024,13 +1031,12 @@ Blockly.Field.prototype.isTabNavigable = function() {
};
/**
* Handles the given action.
* This is only triggered when keyboard accessibility mode is enabled.
* @param {!Blockly.ShortcutRegistry.KeyboardShortcut} _action The action to be handled.
* @return {boolean} True if the field handled the action, false otherwise.
* @package
* Handles the given keyboard shortcut.
* @param {!Blockly.ShortcutRegistry.KeyboardShortcut} _shortcut The shortcut to be handled.
* @return {boolean} True if the shortcut has been handled, false otherwise.
* @public
*/
Blockly.Field.prototype.onBlocklyAction = function(_action) {
Blockly.Field.prototype.onShortcut = function(_shortcut) {
return false;
};
@@ -1077,6 +1083,7 @@ Blockly.Field.prototype.updateMarkers_ = function() {
workspace.getCursor().draw();
}
if (workspace.keyboardAccessibilityMode && this.markerSvg_) {
workspace.getMarker(Blockly.navigation.MARKER_NAME).draw();
// TODO(#4592): Update all markers on the field.
workspace.getMarker(Blockly.MarkerManager.LOCAL_MARKER).draw();
}
};

View File

@@ -12,6 +12,7 @@
goog.provide('Blockly.FieldAngle');
goog.require('Blockly.browserEvents');
goog.require('Blockly.Css');
goog.require('Blockly.DropDownDiv');
goog.require('Blockly.fieldRegistry');
@@ -88,21 +89,21 @@ Blockly.FieldAngle = function(opt_value, opt_validator, opt_config) {
/**
* Wrapper click event data.
* @type {?Blockly.EventData}
* @type {?Blockly.browserEvents.Data}
* @private
*/
this.clickWrapper_ = null;
/**
* Surface click event data.
* @type {?Blockly.EventData}
* @type {?Blockly.browserEvents.Data}
* @private
*/
this.clickSurfaceWrapper_ = null;
/**
* Surface mouse move event data.
* @type {?Blockly.EventData}
* @type {?Blockly.browserEvents.Data}
* @private
*/
this.moveSurfaceWrapper_ = null;
@@ -331,16 +332,14 @@ Blockly.FieldAngle.prototype.dropdownCreate_ = function() {
// mousemove even if it's not in the middle of a drag. In future we may
// change this behaviour.
this.clickWrapper_ =
Blockly.bindEventWithChecks_(svg, 'click', this, this.hide_);
Blockly.browserEvents.conditionalBind(svg, 'click', this, this.hide_);
// On touch devices, the picker's value is only updated with a drag. Add
// a click handler on the drag surface to update the value if the surface
// is clicked.
this.clickSurfaceWrapper_ =
Blockly.bindEventWithChecks_(circle, 'click', this, this.onMouseMove_,
true, true);
this.moveSurfaceWrapper_ =
Blockly.bindEventWithChecks_(circle, 'mousemove', this, this.onMouseMove_,
true, true);
this.clickSurfaceWrapper_ = Blockly.browserEvents.conditionalBind(
circle, 'click', this, this.onMouseMove_, true, true);
this.moveSurfaceWrapper_ = Blockly.browserEvents.conditionalBind(
circle, 'mousemove', this, this.onMouseMove_, true, true);
return svg;
};
@@ -350,15 +349,15 @@ Blockly.FieldAngle.prototype.dropdownCreate_ = function() {
*/
Blockly.FieldAngle.prototype.dropdownDispose_ = function() {
if (this.clickWrapper_) {
Blockly.unbindEvent_(this.clickWrapper_);
Blockly.browserEvents.unbind(this.clickWrapper_);
this.clickWrapper_ = null;
}
if (this.clickSurfaceWrapper_) {
Blockly.unbindEvent_(this.clickSurfaceWrapper_);
Blockly.browserEvents.unbind(this.clickSurfaceWrapper_);
this.clickSurfaceWrapper_ = null;
}
if (this.moveSurfaceWrapper_) {
Blockly.unbindEvent_(this.moveSurfaceWrapper_);
Blockly.browserEvents.unbind(this.moveSurfaceWrapper_);
this.moveSurfaceWrapper_ = null;
}
this.gauge_ = null;

View File

@@ -12,13 +12,12 @@
goog.provide('Blockly.FieldCheckbox');
goog.require('Blockly.Events');
/** @suppress {extraRequire} */
goog.require('Blockly.Events.BlockChange');
goog.require('Blockly.Field');
goog.require('Blockly.fieldRegistry');
goog.require('Blockly.utils.dom');
goog.require('Blockly.utils.object');
goog.require('Blockly.utils.Size');
/**

View File

@@ -12,13 +12,13 @@
goog.provide('Blockly.FieldColour');
goog.require('Blockly.browserEvents');
goog.require('Blockly.Css');
goog.require('Blockly.DropDownDiv');
goog.require('Blockly.Events');
/** @suppress {extraRequire} */
goog.require('Blockly.Events.BlockChange');
goog.require('Blockly.Field');
goog.require('Blockly.fieldRegistry');
goog.require('Blockly.navigation');
goog.require('Blockly.utils.aria');
goog.require('Blockly.utils.colour');
goog.require('Blockly.utils.dom');
@@ -27,7 +27,6 @@ goog.require('Blockly.utils.KeyCodes');
goog.require('Blockly.utils.object');
goog.require('Blockly.utils.Size');
goog.requireType('Blockly.ShortcutRegistry');
/**
* Class for a colour input field.
@@ -62,35 +61,35 @@ Blockly.FieldColour = function(opt_value, opt_validator, opt_config) {
/**
* Mouse click event data.
* @type {?Blockly.EventData}
* @type {?Blockly.browserEvents.Data}
* @private
*/
this.onClickWrapper_ = null;
/**
* Mouse move event data.
* @type {?Blockly.EventData}
* @type {?Blockly.browserEvents.Data}
* @private
*/
this.onMouseMoveWrapper_ = null;
/**
* Mouse enter event data.
* @type {?Blockly.EventData}
* @type {?Blockly.browserEvents.Data}
* @private
*/
this.onMouseEnterWrapper_ = null;
/**
* Mouse leave event data.
* @type {?Blockly.EventData}
* @type {?Blockly.browserEvents.Data}
* @private
*/
this.onMouseLeaveWrapper_ = null;
/**
* Key down event data.
* @type {?Blockly.EventData}
* @type {?Blockly.browserEvents.Data}
* @private
*/
this.onKeyDownWrapper_ = null;
@@ -189,7 +188,7 @@ Blockly.FieldColour.prototype.initView = function() {
Blockly.FieldColour.prototype.applyColour = function() {
if (!this.getConstants().FIELD_COLOUR_FULL_BLOCK) {
if (this.borderRect_) {
this.borderRect_.style.fill = this.getValue();
this.borderRect_.style.fill = /** @type {string} */ (this.getValue());
}
} else {
this.sourceBlock_.pathObject.svgPath.setAttribute('fill', this.getValue());
@@ -219,7 +218,7 @@ Blockly.FieldColour.prototype.doClassValidation_ = function(opt_newValue) {
Blockly.FieldColour.prototype.doValueUpdate_ = function(newValue) {
this.value_ = newValue;
if (this.borderRect_) {
this.borderRect_.style.fill = newValue;
this.borderRect_.style.fill = /** @type {string} */ (newValue);
} else if (this.sourceBlock_ && this.sourceBlock_.rendered) {
this.sourceBlock_.pathObject.svgPath.setAttribute('fill', newValue);
this.sourceBlock_.pathObject.svgPath.setAttribute('stroke', '#fff');
@@ -382,35 +381,6 @@ Blockly.FieldColour.prototype.onKeyDown_ = function(e) {
}
};
/**
* Handles the given action.
* This is only triggered when keyboard accessibility mode is enabled.
* @param {!Blockly.ShortcutRegistry.KeyboardShortcut} action The action to be handled.
* @return {boolean} True if the field handled the action, false otherwise.
* @package
*/
Blockly.FieldColour.prototype.onBlocklyAction = function(action) {
if (this.picker_) {
switch (action.name) {
case Blockly.navigation.actionNames.PREVIOUS:
this.moveHighlightBy_(0, -1);
return true;
case Blockly.navigation.actionNames.NEXT:
this.moveHighlightBy_(0, 1);
return true;
case Blockly.navigation.actionNames.OUT:
this.moveHighlightBy_(-1, 0);
return true;
case Blockly.navigation.actionNames.IN:
this.moveHighlightBy_(1, 0);
return true;
default:
return false;
}
}
return Blockly.FieldColour.superClass_.onBlocklyAction.call(this, action);
};
/**
* Move the currently highlighted position by dx and dy.
* @param {number} dx Change of x
@@ -586,16 +556,16 @@ Blockly.FieldColour.prototype.dropdownCreate_ = function() {
}
// Configure event handler on the table to listen for any event in a cell.
this.onClickWrapper_ = Blockly.bindEventWithChecks_(table,
'click', this, this.onClick_, true);
this.onMouseMoveWrapper_ = Blockly.bindEventWithChecks_(table,
'mousemove', this, this.onMouseMove_, true);
this.onMouseEnterWrapper_ = Blockly.bindEventWithChecks_(table,
'mouseenter', this, this.onMouseEnter_, true);
this.onMouseLeaveWrapper_ = Blockly.bindEventWithChecks_(table,
'mouseleave', this, this.onMouseLeave_, true);
this.onKeyDownWrapper_ = Blockly.bindEventWithChecks_(table,
'keydown', this, this.onKeyDown_);
this.onClickWrapper_ = Blockly.browserEvents.conditionalBind(
table, 'click', this, this.onClick_, true);
this.onMouseMoveWrapper_ = Blockly.browserEvents.conditionalBind(
table, 'mousemove', this, this.onMouseMove_, true);
this.onMouseEnterWrapper_ = Blockly.browserEvents.conditionalBind(
table, 'mouseenter', this, this.onMouseEnter_, true);
this.onMouseLeaveWrapper_ = Blockly.browserEvents.conditionalBind(
table, 'mouseleave', this, this.onMouseLeave_, true);
this.onKeyDownWrapper_ = Blockly.browserEvents.conditionalBind(
table, 'keydown', this, this.onKeyDown_);
return table;
};
@@ -606,23 +576,23 @@ Blockly.FieldColour.prototype.dropdownCreate_ = function() {
*/
Blockly.FieldColour.prototype.dropdownDispose_ = function() {
if (this.onClickWrapper_) {
Blockly.unbindEvent_(this.onClickWrapper_);
Blockly.browserEvents.unbind(this.onClickWrapper_);
this.onClickWrapper_ = null;
}
if (this.onMouseMoveWrapper_) {
Blockly.unbindEvent_(this.onMouseMoveWrapper_);
Blockly.browserEvents.unbind(this.onMouseMoveWrapper_);
this.onMouseMoveWrapper_ = null;
}
if (this.onMouseEnterWrapper_) {
Blockly.unbindEvent_(this.onMouseEnterWrapper_);
Blockly.browserEvents.unbind(this.onMouseEnterWrapper_);
this.onMouseEnterWrapper_ = null;
}
if (this.onMouseLeaveWrapper_) {
Blockly.unbindEvent_(this.onMouseLeaveWrapper_);
Blockly.browserEvents.unbind(this.onMouseLeaveWrapper_);
this.onMouseLeaveWrapper_ = null;
}
if (this.onKeyDownWrapper_) {
Blockly.unbindEvent_(this.onKeyDownWrapper_);
Blockly.browserEvents.unbind(this.onKeyDownWrapper_);
this.onKeyDownWrapper_ = null;
}
this.picker_ = null;

View File

@@ -14,25 +14,19 @@
goog.provide('Blockly.FieldDropdown');
goog.require('Blockly.Events');
goog.require('Blockly.Events.BlockChange');
goog.require('Blockly.Field');
goog.require('Blockly.fieldRegistry');
goog.require('Blockly.Menu');
goog.require('Blockly.MenuItem');
goog.require('Blockly.navigation');
goog.require('Blockly.utils');
goog.require('Blockly.utils.aria');
goog.require('Blockly.utils.Coordinate');
goog.require('Blockly.utils.dom');
goog.require('Blockly.utils.object');
goog.require('Blockly.utils.Size');
goog.require('Blockly.utils.string');
goog.require('Blockly.utils.Svg');
goog.require('Blockly.utils.userAgent');
goog.requireType('Blockly.ShortcutRegistry');
/**
* Class for an editable dropdown field.
@@ -157,6 +151,20 @@ Blockly.FieldDropdown.fromJson = function(options) {
return new Blockly.FieldDropdown(options['options'], undefined, options);
};
/**
* Sets the field's value based on the given XML element. Should only be
* called by Blockly.Xml.
* @param {!Element} fieldElement The element containing info about the
* field's state.
* @package
*/
Blockly.FieldDropdown.prototype.fromXml = function(fieldElement) {
if (this.isOptionListDynamic()) {
this.getOptions(false);
}
this.setValue(fieldElement.textContent);
};
/**
* Serializable fields are saved by the XML renderer, non-serializable fields
* are not. Editable fields should also be serializable.
@@ -738,28 +746,4 @@ Blockly.FieldDropdown.validateOptions_ = function(options) {
}
};
/**
* Handles the given action.
* This is only triggered when keyboard accessibility mode is enabled.
* @param {!Blockly.ShortcutRegistry.KeyboardShortcut} action The action to be handled.
* @return {boolean} True if the field handled the action, false otherwise.
* @package
*/
Blockly.FieldDropdown.prototype.onBlocklyAction = function(action) {
if (this.menu_) {
switch (action.name) {
case Blockly.navigation.actionNames.PREVIOUS:
this.menu_.highlightPrevious();
return true;
case Blockly.navigation.actionNames.NEXT:
this.menu_.highlightNext();
return true;
default:
return false;
}
}
return Blockly.FieldDropdown.superClass_.onBlocklyAction.call(this, action);
};
Blockly.fieldRegistry.register('field_dropdown', Blockly.FieldDropdown);

View File

@@ -18,7 +18,6 @@ goog.require('Blockly.fieldRegistry');
goog.require('Blockly.utils');
goog.require('Blockly.utils.dom');
goog.require('Blockly.utils.object');
goog.require('Blockly.utils.Size');
/**

View File

@@ -15,11 +15,9 @@
goog.provide('Blockly.FieldMultilineInput');
goog.require('Blockly.Css');
goog.require('Blockly.DropDownDiv');
goog.require('Blockly.FieldTextInput');
goog.require('Blockly.utils');
goog.require('Blockly.utils.aria');
goog.require('Blockly.utils.Coordinate');
goog.require('Blockly.utils.dom');
goog.require('Blockly.utils.KeyCodes');
goog.require('Blockly.utils.object');
@@ -51,10 +49,33 @@ Blockly.FieldMultilineInput = function(opt_value, opt_validator, opt_config) {
* @type {SVGGElement}
*/
this.textGroup_ = null;
/**
* Defines the maximum number of lines of field.
* If exceeded, scrolling functionality is enabled.
* @type {number}
* @protected
*/
this.maxLines_ = Infinity;
/**
* Whether Y overflow is currently occuring.
* @type {boolean}
* @protected
*/
this.isOverflowedY_ = false;
};
Blockly.utils.object.inherits(Blockly.FieldMultilineInput,
Blockly.FieldTextInput);
/**
* @override
*/
Blockly.FieldMultilineInput.prototype.configure_ = function(config) {
Blockly.FieldMultilineInput.superClass_.configure_.call(this, config);
config.maxLines && this.setMaxLines(config.maxLines);
};
/**
* Construct a FieldMultilineInput from a JSON arg object,
* dereferencing any string table references.
@@ -121,17 +142,20 @@ Blockly.FieldMultilineInput.prototype.getDisplayText_ = function() {
}
var lines = textLines.split('\n');
textLines = '';
for (var i = 0; i < lines.length; i++) {
var displayLinesNumber = this.isOverflowedY_ ? this.maxLines_ : lines.length;
for (var i = 0; i < displayLinesNumber; i++) {
var text = lines[i];
if (text.length > this.maxDisplayLength) {
// Truncate displayed string and add an ellipsis ('...').
text = text.substring(0, this.maxDisplayLength - 4) + '...';
} else if (this.isOverflowedY_ && i === displayLinesNumber - 1) {
text = text.substring(0, text.length - 3) + '...';
}
// Replace whitespace with non-breaking spaces so the text doesn't collapse.
text = text.replace(/\s/g, Blockly.Field.NBSP);
textLines += text;
if (i !== lines.length - 1) {
if (i !== displayLinesNumber - 1) {
textLines += '\n';
}
}
@@ -142,6 +166,20 @@ Blockly.FieldMultilineInput.prototype.getDisplayText_ = function() {
return textLines;
};
/**
* Called by setValue if the text input is valid. Updates the value of the
* field, and updates the text of the field if it is not currently being
* edited (i.e. handled by the htmlInput_). Is being redefined here to update
* overflow state of the field.
* @param {*} newValue The value to be saved. The default validator guarantees
* that this is a string.
* @protected
*/
Blockly.FieldMultilineInput.prototype.doValueUpdate_ = function(newValue) {
Blockly.FieldMultilineInput.superClass_.doValueUpdate_.call(this, newValue);
this.isOverflowedY_ = this.value_.split('\n').length > this.maxLines_;
};
/**
* Updates the text of the textElement.
* @protected
@@ -170,6 +208,15 @@ Blockly.FieldMultilineInput.prototype.render_ = function() {
y += lineHeight;
}
if (this.isBeingEdited_) {
var htmlInput = /** @type {!HTMLElement} */(this.htmlInput_);
if (this.isOverflowedY_) {
Blockly.utils.dom.addClass(htmlInput, 'blocklyHtmlTextAreaInputOverflowedY');
} else {
Blockly.utils.dom.removeClass(htmlInput, 'blocklyHtmlTextAreaInputOverflowedY');
}
}
this.updateSize_();
if (this.isBeingEdited_) {
@@ -211,6 +258,34 @@ Blockly.FieldMultilineInput.prototype.updateSize_ = function() {
totalHeight += this.getConstants().FIELD_TEXT_HEIGHT +
(i > 0 ? this.getConstants().FIELD_BORDER_RECT_Y_PADDING : 0);
}
if (this.isBeingEdited_) {
// The default width is based on the longest line in the display text,
// but when it's being edited, width should be calculated based on the
// absolute longest line, even if it would be truncated after editing.
// Otherwise we would get wrong editor width when there are more
// lines than this.maxLines_.
var actualEditorLines = this.value_.split('\n');
var dummyTextElement = Blockly.utils.dom.createSvgElement(
Blockly.utils.Svg.TEXT,{'class': 'blocklyText blocklyMultilineText'});
var fontSize = this.getConstants().FIELD_TEXT_FONTSIZE;
var fontWeight = this.getConstants().FIELD_TEXT_FONTWEIGHT;
var fontFamily = this.getConstants().FIELD_TEXT_FONTFAMILY;
for (var i = 0; i < actualEditorLines.length; i++) {
if (actualEditorLines[i].length > this.maxDisplayLength) {
actualEditorLines[i] = actualEditorLines[i].substring(0, this.maxDisplayLength);
}
dummyTextElement.textContent = actualEditorLines[i];
var lineWidth = Blockly.utils.dom.getFastTextWidth(
dummyTextElement, fontSize, fontWeight, fontFamily);
if (lineWidth > totalWidth) {
totalWidth = lineWidth;
}
}
var scrollbarWidth = this.htmlInput_.offsetWidth - this.htmlInput_.clientWidth;
totalWidth += scrollbarWidth;
}
if (this.borderRect_) {
totalHeight += this.getConstants().FIELD_BORDER_RECT_Y_PADDING * 2;
totalWidth += this.getConstants().FIELD_BORDER_RECT_X_PADDING * 2;
@@ -223,6 +298,21 @@ Blockly.FieldMultilineInput.prototype.updateSize_ = function() {
this.positionBorderRect_();
};
/**
* Show the inline free-text editor on top of the text.
* Overrides the default behaviour to force rerender in order to
* correct block size, based on editor text.
* @param {Event=} _opt_e Optional mouse event that triggered the field to open,
* or undefined if triggered programmatically.
* @param {boolean=} opt_quietInput True if editor should be created without
* focus. Defaults to false.
* @override
*/
Blockly.FieldMultilineInput.prototype.showEditor_ = function(_opt_e, opt_quietInput) {
Blockly.FieldMultilineInput.superClass_.showEditor_.call(this, _opt_e, opt_quietInput);
this.forceRerender();
};
/**
* Create the text input editor widget.
* @return {!HTMLTextAreaElement} The newly created text input editor.
@@ -266,6 +356,26 @@ Blockly.FieldMultilineInput.prototype.widgetCreate_ = function() {
return htmlInput;
};
/**
* Sets the maxLines config for this field.
* @param {number} maxLines Defines the maximum number of lines allowed,
* before scrolling functionality is enabled.
*/
Blockly.FieldMultilineInput.prototype.setMaxLines = function(maxLines) {
if (typeof maxLines === 'number' && maxLines > 0 && maxLines !== this.maxLines_) {
this.maxLines_ = maxLines;
this.forceRerender();
}
};
/**
* Returns the maxLines config of this field.
* @return {number} The maxLines config value.
*/
Blockly.FieldMultilineInput.prototype.getMaxLines = function() {
return this.maxLines_;
};
/**
* Handle key down to the editor. Override the text input definition of this
* so as to not close the editor when enter is typed in.
@@ -289,6 +399,9 @@ Blockly.Css.register([
'overflow: hidden;',
'height: 100%;',
'text-align: left;',
'}',
'.blocklyHtmlTextAreaInputOverflowedY {',
'overflow-y: scroll;',
'}'
/* eslint-enable indent */
]);

View File

@@ -16,6 +16,7 @@ goog.provide('Blockly.fieldRegistry');
goog.require('Blockly.registry');
goog.requireType('Blockly.Field');
goog.requireType('Blockly.IRegistrableField');

View File

@@ -12,7 +12,9 @@
goog.provide('Blockly.FieldTextInput');
goog.require('Blockly.browserEvents');
goog.require('Blockly.Events');
/** @suppress {extraRequire} */
goog.require('Blockly.Events.BlockChange');
goog.require('Blockly.Field');
goog.require('Blockly.fieldRegistry');
@@ -23,9 +25,11 @@ goog.require('Blockly.utils.Coordinate');
goog.require('Blockly.utils.dom');
goog.require('Blockly.utils.KeyCodes');
goog.require('Blockly.utils.object');
goog.require('Blockly.utils.Size');
goog.require('Blockly.utils.userAgent');
goog.requireType('Blockly.BlockSvg');
goog.requireType('Blockly.WorkspaceSvg');
/**
* Class for an editable text field.
@@ -59,14 +63,14 @@ Blockly.FieldTextInput = function(opt_value, opt_validator, opt_config) {
/**
* Key down event data.
* @type {?Blockly.EventData}
* @type {?Blockly.browserEvents.Data}
* @private
*/
this.onKeyDownWrapper_ = null;
/**
* Key input event data.
* @type {?Blockly.EventData}
* @type {?Blockly.browserEvents.Data}
* @private
*/
this.onKeyInputWrapper_ = null;
@@ -199,7 +203,7 @@ Blockly.FieldTextInput.prototype.doValueInvalid_ = function(_invalidValue) {
// Revert value when the text becomes invalid.
this.value_ = this.htmlInput_.untypedDefaultValue_;
if (this.sourceBlock_ && Blockly.Events.isEnabled()) {
Blockly.Events.fire(new Blockly.Events.BlockChange(
Blockly.Events.fire(new (Blockly.Events.get(Blockly.Events.BLOCK_CHANGE))(
this.sourceBlock_, 'field', this.name || null, oldValue, this.value_));
}
}
@@ -418,13 +422,11 @@ Blockly.FieldTextInput.prototype.widgetDispose_ = function() {
*/
Blockly.FieldTextInput.prototype.bindInputEvents_ = function(htmlInput) {
// Trap Enter without IME and Esc to hide.
this.onKeyDownWrapper_ =
Blockly.bindEventWithChecks_(
htmlInput, 'keydown', this, this.onHtmlInputKeyDown_);
this.onKeyDownWrapper_ = Blockly.browserEvents.conditionalBind(
htmlInput, 'keydown', this, this.onHtmlInputKeyDown_);
// Resize after every input change.
this.onKeyInputWrapper_ =
Blockly.bindEventWithChecks_(
htmlInput, 'input', this, this.onHtmlInputChange_);
this.onKeyInputWrapper_ = Blockly.browserEvents.conditionalBind(
htmlInput, 'input', this, this.onHtmlInputChange_);
};
/**
@@ -433,11 +435,11 @@ Blockly.FieldTextInput.prototype.bindInputEvents_ = function(htmlInput) {
*/
Blockly.FieldTextInput.prototype.unbindInputEvents_ = function() {
if (this.onKeyDownWrapper_) {
Blockly.unbindEvent_(this.onKeyDownWrapper_);
Blockly.browserEvents.unbind(this.onKeyDownWrapper_);
this.onKeyDownWrapper_ = null;
}
if (this.onKeyInputWrapper_) {
Blockly.unbindEvent_(this.onKeyInputWrapper_);
Blockly.browserEvents.unbind(this.onKeyInputWrapper_);
this.onKeyInputWrapper_ = null;
}
};

View File

@@ -12,8 +12,10 @@
goog.provide('Blockly.FieldVariable');
/** @suppress {extraRequire} */
/** @suppress {extraRequire} */
goog.require('Blockly.constants');
goog.require('Blockly.Events');
/** @suppress {extraRequire} */
goog.require('Blockly.Events.BlockChange');
goog.require('Blockly.FieldDropdown');
goog.require('Blockly.fieldRegistry');
@@ -25,6 +27,9 @@ goog.require('Blockly.VariableModel');
goog.require('Blockly.Variables');
goog.require('Blockly.Xml');
goog.requireType('Blockly.Block');
goog.requireType('Blockly.Menu');
goog.requireType('Blockly.MenuItem');
/**

View File

@@ -13,29 +13,36 @@
goog.provide('Blockly.Flyout');
goog.require('Blockly.Block');
/** @suppress {extraRequire} */
goog.require('Blockly.blockRendering');
goog.require('Blockly.browserEvents');
goog.require('Blockly.Events');
/** @suppress {extraRequire} */
goog.require('Blockly.Events.BlockCreate');
/** @suppress {extraRequire} */
goog.require('Blockly.Events.VarCreate');
goog.require('Blockly.FlyoutCursor');
goog.require('Blockly.FlyoutMetricsManager');
/** @suppress {extraRequire} */
goog.require('Blockly.Gesture');
goog.require('Blockly.Marker');
goog.require('Blockly.Scrollbar');
goog.require('Blockly.ScrollbarPair');
goog.require('Blockly.Tooltip');
/** @suppress {extraRequire} */
goog.require('Blockly.Touch');
goog.require('Blockly.utils');
goog.require('Blockly.utils.Coordinate');
goog.require('Blockly.utils.dom');
goog.require('Blockly.utils.Svg');
goog.require('Blockly.utils.toolbox');
goog.require('Blockly.utils.xml');
goog.require('Blockly.WorkspaceSvg');
goog.require('Blockly.Xml');
goog.requireType('Blockly.IBlocklyActionable');
goog.requireType('Blockly.BlockSvg');
goog.requireType('Blockly.FlyoutButton');
goog.requireType('Blockly.IDeleteArea');
goog.requireType('Blockly.IFlyout');
goog.requireType('Blockly.ShortcutRegistry');
goog.requireType('Blockly.utils.Metrics');
goog.requireType('Blockly.Options');
goog.requireType('Blockly.utils.Rect');
/**
@@ -44,14 +51,10 @@ goog.requireType('Blockly.utils.Metrics');
* workspace.
* @constructor
* @abstract
* @implements {Blockly.IBlocklyActionable}
* @implements {Blockly.IDeleteArea}
* @implements {Blockly.IFlyout}
*/
Blockly.Flyout = function(workspaceOptions) {
workspaceOptions.getMetrics =
/** @type {function():!Blockly.utils.Metrics} */ (
this.getMetrics_.bind(this));
workspaceOptions.setMetrics = this.setMetrics_.bind(this);
/**
@@ -59,6 +62,9 @@ Blockly.Flyout = function(workspaceOptions) {
* @protected
*/
this.workspace_ = new Blockly.WorkspaceSvg(workspaceOptions);
this.workspace_.setMetricsManager(
new Blockly.FlyoutMetricsManager(this.workspace_, this));
this.workspace_.isFlyout = true;
// Keep the workspace visibility consistent with the flyout's visibility.
this.workspace_.setVisible(this.isVisible_);
@@ -253,7 +259,6 @@ Blockly.Flyout.prototype.createDom = function(tagName) {
this.svgBackground_, 'flyoutBackgroundColour', 'fill');
this.workspace_.getThemeManager().subscribe(
this.svgBackground_, 'flyoutOpacity', 'fill-opacity');
this.workspace_.getMarkerManager().setCursor(new Blockly.FlyoutCursor());
return this.svgGroup_;
};
@@ -266,25 +271,25 @@ Blockly.Flyout.prototype.init = function(targetWorkspace) {
this.targetWorkspace = targetWorkspace;
this.workspace_.targetWorkspace = targetWorkspace;
/**
* @type {!Blockly.Scrollbar}
* @package
*/
this.scrollbar = new Blockly.Scrollbar(this.workspace_,
this.horizontalLayout, false, 'blocklyFlyoutScrollbar');
this.workspace_.scrollbar = new Blockly.ScrollbarPair(
this.workspace_, this.horizontalLayout, !this.horizontalLayout,
'blocklyFlyoutScrollbar');
this.hide();
Array.prototype.push.apply(this.eventWrappers_,
Blockly.bindEventWithChecks_(this.svgGroup_, 'wheel', this, this.wheel_));
Array.prototype.push.apply(
this.eventWrappers_,
Blockly.browserEvents.conditionalBind(
this.svgGroup_, 'wheel', this, this.wheel_));
if (!this.autoClose) {
this.filterWrapper_ = this.filterForCapacity_.bind(this);
this.targetWorkspace.addChangeListener(this.filterWrapper_);
}
// Dragging the flyout up and down.
Array.prototype.push.apply(this.eventWrappers_,
Blockly.bindEventWithChecks_(
Array.prototype.push.apply(
this.eventWrappers_,
Blockly.browserEvents.conditionalBind(
this.svgBackground_, 'mousedown', this, this.onMouseDown_));
// A flyout connected to a workspace doesn't have its own current gesture.
@@ -304,15 +309,11 @@ Blockly.Flyout.prototype.init = function(targetWorkspace) {
*/
Blockly.Flyout.prototype.dispose = function() {
this.hide();
Blockly.unbindEvent_(this.eventWrappers_);
Blockly.browserEvents.unbind(this.eventWrappers_);
if (this.filterWrapper_) {
this.targetWorkspace.removeChangeListener(this.filterWrapper_);
this.filterWrapper_ = null;
}
if (this.scrollbar) {
this.scrollbar.dispose();
this.scrollbar = null;
}
if (this.workspace_) {
this.workspace_.getThemeManager().unsubscribe(this.svgBackground_);
this.workspace_.targetWorkspace = null;
@@ -343,6 +344,15 @@ Blockly.Flyout.prototype.getHeight = function() {
return this.height_;
};
/**
* Get the scale (zoom level) of the flyout. By default,
* this matches the target workspace scale, but this can be overridden.
* @return {number} Flyout workspace scale.
*/
Blockly.Flyout.prototype.getFlyoutScale = function() {
return this.targetWorkspace.scale;
};
/**
* Get the workspace inside the flyout.
* @return {!Blockly.WorkspaceSvg} The workspace inside the flyout.
@@ -401,7 +411,7 @@ Blockly.Flyout.prototype.updateDisplay_ = function() {
this.svgGroup_.style.display = show ? 'block' : 'none';
// Update the scrollbar's visibility too since it should mimic the
// flyout's visibility.
this.scrollbar.setContainerVisible(show);
this.workspace_.scrollbar.setContainerVisible(show);
};
/**
@@ -415,6 +425,8 @@ Blockly.Flyout.prototype.updateDisplay_ = function() {
Blockly.Flyout.prototype.positionAt_ = function(width, height, x, y) {
this.svgGroup_.setAttribute("width", width);
this.svgGroup_.setAttribute("height", height);
this.workspace_.setCachedParentSvgSize(width, height);
if (this.svgGroup_.tagName == 'svg') {
var transform = 'translate(' + x + 'px,' + y + 'px)';
Blockly.utils.dom.setCssTransform(this.svgGroup_, transform);
@@ -426,14 +438,22 @@ Blockly.Flyout.prototype.positionAt_ = function(width, height, x, y) {
}
// Update the scrollbar (if one exists).
if (this.scrollbar) {
var scrollbar = this.workspace_.scrollbar;
if (scrollbar) {
// Set the scrollbars origin to be the top left of the flyout.
this.scrollbar.setOrigin(x, y);
this.scrollbar.resize();
// Set the position again so that if the metrics were the same (and the
// resize failed) our position is still updated.
this.scrollbar.setPosition(
this.scrollbar.position.x, this.scrollbar.position.y);
scrollbar.setOrigin(x, y);
scrollbar.resize();
// If origin changed and metrics haven't changed enough to trigger
// reposition in resize, we need to call setPosition. See issue #4692.
if (scrollbar.hScroll) {
scrollbar.hScroll.setPosition(
scrollbar.hScroll.position.x, scrollbar.hScroll.position.y);
}
if (scrollbar.vScroll) {
scrollbar.vScroll.setPosition(
scrollbar.vScroll.position.x, scrollbar.vScroll.position.y);
}
}
};
@@ -447,7 +467,7 @@ Blockly.Flyout.prototype.hide = function() {
this.setVisible(false);
// Delete all the event listeners.
for (var i = 0, listen; (listen = this.listeners_[i]); i++) {
Blockly.unbindEvent_(listen);
Blockly.browserEvents.unbind(listen);
}
this.listeners_.length = 0;
if (this.reflowWrapper_) {
@@ -492,8 +512,8 @@ Blockly.Flyout.prototype.show = function(flyoutDef) {
}
};
this.listeners_.push(Blockly.bindEventWithChecks_(this.svgBackground_,
'mouseover', this, deselectAll));
this.listeners_.push(Blockly.browserEvents.conditionalBind(
this.svgBackground_, 'mouseover', this, deselectAll));
if (this.horizontalLayout) {
this.height_ = 0;
@@ -722,18 +742,18 @@ Blockly.Flyout.prototype.clearOldBlocks_ = function() {
* @protected
*/
Blockly.Flyout.prototype.addBlockListeners_ = function(root, block, rect) {
this.listeners_.push(Blockly.bindEventWithChecks_(root, 'mousedown', null,
this.blockMouseDown_(block)));
this.listeners_.push(Blockly.bindEventWithChecks_(rect, 'mousedown', null,
this.blockMouseDown_(block)));
this.listeners_.push(Blockly.bindEvent_(root, 'mouseenter', block,
block.addSelect));
this.listeners_.push(Blockly.bindEvent_(root, 'mouseleave', block,
block.removeSelect));
this.listeners_.push(Blockly.bindEvent_(rect, 'mouseenter', block,
block.addSelect));
this.listeners_.push(Blockly.bindEvent_(rect, 'mouseleave', block,
block.removeSelect));
this.listeners_.push(Blockly.browserEvents.conditionalBind(
root, 'mousedown', null, this.blockMouseDown_(block)));
this.listeners_.push(Blockly.browserEvents.conditionalBind(
rect, 'mousedown', null, this.blockMouseDown_(block)));
this.listeners_.push(
Blockly.browserEvents.bind(root, 'mouseenter', block, block.addSelect));
this.listeners_.push(Blockly.browserEvents.bind(
root, 'mouseleave', block, block.removeSelect));
this.listeners_.push(
Blockly.browserEvents.bind(rect, 'mouseenter', block, block.addSelect));
this.listeners_.push(Blockly.browserEvents.bind(
rect, 'mouseleave', block, block.removeSelect));
};
/**
@@ -806,12 +826,14 @@ Blockly.Flyout.prototype.createBlock = function(originalBlock) {
// Fire a VarCreate event for each (if any) new variable created.
for (var i = 0; i < newVariables.length; i++) {
var thisVariable = newVariables[i];
Blockly.Events.fire(new Blockly.Events.VarCreate(thisVariable));
Blockly.Events.fire(
new (Blockly.Events.get(Blockly.Events.VAR_CREATE))(thisVariable));
}
// Block events come after var events, in case they refer to newly created
// variables.
Blockly.Events.fire(new Blockly.Events.Create(newBlock));
Blockly.Events.fire(
new (Blockly.Events.get(Blockly.Events.BLOCK_CREATE))(newBlock));
}
if (this.autoClose) {
this.hide();
@@ -835,9 +857,8 @@ Blockly.Flyout.prototype.initFlyoutButton_ = function(button, x, y) {
button.show();
// Clicking on a flyout button or label is a lot like clicking on the
// flyout background.
this.listeners_.push(
Blockly.bindEventWithChecks_(
buttonSvg, 'mousedown', this, this.onMouseDown_));
this.listeners_.push(Blockly.browserEvents.conditionalBind(
buttonSvg, 'mousedown', this, this.onMouseDown_));
this.buttons_.push(button);
};
@@ -933,7 +954,8 @@ Blockly.Flyout.prototype.reflow = function() {
* @package
*/
Blockly.Flyout.prototype.isScrollable = function() {
return this.scrollbar ? this.scrollbar.isVisible() : false;
return this.workspace_.scrollbar ?
this.workspace_.scrollbar.isVisible() : false;
};
/**
@@ -995,18 +1017,6 @@ Blockly.Flyout.prototype.placeNewBlock_ = function(oldBlock) {
return block;
};
/**
* Handles the given action.
* This is only triggered when keyboard accessibility mode is enabled.
* @param {!Blockly.ShortcutRegistry.KeyboardShortcut} action The action to be handled.
* @return {boolean} True if the flyout handled the action, false otherwise.
* @package
*/
Blockly.Flyout.prototype.onBlocklyAction = function(action) {
var cursor = this.workspace_.getCursor();
return cursor.onBlocklyAction(action);
};
/**
* Return the deletion rectangle for this flyout in viewport coordinates.
* @return {Blockly.utils.Rect} Rectangle in which to delete.
@@ -1030,15 +1040,6 @@ Blockly.Flyout.prototype.position;
*/
Blockly.Flyout.prototype.isDragTowardWorkspace;
/**
* Return an object with all the metrics required to size scrollbars for the
* flyout.
* @return {Blockly.utils.Metrics} Contains size and position metrics of the
* flyout.
* @protected
*/
Blockly.Flyout.prototype.getMetrics_;
/**
* Sets the translation of the flyout to match the scrollbars.
* @param {!{x:number,y:number}} xyRatio Contains a y property which is a float

View File

@@ -12,12 +12,16 @@
goog.provide('Blockly.FlyoutButton');
goog.require('Blockly.browserEvents');
goog.require('Blockly.Css');
goog.require('Blockly.utils');
goog.require('Blockly.utils.Coordinate');
goog.require('Blockly.utils.dom');
goog.require('Blockly.utils.Svg');
goog.requireType('Blockly.utils.toolbox');
goog.requireType('Blockly.WorkspaceSvg');
/**
* Class for a button in the flyout.
@@ -82,7 +86,7 @@ Blockly.FlyoutButton = function(workspace, targetWorkspace, json, isLabel) {
/**
* Mouse up event data.
* @type {?Blockly.EventData}
* @type {?Blockly.browserEvents.Data}
* @private
*/
this.onMouseUpWrapper_ = null;
@@ -195,7 +199,7 @@ Blockly.FlyoutButton.prototype.createDom = function() {
this.updateTransform_();
this.onMouseUpWrapper_ = Blockly.bindEventWithChecks_(
this.onMouseUpWrapper_ = Blockly.browserEvents.conditionalBind(
this.svgGroup_, 'mouseup', this, this.onMouseUp_);
return this.svgGroup_;
};
@@ -265,7 +269,7 @@ Blockly.FlyoutButton.prototype.getTargetWorkspace = function() {
*/
Blockly.FlyoutButton.prototype.dispose = function() {
if (this.onMouseUpWrapper_) {
Blockly.unbindEvent_(this.onMouseUpWrapper_);
Blockly.browserEvents.unbind(this.onMouseUpWrapper_);
}
if (this.svgGroup_) {
Blockly.utils.dom.removeNode(this.svgGroup_);

View File

@@ -1,76 +0,0 @@
/**
* @license
* Copyright 2017 Google LLC
* SPDX-License-Identifier: Apache-2.0
*/
/**
* @fileoverview Methods for dragging a flyout visually.
* @author fenichel@google.com (Rachel Fenichel)
*/
'use strict';
goog.provide('Blockly.FlyoutDragger');
goog.require('Blockly.utils.object');
goog.require('Blockly.WorkspaceDragger');
goog.requireType('Blockly.IFlyout');
/**
* Class for a flyout dragger. It moves a flyout workspace around when it is
* being dragged by a mouse or touch.
* Note that the workspace itself manages whether or not it has a drag surface
* and how to do translations based on that. This simply passes the right
* commands based on events.
* @param {!Blockly.IFlyout} flyout The flyout to drag.
* @extends {Blockly.WorkspaceDragger}
* @constructor
*/
Blockly.FlyoutDragger = function(flyout) {
Blockly.FlyoutDragger.superClass_.constructor.call(this,
flyout.getWorkspace());
/**
* The scrollbar to update to move the flyout.
* Unlike the main workspace, the flyout has only one scrollbar, in either the
* horizontal or the vertical direction.
* @type {!Blockly.Scrollbar}
* @private
*/
this.scrollbar_ = flyout.scrollbar;
/**
* Whether the flyout scrolls horizontally. If false, the flyout scrolls
* vertically.
* @type {boolean}
* @private
*/
this.horizontalLayout_ = flyout.horizontalLayout;
};
Blockly.utils.object.inherits(Blockly.FlyoutDragger, Blockly.WorkspaceDragger);
/**
* Move the flyout based on the most recent mouse movements.
* @param {!Blockly.utils.Coordinate} currentDragDeltaXY How far the pointer has
* moved from the position at the start of the drag, in pixel coordinates.
* @package
*/
Blockly.FlyoutDragger.prototype.drag = function(currentDragDeltaXY) {
// startScrollXY_ is assigned by the superclass.
var newXY = Blockly.utils.Coordinate.sum(this.startScrollXY_,
currentDragDeltaXY);
// We can't call workspace.scroll because the flyout's workspace doesn't own
// it's own scrollbars. This is because (as of 2.20190722.1) the
// workspace's scrollbar property must be a scrollbar pair, rather than a
// single scrollbar.
// Instead we'll just expect setting the scrollbar to update the scroll of
// the workspace as well.
if (this.horizontalLayout_) {
this.scrollbar_.set(-newXY.x);
} else {
this.scrollbar_.set(-newXY.y);
}
};

View File

@@ -12,7 +12,9 @@
goog.provide('Blockly.HorizontalFlyout');
/** @suppress {extraRequire} */
goog.require('Blockly.Block');
/** @suppress {extraRequire} */
goog.require('Blockly.constants');
goog.require('Blockly.Flyout');
goog.require('Blockly.registry');
@@ -20,9 +22,11 @@ goog.require('Blockly.Scrollbar');
goog.require('Blockly.utils');
goog.require('Blockly.utils.object');
goog.require('Blockly.utils.Rect');
goog.require('Blockly.utils.toolbox');
goog.require('Blockly.WidgetDiv');
goog.requireType('Blockly.utils.Metrics');
goog.requireType('Blockly.Options');
goog.requireType('Blockly.utils.Coordinate');
/**
@@ -38,64 +42,6 @@ Blockly.HorizontalFlyout = function(workspaceOptions) {
};
Blockly.utils.object.inherits(Blockly.HorizontalFlyout, Blockly.Flyout);
/**
* Return an object with all the metrics required to size scrollbars for the
* flyout. The following properties are computed:
* .viewHeight: Height of the visible rectangle,
* .viewWidth: Width of the visible rectangle,
* .contentHeight: Height of the contents,
* .contentWidth: Width of the contents,
* .viewTop: Offset of top edge of visible rectangle from parent,
* .contentTop: Offset of the top-most content from the y=0 coordinate,
* .absoluteTop: Top-edge of view.
* .viewLeft: Offset of the left edge of visible rectangle from parent,
* .contentLeft: Offset of the left-most content from the x=0 coordinate,
* .absoluteLeft: Left-edge of view.
* @return {Blockly.utils.Metrics} Contains size and position metrics of the
* flyout.
* @protected
*/
Blockly.HorizontalFlyout.prototype.getMetrics_ = function() {
if (!this.isVisible()) {
// Flyout is hidden.
return null;
}
try {
var optionBox = this.workspace_.getCanvas().getBBox();
} catch (e) {
// Firefox has trouble with hidden elements (Bug 528969).
var optionBox = {height: 0, y: 0, width: 0, x: 0};
}
var absoluteTop = this.SCROLLBAR_PADDING;
var absoluteLeft = this.SCROLLBAR_PADDING;
if (this.toolboxPosition_ == Blockly.TOOLBOX_AT_BOTTOM) {
absoluteTop = 0;
}
var viewHeight = this.height_;
if (this.toolboxPosition_ == Blockly.TOOLBOX_AT_TOP) {
viewHeight -= this.SCROLLBAR_PADDING;
}
var viewWidth = this.width_ - 2 * this.SCROLLBAR_PADDING;
var metrics = {
contentHeight: (optionBox.height + 2 * this.MARGIN) * this.workspace_.scale,
contentWidth: (optionBox.width + 2 * this.MARGIN) * this.workspace_.scale,
contentTop: 0,
contentLeft: 0,
viewHeight: viewHeight,
viewWidth: viewWidth,
viewTop: -this.workspace_.scrollY,
viewLeft: -this.workspace_.scrollX,
absoluteTop: absoluteTop,
absoluteLeft: absoluteLeft
};
return metrics;
};
/**
* Sets the translation of the flyout to match the scrollbars.
* @param {!{x:number,y:number}} xyRatio Contains a y property which is a float
@@ -104,18 +50,23 @@ Blockly.HorizontalFlyout.prototype.getMetrics_ = function() {
* @protected
*/
Blockly.HorizontalFlyout.prototype.setMetrics_ = function(xyRatio) {
var metrics = this.getMetrics_();
// This is a fix to an apparent race condition.
if (!metrics) {
if (!this.isVisible()) {
return;
}
var metricsManager = this.workspace_.getMetricsManager();
var scrollMetrics = metricsManager.getScrollMetrics();
var viewMetrics = metricsManager.getViewMetrics();
var absoluteMetrics = metricsManager.getAbsoluteMetrics();
if (typeof xyRatio.x == 'number') {
this.workspace_.scrollX = -metrics.contentWidth * xyRatio.x;
this.workspace_.scrollX =
-(scrollMetrics.left +
(scrollMetrics.width - viewMetrics.width) * xyRatio.x);
}
this.workspace_.translate(this.workspace_.scrollX + metrics.absoluteLeft,
this.workspace_.scrollY + metrics.absoluteTop);
this.workspace_.translate(this.workspace_.scrollX + absoluteMetrics.left,
this.workspace_.scrollY + absoluteMetrics.top);
};
/**
@@ -132,42 +83,44 @@ Blockly.HorizontalFlyout.prototype.getX = function() {
* @return {number} Y coordinate.
*/
Blockly.HorizontalFlyout.prototype.getY = function() {
var targetWorkspaceMetrics = this.targetWorkspace.getMetrics();
if (!targetWorkspaceMetrics) {
// Hidden components will return null.
if (!this.isVisible()) {
return 0;
}
var metricsManager = this.targetWorkspace.getMetricsManager();
var absoluteMetrics = metricsManager.getAbsoluteMetrics();
var viewMetrics = metricsManager.getViewMetrics();
var toolboxMetrics = metricsManager.getToolboxMetrics();
var y = 0;
var atTop = this.toolboxPosition_ == Blockly.utils.toolbox.Position.TOP;
// If this flyout is not the trashcan flyout (e.g. toolbox or mutator).
if (this.targetWorkspace.toolboxPosition == this.toolboxPosition_) {
// If there is a category toolbox.
if (targetWorkspaceMetrics.toolboxHeight) {
if (this.toolboxPosition_ == Blockly.TOOLBOX_AT_TOP) {
y = targetWorkspaceMetrics.toolboxHeight;
if (this.targetWorkspace.getToolbox()) {
if (atTop) {
y = toolboxMetrics.height;
} else {
y = targetWorkspaceMetrics.viewHeight - this.height_;
y = viewMetrics.height - this.height_;
}
// Simple (flyout-only) toolbox.
} else {
if (this.toolboxPosition_ == Blockly.TOOLBOX_AT_TOP) {
if (atTop) {
y = 0;
} else {
// The simple flyout does not cover the workspace.
y = targetWorkspaceMetrics.viewHeight;
y = viewMetrics.height;
}
}
// Trashcan flyout is opposite the main flyout.
} else {
if (this.toolboxPosition_ == Blockly.TOOLBOX_AT_TOP) {
if (atTop) {
y = 0;
} else {
// Because the anchor point of the flyout is on the top, but we want
// to align the bottom edge of the flyout with the bottom edge of the
// blocklyDiv, we calculate the full height of the div minus the height
// of the flyout.
y = targetWorkspaceMetrics.viewHeight +
targetWorkspaceMetrics.absoluteTop - this.height_;
y = viewMetrics.height + absoluteMetrics.top - this.height_;
}
}
@@ -178,24 +131,22 @@ Blockly.HorizontalFlyout.prototype.getY = function() {
* Move the flyout to the edge of the workspace.
*/
Blockly.HorizontalFlyout.prototype.position = function() {
if (!this.isVisible()) {
if (!this.isVisible() || !this.targetWorkspace.isVisible()) {
return;
}
var targetWorkspaceMetrics = this.targetWorkspace.getMetrics();
if (!targetWorkspaceMetrics) {
// Hidden components will return null.
return;
}
// Record the width for Blockly.Flyout.getMetrics_.
this.width_ = targetWorkspaceMetrics.viewWidth;
var metricsManager = this.targetWorkspace.getMetricsManager();
var targetWorkspaceViewMetrics = metricsManager.getViewMetrics();
var edgeWidth = targetWorkspaceMetrics.viewWidth - 2 * this.CORNER_RADIUS;
// Record the width for workspace metrics.
this.width_ = targetWorkspaceViewMetrics.width;
var edgeWidth = targetWorkspaceViewMetrics.width - 2 * this.CORNER_RADIUS;
var edgeHeight = this.height_ - this.CORNER_RADIUS;
this.setBackgroundPath_(edgeWidth, edgeHeight);
var x = this.getX();
var y = this.getY();
this.positionAt_(this.width_, this.height_, x, y);
};
@@ -207,9 +158,9 @@ Blockly.HorizontalFlyout.prototype.position = function() {
* rounded corners.
* @private
*/
Blockly.HorizontalFlyout.prototype.setBackgroundPath_ = function(width,
height) {
var atTop = this.toolboxPosition_ == Blockly.TOOLBOX_AT_TOP;
Blockly.HorizontalFlyout.prototype.setBackgroundPath_ = function(
width, height) {
var atTop = this.toolboxPosition_ == Blockly.utils.toolbox.Position.TOP;
// Start at top left.
var path = ['M 0,' + (atTop ? 0 : this.CORNER_RADIUS)];
@@ -247,7 +198,7 @@ Blockly.HorizontalFlyout.prototype.setBackgroundPath_ = function(width,
* Scroll the flyout to the top.
*/
Blockly.HorizontalFlyout.prototype.scrollToStart = function() {
this.scrollbar.set(this.RTL ? Infinity : 0);
this.workspace_.scrollbar.setX(this.RTL ? Infinity : 0);
};
/**
@@ -260,12 +211,12 @@ Blockly.HorizontalFlyout.prototype.wheel_ = function(e) {
var delta = scrollDelta.x || scrollDelta.y;
if (delta) {
var metrics = this.getMetrics_();
var pos = metrics.viewLeft + delta;
var limit = metrics.contentWidth - metrics.viewWidth;
pos = Math.min(pos, limit);
pos = Math.max(pos, 0);
this.scrollbar.set(pos);
var metricsManager = this.workspace_.getMetricsManager();
var scrollMetrics = metricsManager.getScrollMetrics();
var viewMetrics = metricsManager.getViewMetrics();
var pos = (viewMetrics.left - scrollMetrics.left) + delta;
this.workspace_.scrollbar.setX(pos);
// When the flyout moves from a wheel event, hide WidgetDiv and DropDownDiv.
Blockly.WidgetDiv.hide();
Blockly.DropDownDiv.hideWithoutAnimation();
@@ -367,7 +318,7 @@ Blockly.HorizontalFlyout.prototype.getClientRect = function() {
var BIG_NUM = 1000000000;
var top = flyoutRect.top;
if (this.toolboxPosition_ == Blockly.TOOLBOX_AT_TOP) {
if (this.toolboxPosition_ == Blockly.utils.toolbox.Position.TOP) {
var height = flyoutRect.height;
return new Blockly.utils.Rect(-BIG_NUM, top + height, -BIG_NUM, BIG_NUM);
} else { // Bottom.
@@ -381,7 +332,7 @@ Blockly.HorizontalFlyout.prototype.getClientRect = function() {
* @protected
*/
Blockly.HorizontalFlyout.prototype.reflowInternal_ = function() {
this.workspace_.scale = this.targetWorkspace.scale;
this.workspace_.scale = this.getFlyoutScale();
var flyoutHeight = 0;
var blocks = this.workspace_.getTopBlocks(false);
for (var i = 0, block; (block = blocks[i]); i++) {
@@ -399,7 +350,7 @@ Blockly.HorizontalFlyout.prototype.reflowInternal_ = function() {
}
if (this.targetWorkspace.toolboxPosition == this.toolboxPosition_ &&
this.toolboxPosition_ == Blockly.TOOLBOX_AT_TOP &&
this.toolboxPosition_ == Blockly.utils.toolbox.Position.TOP &&
!this.targetWorkspace.getToolbox()) {
// This flyout is a simple toolbox. Reposition the workspace so that (0,0)
// is in the correct position relative to the new absolute edge (ie
@@ -408,7 +359,7 @@ Blockly.HorizontalFlyout.prototype.reflowInternal_ = function() {
this.targetWorkspace.scrollX, this.targetWorkspace.scrollY + flyoutHeight);
}
// Record the height for .getMetrics_ and .position.
// Record the height for workspace metrics and .position.
this.height_ = flyoutHeight;
this.position();
}

View File

@@ -12,7 +12,9 @@
goog.provide('Blockly.VerticalFlyout');
/** @suppress {extraRequire} */
goog.require('Blockly.Block');
/** @suppress {extraRequire} */
goog.require('Blockly.constants');
goog.require('Blockly.Flyout');
goog.require('Blockly.registry');
@@ -20,10 +22,11 @@ goog.require('Blockly.Scrollbar');
goog.require('Blockly.utils');
goog.require('Blockly.utils.object');
goog.require('Blockly.utils.Rect');
goog.require('Blockly.utils.userAgent');
goog.require('Blockly.utils.toolbox');
goog.require('Blockly.WidgetDiv');
goog.requireType('Blockly.utils.Metrics');
goog.requireType('Blockly.Options');
goog.requireType('Blockly.utils.Coordinate');
/**
@@ -44,63 +47,6 @@ Blockly.utils.object.inherits(Blockly.VerticalFlyout, Blockly.Flyout);
*/
Blockly.VerticalFlyout.registryName = 'verticalFlyout';
/**
* Return an object with all the metrics required to size scrollbars for the
* flyout. The following properties are computed:
* .viewHeight: Height of the visible rectangle,
* .viewWidth: Width of the visible rectangle,
* .contentHeight: Height of the contents,
* .contentWidth: Width of the contents,
* .viewTop: Offset of top edge of visible rectangle from parent,
* .contentTop: Offset of the top-most content from the y=0 coordinate,
* .absoluteTop: Top-edge of view.
* .viewLeft: Offset of the left edge of visible rectangle from parent,
* .contentLeft: Offset of the left-most content from the x=0 coordinate,
* .absoluteLeft: Left-edge of view.
* @return {Blockly.utils.Metrics} Contains size and position metrics of the
* flyout.
* @protected
*/
Blockly.VerticalFlyout.prototype.getMetrics_ = function() {
if (!this.isVisible()) {
// Flyout is hidden.
return null;
}
try {
var optionBox = this.workspace_.getCanvas().getBBox();
} catch (e) {
// Firefox has trouble with hidden elements (Bug 528969).
var optionBox = {height: 0, y: 0, width: 0, x: 0};
}
// Padding for the end of the scrollbar.
var absoluteTop = this.SCROLLBAR_PADDING;
var absoluteLeft = 0;
var viewHeight = this.height_ - 2 * this.SCROLLBAR_PADDING;
var viewWidth = this.width_;
if (!this.RTL) {
viewWidth -= this.SCROLLBAR_PADDING;
}
var metrics = {
contentHeight: optionBox.height * this.workspace_.scale + 2 * this.MARGIN,
contentWidth: optionBox.width * this.workspace_.scale + 2 * this.MARGIN,
contentTop: optionBox.y,
contentLeft: optionBox.x,
viewHeight: viewHeight,
viewWidth: viewWidth,
viewTop: -this.workspace_.scrollY + optionBox.y,
viewLeft: -this.workspace_.scrollX,
absoluteTop: absoluteTop,
absoluteLeft: absoluteLeft
};
return metrics;
};
/**
* Sets the translation of the flyout to match the scrollbars.
* @param {!{x:number,y:number}} xyRatio Contains a y property which is a float
@@ -109,16 +55,21 @@ Blockly.VerticalFlyout.prototype.getMetrics_ = function() {
* @protected
*/
Blockly.VerticalFlyout.prototype.setMetrics_ = function(xyRatio) {
var metrics = this.getMetrics_();
// This is a fix to an apparent race condition.
if (!metrics) {
if (!this.isVisible()) {
return;
}
var metricsManager = this.workspace_.getMetricsManager();
var scrollMetrics = metricsManager.getScrollMetrics();
var viewMetrics = metricsManager.getViewMetrics();
var absoluteMetrics = metricsManager.getAbsoluteMetrics();
if (typeof xyRatio.y == 'number') {
this.workspace_.scrollY = -metrics.contentHeight * xyRatio.y;
this.workspace_.scrollY =
-(scrollMetrics.top +
(scrollMetrics.height - viewMetrics.height) * xyRatio.y);
}
this.workspace_.translate(this.workspace_.scrollX + metrics.absoluteLeft,
this.workspace_.scrollY + metrics.absoluteTop);
this.workspace_.translate(this.workspace_.scrollX + absoluteMetrics.left,
this.workspace_.scrollY + absoluteMetrics.top);
};
/**
@@ -126,43 +77,43 @@ Blockly.VerticalFlyout.prototype.setMetrics_ = function(xyRatio) {
* @return {number} X coordinate.
*/
Blockly.VerticalFlyout.prototype.getX = function() {
var targetWorkspaceMetrics = this.targetWorkspace.getMetrics();
if (!targetWorkspaceMetrics) {
// Hidden components will return null.
if (!this.isVisible()) {
return 0;
}
var metricsManager = this.targetWorkspace.getMetricsManager();
var absoluteMetrics = metricsManager.getAbsoluteMetrics();
var viewMetrics = metricsManager.getViewMetrics();
var toolboxMetrics = metricsManager.getToolboxMetrics();
var x = 0;
// If this flyout is not the trashcan flyout (e.g. toolbox or mutator).
if (this.targetWorkspace.toolboxPosition == this.toolboxPosition_) {
// If there is a category toolbox.
if (targetWorkspaceMetrics.toolboxWidth) {
if (this.toolboxPosition_ == Blockly.TOOLBOX_AT_LEFT) {
x = targetWorkspaceMetrics.toolboxWidth;
if (this.targetWorkspace.getToolbox()) {
if (this.toolboxPosition_ == Blockly.utils.toolbox.Position.LEFT) {
x = toolboxMetrics.width;
} else {
x = targetWorkspaceMetrics.viewWidth - this.width_;
x = viewMetrics.width - this.width_;
}
// Simple (flyout-only) toolbox.
} else {
if (this.toolboxPosition_ == Blockly.TOOLBOX_AT_LEFT) {
if (this.toolboxPosition_ == Blockly.utils.toolbox.Position.LEFT) {
x = 0;
} else {
// The simple flyout does not cover the workspace.
x = targetWorkspaceMetrics.viewWidth;
x = viewMetrics.width;
}
}
// Trashcan flyout is opposite the main flyout.
} else {
if (this.toolboxPosition_ == Blockly.TOOLBOX_AT_LEFT) {
if (this.toolboxPosition_ == Blockly.utils.toolbox.Position.LEFT) {
x = 0;
} else {
// Because the anchor point of the flyout is on the left, but we want
// to align the right edge of the flyout with the right edge of the
// blocklyDiv, we calculate the full width of the div minus the width
// of the flyout.
x = targetWorkspaceMetrics.viewWidth +
targetWorkspaceMetrics.absoluteLeft - this.width_;
x = viewMetrics.width + absoluteMetrics.left - this.width_;
}
}
@@ -182,24 +133,22 @@ Blockly.VerticalFlyout.prototype.getY = function() {
* Move the flyout to the edge of the workspace.
*/
Blockly.VerticalFlyout.prototype.position = function() {
if (!this.isVisible()) {
if (!this.isVisible() || !this.targetWorkspace.isVisible()) {
return;
}
var targetWorkspaceMetrics = this.targetWorkspace.getMetrics();
if (!targetWorkspaceMetrics) {
// Hidden components will return null.
return;
}
// Record the height for Blockly.Flyout.getMetrics_
this.height_ = targetWorkspaceMetrics.viewHeight;
var metricsManager = this.targetWorkspace.getMetricsManager();
var targetWorkspaceViewMetrics = metricsManager.getViewMetrics();
// Record the height for workspace metrics.
this.height_ = targetWorkspaceViewMetrics.height;
var edgeWidth = this.width_ - this.CORNER_RADIUS;
var edgeHeight = targetWorkspaceMetrics.viewHeight - 2 * this.CORNER_RADIUS;
var edgeHeight = targetWorkspaceViewMetrics.height - 2 * this.CORNER_RADIUS;
this.setBackgroundPath_(edgeWidth, edgeHeight);
var x = this.getX();
var y = this.getY();
this.positionAt_(this.width_, this.height_, x, y);
};
@@ -212,7 +161,7 @@ Blockly.VerticalFlyout.prototype.position = function() {
* @private
*/
Blockly.VerticalFlyout.prototype.setBackgroundPath_ = function(width, height) {
var atRight = this.toolboxPosition_ == Blockly.TOOLBOX_AT_RIGHT;
var atRight = this.toolboxPosition_ == Blockly.utils.toolbox.Position.RIGHT;
var totalWidth = width + this.CORNER_RADIUS;
// Decide whether to start on the left or right.
@@ -241,7 +190,7 @@ Blockly.VerticalFlyout.prototype.setBackgroundPath_ = function(width, height) {
* Scroll the flyout to the top.
*/
Blockly.VerticalFlyout.prototype.scrollToStart = function() {
this.scrollbar.set(0);
this.workspace_.scrollbar.setY(0);
};
/**
@@ -253,12 +202,12 @@ Blockly.VerticalFlyout.prototype.wheel_ = function(e) {
var scrollDelta = Blockly.utils.getScrollDeltaPixels(e);
if (scrollDelta.y) {
var metrics = this.getMetrics_();
var pos = (metrics.viewTop - metrics.contentTop) + scrollDelta.y;
var limit = metrics.contentHeight - metrics.viewHeight;
pos = Math.min(pos, limit);
pos = Math.max(pos, 0);
this.scrollbar.set(pos);
var metricsManager = this.workspace_.getMetricsManager();
var scrollMetrics = metricsManager.getScrollMetrics();
var viewMetrics = metricsManager.getViewMetrics();
var pos = (viewMetrics.top - scrollMetrics.top) + scrollDelta.y;
this.workspace_.scrollbar.setY(pos);
// When the flyout moves from a wheel event, hide WidgetDiv and DropDownDiv.
Blockly.WidgetDiv.hide();
Blockly.DropDownDiv.hideWithoutAnimation();
@@ -352,7 +301,7 @@ Blockly.VerticalFlyout.prototype.getClientRect = function() {
var BIG_NUM = 1000000000;
var left = flyoutRect.left;
if (this.toolboxPosition_ == Blockly.TOOLBOX_AT_LEFT) {
if (this.toolboxPosition_ == Blockly.utils.toolbox.Position.LEFT) {
var width = flyoutRect.width;
return new Blockly.utils.Rect(-BIG_NUM, BIG_NUM, -BIG_NUM, left + width);
} else { // Right
@@ -366,7 +315,7 @@ Blockly.VerticalFlyout.prototype.getClientRect = function() {
* @protected
*/
Blockly.VerticalFlyout.prototype.reflowInternal_ = function() {
this.workspace_.scale = this.targetWorkspace.scale;
this.workspace_.scale = this.getFlyoutScale();
var flyoutWidth = 0;
var blocks = this.workspace_.getTopBlocks(false);
for (var i = 0, block; (block = blocks[i]); i++) {
@@ -409,7 +358,7 @@ Blockly.VerticalFlyout.prototype.reflowInternal_ = function() {
}
if (this.targetWorkspace.toolboxPosition == this.toolboxPosition_ &&
this.toolboxPosition_ == Blockly.TOOLBOX_AT_LEFT &&
this.toolboxPosition_ == Blockly.utils.toolbox.Position.LEFT &&
!this.targetWorkspace.getToolbox()) {
// This flyout is a simple toolbox. Reposition the workspace so that (0,0)
// is in the correct position relative to the new absolute edge (ie
@@ -418,7 +367,7 @@ Blockly.VerticalFlyout.prototype.reflowInternal_ = function() {
this.targetWorkspace.scrollX + flyoutWidth, this.targetWorkspace.scrollY);
}
// Record the width for .getMetrics_ and .position.
// Record the width for workspace metrics and .position.
this.width_ = flyoutWidth;
this.position();
}

View File

@@ -13,8 +13,12 @@
goog.provide('Blockly.Generator');
goog.require('Blockly.constants');
goog.require('Blockly.Block');
/** @suppress {extraRequire} */
goog.require('Blockly.constants');
goog.requireType('Blockly.Names');
goog.requireType('Blockly.Workspace');
/**

View File

@@ -13,23 +13,26 @@
goog.provide('Blockly.Gesture');
goog.require('Blockly.ASTNode');
goog.require('Blockly.blockAnimations');
goog.require('Blockly.BlockDragger');
goog.require('Blockly.browserEvents');
goog.require('Blockly.BubbleDragger');
/** @suppress {extraRequire} */
goog.require('Blockly.constants');
goog.require('Blockly.Events');
/** @suppress {extraRequire} */
goog.require('Blockly.Events.Click');
goog.require('Blockly.FlyoutDragger');
goog.require('Blockly.navigation');
goog.require('Blockly.Tooltip');
goog.require('Blockly.Touch');
goog.require('Blockly.utils');
goog.require('Blockly.utils.Coordinate');
goog.require('Blockly.WorkspaceDragger');
goog.requireType('Blockly.BlockSvg');
goog.requireType('Blockly.Field');
goog.requireType('Blockly.IBubble');
goog.requireType('Blockly.IFlyout');
goog.requireType('Blockly.WorkspaceSvg');
/**
@@ -155,7 +158,7 @@ Blockly.Gesture = function(e, creatorWorkspace) {
/**
* A handle to use to unbind a mouse move listener at the end of a drag.
* Opaque data returned from Blockly.bindEventWithChecks_.
* @type {?Blockly.EventData}
* @type {?Blockly.browserEvents.Data}
* @protected
*/
this.onMoveWrapper_ = null;
@@ -163,7 +166,7 @@ Blockly.Gesture = function(e, creatorWorkspace) {
/**
* A handle to use to unbind a mouse up listener at the end of a drag.
* Opaque data returned from Blockly.bindEventWithChecks_.
* @type {?Blockly.EventData}
* @type {?Blockly.browserEvents.Data}
* @protected
*/
this.onUpWrapper_ = null;
@@ -238,10 +241,10 @@ Blockly.Gesture.prototype.dispose = function() {
this.creatorWorkspace_.clearGesture();
if (this.onMoveWrapper_) {
Blockly.unbindEvent_(this.onMoveWrapper_);
Blockly.browserEvents.unbind(this.onMoveWrapper_);
}
if (this.onUpWrapper_) {
Blockly.unbindEvent_(this.onUpWrapper_);
Blockly.browserEvents.unbind(this.onUpWrapper_);
}
if (this.blockDragger_) {
@@ -384,7 +387,7 @@ Blockly.Gesture.prototype.updateIsDraggingBlock_ = function() {
* This function should be called on a mouse/touch move event the first time the
* drag radius is exceeded. It should be called no more than once per gesture.
* If a workspace is being dragged this function creates the necessary
* WorkspaceDragger or FlyoutDragger and starts the drag.
* WorkspaceDragger and starts the drag.
* @private
*/
Blockly.Gesture.prototype.updateIsDraggingWorkspace_ = function() {
@@ -396,12 +399,8 @@ Blockly.Gesture.prototype.updateIsDraggingWorkspace_ = function() {
return;
}
if (this.flyout_) {
this.workspaceDragger_ = new Blockly.FlyoutDragger(this.flyout_);
} else {
this.workspaceDragger_ = new Blockly.WorkspaceDragger(
/** @type {!Blockly.WorkspaceSvg} */ (this.startWorkspace_));
}
this.workspaceDragger_ = new Blockly.WorkspaceDragger(
/** @type {!Blockly.WorkspaceSvg} */ (this.startWorkspace_));
this.isDraggingWorkspace_ = true;
this.workspaceDragger_.startDrag();
@@ -488,13 +487,7 @@ Blockly.Gesture.prototype.doStart = function(e) {
Blockly.Tooltip.block();
if (this.targetBlock_) {
if (!this.targetBlock_.isInFlyout && e.shiftKey &&
this.targetBlock_.workspace.keyboardAccessibilityMode) {
this.creatorWorkspace_.getCursor().setCurNode(
Blockly.ASTNode.createTopNode(this.targetBlock_));
} else {
this.targetBlock_.select();
}
this.targetBlock_.select();
}
if (Blockly.utils.isRightButton(e)) {
@@ -520,9 +513,9 @@ Blockly.Gesture.prototype.doStart = function(e) {
* @package
*/
Blockly.Gesture.prototype.bindMouseEvents = function(e) {
this.onMoveWrapper_ = Blockly.bindEventWithChecks_(
this.onMoveWrapper_ = Blockly.browserEvents.conditionalBind(
document, 'mousemove', null, this.handleMove.bind(this));
this.onUpWrapper_ = Blockly.bindEventWithChecks_(
this.onUpWrapper_ = Blockly.browserEvents.conditionalBind(
document, 'mouseup', null, this.handleUp.bind(this));
e.preventDefault();
@@ -654,9 +647,6 @@ Blockly.Gesture.prototype.handleWsStart = function(e, ws) {
this.setStartWorkspace_(ws);
this.mostRecentEvent_ = e;
this.doStart(e);
if (this.startWorkspace_.keyboardAccessibilityMode) {
Blockly.navigation.setState(Blockly.navigation.STATE_WS);
}
};
/**
@@ -665,8 +655,8 @@ Blockly.Gesture.prototype.handleWsStart = function(e, ws) {
* @private
*/
Blockly.Gesture.prototype.fireWorkspaceClick_ = function(ws) {
var clickEvent = new Blockly.Events.Click(null, ws.id, 'workspace');
Blockly.Events.fire(clickEvent);
Blockly.Events.fire(new (Blockly.Events.get(Blockly.Events.CLICK))(
null, ws.id, 'workspace'));
};
/**
@@ -756,7 +746,7 @@ Blockly.Gesture.prototype.doBlockClick_ = function() {
}
} else {
// Clicks events are on the start block, even if it was a shadow.
var event = new Blockly.Events.Click(
var event = new (Blockly.Events.get(Blockly.Events.CLICK))(
this.startBlock_, this.startWorkspace_.id, 'block');
Blockly.Events.fire(event);
}
@@ -767,17 +757,12 @@ Blockly.Gesture.prototype.doBlockClick_ = function() {
/**
* Execute a workspace click. When in accessibility mode shift clicking will
* move the cursor.
* @param {!Event} e A mouse up or touch end event.
* @param {!Event} _e A mouse up or touch end event.
* @private
*/
Blockly.Gesture.prototype.doWorkspaceClick_ = function(e) {
Blockly.Gesture.prototype.doWorkspaceClick_ = function(_e) {
var ws = this.creatorWorkspace_;
if (e.shiftKey && ws.keyboardAccessibilityMode) {
var screenCoord = new Blockly.utils.Coordinate(e.clientX, e.clientY);
var wsCoord = Blockly.utils.screenToWsCoordinates(ws, screenCoord);
var wsNode = Blockly.ASTNode.createWorkspaceNode(ws, wsCoord);
ws.getCursor().setCurNode(wsNode);
} else if (Blockly.selected) {
if (Blockly.selected) {
Blockly.selected.unselect();
}
this.fireWorkspaceClick_(this.startWorkspace_ || ws);

View File

@@ -12,12 +12,16 @@
goog.provide('Blockly.Icon');
goog.require('Blockly.browserEvents');
goog.require('Blockly.utils');
goog.require('Blockly.utils.Coordinate');
goog.require('Blockly.utils.dom');
goog.require('Blockly.utils.Size');
goog.require('Blockly.utils.Svg');
goog.requireType('Blockly.BlockSvg');
goog.requireType('Blockly.Bubble');
/**
* Class for an icon.
@@ -87,7 +91,7 @@ Blockly.Icon.prototype.createIcon = function() {
this.drawIcon_(this.iconGroup_);
this.block_.getSvgRoot().appendChild(this.iconGroup_);
Blockly.bindEventWithChecks_(
Blockly.browserEvents.conditionalBind(
this.iconGroup_, 'mouseup', this, this.iconClick_);
this.updateEditable();
};

View File

@@ -13,6 +13,7 @@
goog.provide('Blockly.inject');
goog.require('Blockly.BlockDragSurfaceSvg');
goog.require('Blockly.browserEvents');
goog.require('Blockly.Css');
goog.require('Blockly.DropDownDiv');
goog.require('Blockly.Events');
@@ -22,13 +23,14 @@ goog.require('Blockly.Options');
goog.require('Blockly.ScrollbarPair');
goog.require('Blockly.Tooltip');
goog.require('Blockly.utils');
goog.require('Blockly.utils.aria');
goog.require('Blockly.utils.dom');
goog.require('Blockly.utils.Svg');
goog.require('Blockly.utils.userAgent');
goog.require('Blockly.WorkspaceDragSurfaceSvg');
goog.require('Blockly.WorkspaceSvg');
goog.requireType('Blockly.utils.Metrics');
goog.requireType('Blockly.Workspace');
/**
@@ -178,147 +180,7 @@ Blockly.createMainWorkspace_ = function(svg, options, blockDragSurface,
// A null translation will also apply the correct initial scale.
mainWorkspace.translate(0, 0);
if (!wsOptions.readOnly && !mainWorkspace.isMovable()) {
// Helper function for the workspaceChanged callback.
// TODO (#2300): Move metrics math back to the WorkspaceSvg.
var getWorkspaceMetrics = function() {
var workspaceMetrics = Object.create(null);
var defaultMetrics = mainWorkspace.getMetrics();
var scale = mainWorkspace.scale;
workspaceMetrics.RTL = mainWorkspace.RTL;
// Get the view metrics in workspace units.
workspaceMetrics.viewLeft = defaultMetrics.viewLeft / scale;
workspaceMetrics.viewTop = defaultMetrics.viewTop / scale;
workspaceMetrics.viewRight =
(defaultMetrics.viewLeft + defaultMetrics.viewWidth) / scale;
workspaceMetrics.viewBottom =
(defaultMetrics.viewTop + defaultMetrics.viewHeight) / scale;
// Get the exact content metrics (in workspace units), even if the
// content is bounded.
if (mainWorkspace.isContentBounded()) {
// Already in workspace units, no need to divide by scale.
var blocksBoundingBox = mainWorkspace.getBlocksBoundingBox();
workspaceMetrics.contentLeft = blocksBoundingBox.left;
workspaceMetrics.contentTop = blocksBoundingBox.top;
workspaceMetrics.contentRight = blocksBoundingBox.right;
workspaceMetrics.contentBottom = blocksBoundingBox.bottom;
} else {
workspaceMetrics.contentLeft = defaultMetrics.contentLeft / scale;
workspaceMetrics.contentTop = defaultMetrics.contentTop / scale;
workspaceMetrics.contentRight =
(defaultMetrics.contentLeft + defaultMetrics.contentWidth) / scale;
workspaceMetrics.contentBottom =
(defaultMetrics.contentTop + defaultMetrics.contentHeight) / scale;
}
return workspaceMetrics;
};
var getObjectMetrics = function(object) {
var objectMetrics = object.getBoundingRectangle();
objectMetrics.height = objectMetrics.bottom - objectMetrics.top;
objectMetrics.width = objectMetrics.right - objectMetrics.left;
return objectMetrics;
};
var bumpObjects = function(e) {
// We always check isMovable_ again because the original
// "not movable" state of isMovable_ could have been changed.
if (!mainWorkspace.isDragging() && !mainWorkspace.isMovable() &&
(Blockly.Events.BUMP_EVENTS.indexOf(e.type) != -1)) {
var metrics = getWorkspaceMetrics();
if (metrics.contentTop < metrics.viewTop ||
metrics.contentBottom > metrics.viewBottom ||
metrics.contentLeft < metrics.viewLeft ||
metrics.contentRight > metrics.viewRight) {
// Handle undo.
var oldGroup = null;
if (e) {
oldGroup = Blockly.Events.getGroup();
Blockly.Events.setGroup(e.group);
}
switch (e.type) {
case Blockly.Events.BLOCK_CREATE:
case Blockly.Events.BLOCK_MOVE:
var object = mainWorkspace.getBlockById(e.blockId);
if (object) {
object = object.getRootBlock();
}
break;
case Blockly.Events.COMMENT_CREATE:
case Blockly.Events.COMMENT_MOVE:
var object = mainWorkspace.getCommentById(e.commentId);
break;
}
if (object) {
var objectMetrics = getObjectMetrics(object);
// The idea is to find the region of valid coordinates for the top
// left corner of the object, and then clamp the object's
// top left corner within that region.
// The top of the object should always be at or below the top of
// the workspace.
var topClamp = metrics.viewTop;
// The top of the object should ideally be positioned so that
// the bottom of the object is not below the bottom of the
// workspace.
var bottomClamp = metrics.viewBottom - objectMetrics.height;
// If the object is taller than the workspace we want to
// top-align the block, which means setting the bottom clamp to
// match.
bottomClamp = Math.max(topClamp, bottomClamp);
var newYPosition = Blockly.utils.math.clamp(
topClamp, objectMetrics.top, bottomClamp);
var deltaY = newYPosition - objectMetrics.top;
// Note: Even in RTL mode the "anchor" of the object is the
// top-left corner of the object.
// The left edge of the object should ideally be positioned at
// or to the right of the left edge of the workspace.
var leftClamp = metrics.viewLeft;
// The left edge of the object should ideally be positioned so
// that the right of the object is not outside the workspace bounds.
var rightClamp = metrics.viewRight - objectMetrics.width;
if (metrics.RTL) {
// If the object is wider than the workspace and we're in RTL
// mode we want to right-align the block, which means setting
// the left clamp to match.
leftClamp = Math.min(rightClamp, leftClamp);
} else {
// If the object is wider than the workspace and we're in LTR
// mode we want to left-align the block, which means setting
// the right clamp to match.
rightClamp = Math.max(leftClamp, rightClamp);
}
var newXPosition = Blockly.utils.math.clamp(
leftClamp, objectMetrics.left, rightClamp);
var deltaX = newXPosition - objectMetrics.left;
object.moveBy(deltaX, deltaY);
}
if (e) {
if (!e.group && object) {
console.warn('Moved object in bounds but there was no' +
' event group. This may break undo.');
}
if (oldGroup !== null) {
Blockly.Events.setGroup(oldGroup);
}
}
}
}
};
mainWorkspace.addChangeListener(bumpObjects);
}
mainWorkspace.addChangeListener(Blockly.bumpIntoBoundsHandler_(mainWorkspace));
// The SVG is now fully assembled.
Blockly.svgResize(mainWorkspace);
@@ -328,6 +190,148 @@ Blockly.createMainWorkspace_ = function(svg, options, blockDragSurface,
return mainWorkspace;
};
/**
* Extracts the object from the given event.
* @param {!Blockly.WorkspaceSvg} workspace The workspace the event originated
* from.
* @param {!Blockly.Events.BumpEvent} e An event containing an object.
* @return {?Blockly.BlockSvg|?Blockly.WorkspaceCommentSvg} The extracted
* object.
* @private
*/
Blockly.extractObjectFromEvent_ = function(workspace, e) {
var object = null;
switch (e.type) {
case Blockly.Events.BLOCK_CREATE:
case Blockly.Events.BLOCK_MOVE:
object = workspace.getBlockById(e.blockId);
if (object) {
object = object.getRootBlock();
}
break;
case Blockly.Events.COMMENT_CREATE:
case Blockly.Events.COMMENT_MOVE:
object = workspace.getCommentById(e.commentId);
break;
}
return object;
};
/**
* Bumps the top objects in the given workspace into bounds.
* @param {!Blockly.WorkspaceSvg} workspace The workspace.
* @private
*/
Blockly.bumpTopObjectsIntoBounds_ = function(workspace) {
var metricsManager = workspace.getMetricsManager();
if (!metricsManager.hasFixedEdges() || workspace.isDragging()) {
return;
}
var scrollMetricsInWsCoords = metricsManager.getScrollMetrics(true);
var topBlocks = workspace.getTopBoundedElements();
for (var i = 0, block; (block = topBlocks[i]); i++) {
Blockly.bumpObjectIntoBounds_(
workspace, scrollMetricsInWsCoords, block);
}
};
/**
* Creates a handler for bumping objects when they cross fixed bounds.
* @param {!Blockly.WorkspaceSvg} workspace The workspace to handle.
* @return {function(Blockly.Events.Abstract)} The event handler.
* @private
*/
Blockly.bumpIntoBoundsHandler_ = function(workspace) {
return function(e) {
var metricsManager = workspace.getMetricsManager();
if (!metricsManager.hasFixedEdges || workspace.isDragging()) {
return;
}
if (Blockly.Events.BUMP_EVENTS.indexOf(e.type) !== -1) {
var scrollMetricsInWsCoords = metricsManager.getScrollMetrics(true);
// Triggered by move/create event
var object = Blockly.extractObjectFromEvent_(workspace, e);
if (!object) {
return;
}
// Handle undo.
var oldGroup = Blockly.Events.getGroup();
Blockly.Events.setGroup(e.group);
var wasBumped = Blockly.bumpObjectIntoBounds_(
workspace, scrollMetricsInWsCoords,
/** @type {!Blockly.IBoundedElement} */ (object));
if (wasBumped && !e.group) {
console.warn('Moved object in bounds but there was no' +
' event group. This may break undo.');
}
if (oldGroup !== null) {
Blockly.Events.setGroup(oldGroup);
}
} else if (e.type === Blockly.Events.VIEWPORT_CHANGE) {
var viewportEvent = /** @type {!Blockly.Events.ViewportChange} */ (e);
if (viewportEvent.scale > viewportEvent.oldScale) {
Blockly.bumpTopObjectsIntoBounds_(workspace);
}
}
};
};
/**
* Bumps the given object that has passed out of bounds.
* @param {!Blockly.WorkspaceSvg} workspace The workspace containing the object.
* @param {!Blockly.MetricsManager.ContainerRegion} scrollMetrics Scroll metrics
* in workspace coordinates.
* @param {!Blockly.IBoundedElement} object The object to bump.
* @return {boolean} True if block was bumped.
* @private
*/
Blockly.bumpObjectIntoBounds_ = function(workspace, scrollMetrics, object) {
// Compute new top/left position for object.
var objectMetrics = object.getBoundingRectangle();
var height = objectMetrics.bottom - objectMetrics.top;
var width = objectMetrics.right - objectMetrics.left;
var topClamp = scrollMetrics.top;
var scrollMetricsBottom = scrollMetrics.top + scrollMetrics.height;
var bottomClamp = scrollMetricsBottom - height;
// If the object is taller than the workspace we want to
// top-align the block
var newYPosition =
Blockly.utils.math.clamp(topClamp, objectMetrics.top, bottomClamp);
var deltaY = newYPosition - objectMetrics.top;
// Note: Even in RTL mode the "anchor" of the object is the
// top-left corner of the object.
var leftClamp = scrollMetrics.left;
var scrollMetricsRight = scrollMetrics.left + scrollMetrics.width;
var rightClamp = scrollMetricsRight - width;
if (workspace.RTL) {
// If the object is wider than the workspace and we're in RTL
// mode we want to right-align the block, which means setting
// the left clamp to match.
leftClamp = Math.min(rightClamp, leftClamp);
} else {
// If the object is wider than the workspace and we're in LTR
// mode we want to left-align the block, which means setting
// the right clamp to match.
rightClamp = Math.max(leftClamp, rightClamp);
}
var newXPosition =
Blockly.utils.math.clamp(leftClamp, objectMetrics.left, rightClamp);
var deltaX = newXPosition - objectMetrics.left;
if (deltaX || deltaY) {
object.moveBy(deltaX, deltaY);
return true;
}
return false;
};
/**
* Initialize Blockly with various handlers.
* @param {!Blockly.WorkspaceSvg} mainWorkspace Newly created main workspace.
@@ -338,7 +342,7 @@ Blockly.init_ = function(mainWorkspace) {
var svg = mainWorkspace.getParentSvg();
// Suppress the browser's context menu.
Blockly.bindEventWithChecks_(
Blockly.browserEvents.conditionalBind(
/** @type {!Element} */ (svg.parentNode), 'contextmenu', null,
function(e) {
if (!Blockly.utils.isTargetInput(e)) {
@@ -346,11 +350,11 @@ Blockly.init_ = function(mainWorkspace) {
}
});
var workspaceResizeHandler = Blockly.bindEventWithChecks_(window, 'resize',
null,
function() {
var workspaceResizeHandler =
Blockly.browserEvents.conditionalBind(window, 'resize', null, function() {
Blockly.hideChaff(true);
Blockly.svgResize(mainWorkspace);
Blockly.bumpTopObjectsIntoBounds_(mainWorkspace);
});
mainWorkspace.setResizeHandlerWrapper(workspaceResizeHandler);
@@ -380,7 +384,14 @@ Blockly.init_ = function(mainWorkspace) {
}
if (options.moveOptions && options.moveOptions.scrollbars) {
mainWorkspace.scrollbar = new Blockly.ScrollbarPair(mainWorkspace);
var horizontalScroll = options.moveOptions.scrollbars === true ||
!!options.moveOptions.scrollbars.horizontal;
var verticalScroll = options.moveOptions.scrollbars === true ||
!!options.moveOptions.scrollbars.vertical;
mainWorkspace.scrollbar =
new Blockly.ScrollbarPair(
mainWorkspace, horizontalScroll, verticalScroll,
'blocklyMainWorkspaceScrollbar');
mainWorkspace.scrollbar.resize();
} else {
mainWorkspace.setMetrics({x: 0.5, y: 0.5});
@@ -405,7 +416,7 @@ Blockly.init_ = function(mainWorkspace) {
*/
Blockly.inject.bindDocumentEvents_ = function() {
if (!Blockly.documentEventsBound_) {
Blockly.bindEventWithChecks_(document, 'scroll', null, function() {
Blockly.browserEvents.conditionalBind(document, 'scroll', null, function() {
var workspaces = Blockly.Workspace.getAll();
for (var i = 0, workspace; (workspace = workspaces[i]); i++) {
if (workspace.updateInverseScreenCTM) {
@@ -413,15 +424,17 @@ Blockly.inject.bindDocumentEvents_ = function() {
}
}
});
Blockly.bindEventWithChecks_(document, 'keydown', null, Blockly.onKeyDown);
Blockly.browserEvents.conditionalBind(
document, 'keydown', null, Blockly.onKeyDown);
// longStop needs to run to stop the context menu from showing up. It
// should run regardless of what other touch event handlers have run.
Blockly.bindEvent_(document, 'touchend', null, Blockly.longStop_);
Blockly.bindEvent_(document, 'touchcancel', null, Blockly.longStop_);
Blockly.browserEvents.bind(document, 'touchend', null, Blockly.longStop_);
Blockly.browserEvents.bind(
document, 'touchcancel', null, Blockly.longStop_);
// Some iPad versions don't fire resize after portrait to landscape change.
if (Blockly.utils.userAgent.IPAD) {
Blockly.bindEventWithChecks_(window, 'orientationchange', document,
function() {
Blockly.browserEvents.conditionalBind(
window, 'orientationchange', document, function() {
// TODO (#397): Fix for multiple Blockly workspaces.
Blockly.svgResize(/** @type {!Blockly.WorkspaceSvg} */
(Blockly.getMainWorkspace()));
@@ -462,7 +475,7 @@ Blockly.inject.loadSounds_ = function(pathToMedia, workspace) {
var soundBinds = [];
var unbindSounds = function() {
while (soundBinds.length) {
Blockly.unbindEvent_(soundBinds.pop());
Blockly.browserEvents.unbind(soundBinds.pop());
}
audioMgr.preload();
};
@@ -473,10 +486,8 @@ Blockly.inject.loadSounds_ = function(pathToMedia, workspace) {
// necessary.
// Android ignores any sound not loaded as a result of a user action.
soundBinds.push(
Blockly.bindEventWithChecks_(document, 'mousemove', null, unbindSounds,
true));
soundBinds.push(
Blockly.bindEventWithChecks_(document, 'touchstart', null, unbindSounds,
true));
soundBinds.push(Blockly.browserEvents.conditionalBind(
document, 'mousemove', null, unbindSounds, true));
soundBinds.push(Blockly.browserEvents.conditionalBind(
document, 'touchstart', null, unbindSounds, true));
};

View File

@@ -13,8 +13,17 @@
goog.provide('Blockly.Input');
goog.require('Blockly.Connection');
/** @suppress {extraRequire} */
goog.require('Blockly.constants');
goog.require('Blockly.fieldRegistry');
/** @suppress {extraRequire} */
goog.require('Blockly.FieldLabel');
goog.require('Blockly.inputTypes');
goog.requireType('Blockly.Block');
goog.requireType('Blockly.BlockSvg');
goog.requireType('Blockly.Field');
goog.requireType('Blockly.RenderedConnection');
/**
@@ -27,7 +36,7 @@ goog.require('Blockly.FieldLabel');
* @constructor
*/
Blockly.Input = function(type, name, block, connection) {
if (type != Blockly.DUMMY_INPUT && !name) {
if (type != Blockly.inputTypes.DUMMY && !name) {
throw Error('Value inputs and statement inputs must have non-empty name.');
}
/** @type {number} */
@@ -49,7 +58,7 @@ Blockly.Input = function(type, name, block, connection) {
* Alignment of input's fields (left, right or centre).
* @type {number}
*/
Blockly.Input.prototype.align = Blockly.ALIGN_LEFT;
Blockly.Input.prototype.align = Blockly.constants.ALIGN.LEFT;
/**
* Is the input visible?
@@ -100,7 +109,10 @@ Blockly.Input.prototype.insertFieldAt = function(index, field, opt_name) {
// Generate a FieldLabel when given a plain text field.
if (typeof field == 'string') {
field = new Blockly.FieldLabel(/** @type {string} */ (field));
field = /** @type {!Blockly.Field} **/ (Blockly.fieldRegistry.fromJson({
'type': 'field_label',
'text': field,
}));
}
field.setSourceBlock(this.sourceBlock_);
@@ -111,17 +123,16 @@ Blockly.Input.prototype.insertFieldAt = function(index, field, opt_name) {
field.name = opt_name;
field.setVisible(this.isVisible());
var fieldDropdown = /** @type {Blockly.FieldDropdown} */ (field);
if (fieldDropdown.prefixField) {
if (field.prefixField) {
// Add any prefix.
index = this.insertFieldAt(index, fieldDropdown.prefixField);
index = this.insertFieldAt(index, field.prefixField);
}
// Add the field to the field row.
this.fieldRow.splice(index, 0, field);
++index;
if (fieldDropdown.suffixField) {
if (field.suffixField) {
// Add any suffix.
index = this.insertFieldAt(index, fieldDropdown.suffixField);
index = this.insertFieldAt(index, field.suffixField);
}
if (this.sourceBlock_.rendered) {
@@ -233,8 +244,8 @@ Blockly.Input.prototype.setCheck = function(check) {
/**
* Change the alignment of the connection's field(s).
* @param {number} align One of Blockly.ALIGN_LEFT, ALIGN_CENTRE, ALIGN_RIGHT.
* In RTL mode directions are reversed, and ALIGN_RIGHT aligns to the left.
* @param {number} align One of the values of Blockly.constants.ALIGN.
* In RTL mode directions are reversed, and ALIGN.RIGHT aligns to the left.
* @return {!Blockly.Input} The input being modified (to allow chaining).
*/
Blockly.Input.prototype.setAlign = function(align) {

29
core/input_types.js Normal file
View File

@@ -0,0 +1,29 @@
/**
* @license
* Copyright 2021 Google LLC
* SPDX-License-Identifier: Apache-2.0
*/
/**
* @fileoverview An enum for the possible types of inputs.
* @author fenichel@google.com (Rachel Fenichel)
*/
'use strict';
goog.provide('Blockly.inputTypes');
goog.require('Blockly.connectionTypes');
/**
* Enum for the type of a connection or input.
* @enum {number}
*/
Blockly.inputTypes = {
// A right-facing value input. E.g. 'set item to' or 'return'.
VALUE: Blockly.connectionTypes.INPUT_VALUE,
// A down-facing block stack. E.g. 'if-do' or 'else'.
STATEMENT: Blockly.connectionTypes.NEXT_STATEMENT,
// A dummy input. Used to add field(s) with no input.
DUMMY: 5
};

View File

@@ -13,9 +13,16 @@
goog.provide('Blockly.InsertionMarkerManager');
goog.require('Blockly.blockAnimations');
goog.require('Blockly.connectionTypes');
/** @suppress {extraRequire} */
goog.require('Blockly.constants');
goog.require('Blockly.Events');
goog.requireType('Blockly.BlockSvg');
goog.requireType('Blockly.RenderedConnection');
goog.requireType('Blockly.utils.Coordinate');
goog.requireType('Blockly.WorkspaceSvg');
/**
* Class that controls updates to connections during drags. It is primarily
@@ -268,7 +275,7 @@ Blockly.InsertionMarkerManager.prototype.createMarkerBlock_ = function(sourceBlo
// child blocks here.
for (var i = 0; i < sourceBlock.inputList.length; i++) {
var sourceInput = sourceBlock.inputList[i];
if (sourceInput.name == Blockly.Block.COLLAPSED_INPUT_NAME) {
if (sourceInput.name == Blockly.constants.COLLAPSED_INPUT_NAME) {
continue; // Ignore the collapsed input.
}
var resultInput = result.inputList[i];
@@ -612,7 +619,8 @@ Blockly.InsertionMarkerManager.prototype.hideInsertionMarker_ = function() {
var isFirstInStatementStack =
(imConn == markerNext && !(markerPrev && markerPrev.targetConnection));
var isFirstInOutputStack = imConn.type == Blockly.INPUT_VALUE &&
var isFirstInOutputStack =
imConn.type == Blockly.connectionTypes.INPUT_VALUE &&
!(markerOutput && markerOutput.targetConnection);
// The insertion marker is the first block in a stack. Unplug won't do
// anything in that case. Instead, unplug the following block.
@@ -620,7 +628,8 @@ Blockly.InsertionMarkerManager.prototype.hideInsertionMarker_ = function() {
imConn.targetBlock().unplug(false);
}
// Inside of a C-block, first statement connection.
else if (imConn.type == Blockly.NEXT_STATEMENT && imConn != markerNext) {
else if (imConn.type == Blockly.connectionTypes.NEXT_STATEMENT &&
imConn != markerNext) {
var innerConnection = imConn.targetConnection;
innerConnection.getSourceBlock().unplug(false);

View File

@@ -14,9 +14,12 @@
goog.provide('Blockly.IASTNodeLocation');
goog.provide('Blockly.IASTNodeLocationSvg');
goog.provide('Blockly.IASTNodeLocationWithBlock');
goog.provide('Blockly.IBlocklyActionable');
goog.provide('Blockly.IKeyboardAccessible');
goog.requireType('Blockly.Block');
goog.requireType('Blockly.ShortcutRegistry');
/**
* An AST node location interface.
* @interface
@@ -59,15 +62,14 @@ Blockly.IASTNodeLocationWithBlock.prototype.getSourceBlock;
/**
* An interface for an object that handles Blockly actions when keyboard
* navigation is enabled.
* An interface for an object that handles keyboard shortcuts.
* @interface
*/
Blockly.IBlocklyActionable = function() {};
Blockly.IKeyboardAccessible = function() {};
/**
* Handles the given action.
* @param {!Blockly.ShortcutRegistry.KeyboardShortcut} action The action to be handled.
* @return {boolean} True if the action has been handled, false otherwise.
* Handles the given keyboard shortcut.
* @param {!Blockly.ShortcutRegistry.KeyboardShortcut} shortcut The shortcut to be handled.
* @return {boolean} True if the shortcut has been handled, false otherwise.
*/
Blockly.IBlocklyActionable.prototype.onBlocklyAction;
Blockly.IKeyboardAccessible.prototype.onShortcut;

View File

@@ -29,3 +29,10 @@ Blockly.IBoundedElement = function() {};
* @return {!Blockly.utils.Rect} Object with coordinates of the bounded element.
*/
Blockly.IBoundedElement.prototype.getBoundingRectangle;
/**
* Move the element by a relative offset.
* @param {number} dx Horizontal offset in workspace units.
* @param {number} dy Vertical offset in workspace units.
*/
Blockly.IBoundedElement.prototype.moveBy;

View File

@@ -13,8 +13,10 @@
goog.provide('Blockly.IBubble');
goog.requireType('Blockly.BlockDragSurfaceSvg');
goog.requireType('Blockly.IContextMenu');
goog.requireType('Blockly.IDeletable');
goog.requireType('Blockly.utils.Coordinate');
/**

View File

@@ -14,6 +14,7 @@
goog.provide('Blockly.IConnectionChecker');
goog.requireType('Blockly.Connection');
goog.requireType('Blockly.RenderedConnection');
/**

View File

@@ -14,6 +14,8 @@
goog.provide('Blockly.IDeleteArea');
goog.requireType('Blockly.utils.Rect');
/**
* Interface for a component that can delete a block that is dropped on top of it.

View File

@@ -15,7 +15,6 @@ goog.provide('Blockly.IFlyout');
goog.requireType('Blockly.BlockSvg');
goog.requireType('Blockly.IRegistrable');
goog.requireType('Blockly.utils.dom');
goog.requireType('Blockly.utils.Coordinate');
goog.requireType('Blockly.utils.Svg');
goog.requireType('Blockly.utils.toolbox');

View File

@@ -0,0 +1,145 @@
/**
* @license
* Copyright 2021 Google LLC
* SPDX-License-Identifier: Apache-2.0
*/
/**
* @fileoverview The interface for a metrics manager.
* @author aschmiedt@google.com (Abby Schmiedt)
*/
'use strict';
goog.provide('Blockly.IMetricsManager');
goog.requireType('Blockly.MetricsManager');
goog.requireType('Blockly.utils.Metrics');
goog.requireType('Blockly.utils.Size');
/**
* Interface for a metrics manager.
* @interface
*/
Blockly.IMetricsManager = function() {};
/**
* Returns whether the scroll area has fixed edges.
* @return {boolean} Whether the scroll area has fixed edges.
* @package
*/
Blockly.IMetricsManager.prototype.hasFixedEdges;
/**
* Returns the metrics for the scroll area of the workspace.
* @param {boolean=} opt_getWorkspaceCoordinates True to get the scroll metrics
* in workspace coordinates, false to get them in pixel coordinates.
* @param {!Blockly.MetricsManager.ContainerRegion=} opt_viewMetrics The view
* metrics if they have been previously computed. Passing in null may cause
* the view metrics to be computed again, if it is needed.
* @param {!Blockly.MetricsManager.ContainerRegion=} opt_contentMetrics The
* content metrics if they have been previously computed. Passing in null
* may cause the content metrics to be computed again, if it is needed.
* @return {!Blockly.MetricsManager.ContainerRegion} The metrics for the scroll
* container
*/
Blockly.IMetricsManager.prototype.getScrollMetrics;
/**
* Gets the width and the height of the flyout on the workspace in pixel
* coordinates. Returns 0 for the width and height if the workspace has a
* category toolbox instead of a simple toolbox.
* @param {boolean=} opt_own Whether to only return the workspace's own flyout.
* @return {!Blockly.MetricsManager.ToolboxMetrics} The width and height of the
* flyout.
* @public
*/
Blockly.IMetricsManager.prototype.getFlyoutMetrics;
/**
* Gets the width, height and position of the toolbox on the workspace in pixel
* coordinates. Returns 0 for the width and height if the workspace has a simple
* toolbox instead of a category toolbox. To get the width and height of a
* simple toolbox @see {@link getFlyoutMetrics}.
* @return {!Blockly.MetricsManager.ToolboxMetrics} The object with the width,
* height and position of the toolbox.
* @public
*/
Blockly.IMetricsManager.prototype.getToolboxMetrics;
/**
* Gets the width and height of the workspace's parent svg element in pixel
* coordinates. This area includes the toolbox and the visible workspace area.
* @return {!Blockly.utils.Size} The width and height of the workspace's parent
* svg element.
* @public
*/
Blockly.IMetricsManager.prototype.getSvgMetrics;
/**
* Gets the absolute left and absolute top in pixel coordinates.
* This is where the visible workspace starts in relation to the svg container.
* @return {!Blockly.MetricsManager.AbsoluteMetrics} The absolute metrics for
* the workspace.
* @public
*/
Blockly.IMetricsManager.prototype.getAbsoluteMetrics;
/**
* Gets the metrics for the visible workspace in either pixel or workspace
* coordinates. The visible workspace does not include the toolbox or flyout.
* @param {boolean=} opt_getWorkspaceCoordinates True to get the view metrics in
* workspace coordinates, false to get them in pixel coordinates.
* @return {!Blockly.MetricsManager.ContainerRegion} The width, height, top and
* left of the viewport in either workspace coordinates or pixel
* coordinates.
* @public
*/
Blockly.IMetricsManager.prototype.getViewMetrics;
/**
* Gets content metrics in either pixel or workspace coordinates.
* The content area is a rectangle around all the top bounded elements on the
* workspace (workspace comments and blocks).
* @param {boolean=} opt_getWorkspaceCoordinates True to get the content metrics
* in workspace coordinates, false to get them in pixel coordinates.
* @return {!Blockly.MetricsManager.ContainerRegion} The
* metrics for the content container.
* @public
*/
Blockly.IMetricsManager.prototype.getContentMetrics;
/**
* Returns an object with all the metrics required to size scrollbars for a
* top level workspace. The following properties are computed:
* Coordinate system: pixel coordinates, -left, -up, +right, +down
* .viewHeight: Height of the visible portion of the workspace.
* .viewWidth: Width of the visible portion of the workspace.
* .contentHeight: Height of the content.
* .contentWidth: Width of the content.
* .svgHeight: Height of the Blockly div (the view + the toolbox,
* simple or otherwise),
* .svgWidth: Width of the Blockly div (the view + the toolbox,
* simple or otherwise),
* .viewTop: Top-edge of the visible portion of the workspace, relative to
* the workspace origin.
* .viewLeft: Left-edge of the visible portion of the workspace, relative to
* the workspace origin.
* .contentTop: Top-edge of the content, relative to the workspace origin.
* .contentLeft: Left-edge of the content relative to the workspace origin.
* .absoluteTop: Top-edge of the visible portion of the workspace, relative
* to the blocklyDiv.
* .absoluteLeft: Left-edge of the visible portion of the workspace, relative
* to the blocklyDiv.
* .toolboxWidth: Width of the toolbox, if it exists. Otherwise zero.
* .toolboxHeight: Height of the toolbox, if it exists. Otherwise zero.
* .flyoutWidth: Width of the flyout if it is always open. Otherwise zero.
* .flyoutHeight: Height of the flyout if it is always open. Otherwise zero.
* .toolboxPosition: Top, bottom, left or right. Use TOOLBOX_AT constants to
* compare.
* @return {!Blockly.utils.Metrics} Contains size and position metrics of a top
* level workspace.
* @public
*/
Blockly.IMetricsManager.prototype.getMetrics;

View File

@@ -0,0 +1,22 @@
/**
* @license
* Copyright 2021 Google LLC
* SPDX-License-Identifier: Apache-2.0
*/
/**
* @fileoverview Interface for a plugin.
* @author kozbial@google.com (Monica Kozbial)
*/
'use strict';
goog.provide('Blockly.IPlugin');
/**
* The interface for a workspace plugin.
* @interface
*/
Blockly.IPlugin = function() {};

View File

@@ -0,0 +1,39 @@
/**
* @license
* Copyright 2021 Google LLC
* SPDX-License-Identifier: Apache-2.0
*/
/**
* @fileoverview The interface for a positionable ui element.
* @author kozbial@google.com (Monica Kozbial)
*/
'use strict';
goog.provide('Blockly.IPositionable');
goog.require('Blockly.IPlugin');
/**
* Interface for a component that is positioned on top of the workspace.
* @extends {Blockly.IPlugin}
* @interface
*/
Blockly.IPositionable = function() {};
/**
* Positions the element. Called when the window is resized.
* @param {!Blockly.MetricsManager.UiMetrics} metrics The workspace metrics.
* @param {!Array<!Blockly.utils.Rect>} savedPositions List of rectangles that
* are already on the workspace.
*/
Blockly.IPositionable.prototype.position;
/**
* Returns the bounding rectangle of the UI element in pixel units relative to
* the Blockly injection div.
* @return {!Blockly.utils.Rect} The plugins bounding box.
*/
Blockly.IPositionable.prototype.getBoundingRectangle;

View File

@@ -0,0 +1,20 @@
/**
* @license
* Copyright 2021 Google LLC
* SPDX-License-Identifier: Apache-2.0
*/
/**
* @fileoverview Interface for plugins that can be registered on the workspace.
* @author kozbial@google.com (Monica Kozbial)
*/
'use strict';
goog.provide('Blockly.IWorkspacePlugin');
/**
* Base interface for a plugin that can be registered on the workspace.
* @interface
*/
Blockly.IWorkspacePlugin = function() {};

View File

@@ -12,11 +12,18 @@
goog.provide('Blockly.ASTNode');
goog.require('Blockly.connectionTypes');
/** @suppress {extraRequire} */
goog.require('Blockly.constants');
goog.require('Blockly.utils.Coordinate');
goog.requireType('Blockly.Block');
goog.requireType('Blockly.Connection');
goog.requireType('Blockly.Field');
goog.requireType('Blockly.IASTNodeLocation');
goog.requireType('Blockly.IASTNodeLocationWithBlock');
goog.requireType('Blockly.Input');
goog.requireType('Blockly.Workspace');
/**
@@ -142,16 +149,17 @@ Blockly.ASTNode.createConnectionNode = function(connection) {
if (!connection) {
return null;
}
if (connection.type == Blockly.INPUT_VALUE) {
var type = connection.type;
if (type == Blockly.connectionTypes.INPUT_VALUE) {
return Blockly.ASTNode.createInputNode(connection.getParentInput());
} else if (connection.type == Blockly.NEXT_STATEMENT &&
} else if (type == Blockly.connectionTypes.NEXT_STATEMENT &&
connection.getParentInput()) {
return Blockly.ASTNode.createInputNode(connection.getParentInput());
} else if (connection.type == Blockly.NEXT_STATEMENT) {
} else if (type == Blockly.connectionTypes.NEXT_STATEMENT) {
return new Blockly.ASTNode(Blockly.ASTNode.types.NEXT, connection);
} else if (connection.type == Blockly.OUTPUT_VALUE) {
} else if (type == Blockly.connectionTypes.OUTPUT_VALUE) {
return new Blockly.ASTNode(Blockly.ASTNode.types.OUTPUT, connection);
} else if (connection.type == Blockly.PREVIOUS_STATEMENT) {
} else if (type == Blockly.connectionTypes.PREVIOUS_STATEMENT) {
return new Blockly.ASTNode(Blockly.ASTNode.types.PREVIOUS, connection);
}
return null;

View File

@@ -15,6 +15,7 @@ goog.provide('Blockly.BasicCursor');
goog.require('Blockly.ASTNode');
goog.require('Blockly.Cursor');
goog.require('Blockly.registry');
/**
@@ -29,6 +30,12 @@ Blockly.BasicCursor = function() {
};
Blockly.utils.object.inherits(Blockly.BasicCursor, Blockly.Cursor);
/**
* Name used for registering a basic cursor.
* @const {string}
*/
Blockly.BasicCursor.registrationName = 'basicCursor';
/**
* Find the next node in the pre order traversal.
* @return {Blockly.ASTNode} The next node, or null if the current node is
@@ -50,7 +57,8 @@ Blockly.BasicCursor.prototype.next = function() {
/**
* For a basic cursor we only have the ability to go next and previous, so
* in will also allow the user to get to the next node in the pre order traversal.
* in will also allow the user to get to the next node in the pre order
* traversal.
* @return {Blockly.ASTNode} The next node, or null if the current node is
* not set or there is no next value.
* @override
@@ -80,7 +88,8 @@ Blockly.BasicCursor.prototype.prev = function() {
/**
* For a basic cursor we only have the ability to go next and previous, so
* out will allow the user to get to the previous node in the pre order traversal.
* out will allow the user to get to the previous node in the pre order
* traversal.
* @return {Blockly.ASTNode} The previous node, or null if the current node is
* not set or there is no previous value.
* @override
@@ -119,9 +128,9 @@ Blockly.BasicCursor.prototype.getNextNode_ = function(node, isValid) {
};
/**
* Reverses the pre order traversal in order to find the previous node. This will
* allow a user to easily navigate the entire Blockly AST without having to go in
* and out levels on the tree.
* Reverses the pre order traversal in order to find the previous node. This
* will allow a user to easily navigate the entire Blockly AST without having to
* go in and out levels on the tree.
* @param {Blockly.ASTNode} node The current position in the AST.
* @param {!function(Blockly.ASTNode) : boolean} isValid A function true/false
* depending on whether the given node should be traversed.
@@ -204,5 +213,8 @@ Blockly.BasicCursor.prototype.getRightMostChild_ = function(node) {
newNode = newNode.next();
}
return this.getRightMostChild_(newNode);
};
Blockly.registry.register(
Blockly.registry.Type.CURSOR, Blockly.BasicCursor.registrationName,
Blockly.BasicCursor);

View File

@@ -15,19 +15,15 @@ goog.provide('Blockly.Cursor');
goog.require('Blockly.ASTNode');
goog.require('Blockly.Marker');
goog.require('Blockly.navigation');
goog.require('Blockly.registry');
goog.require('Blockly.utils.object');
goog.requireType('Blockly.IBlocklyActionable');
goog.requireType('Blockly.ShortcutRegistry');
/**
* Class for a cursor.
* A cursor controls how a user navigates the Blockly AST.
* @constructor
* @extends {Blockly.Marker}
* @implements {Blockly.IBlocklyActionable}
*/
Blockly.Cursor = function() {
Blockly.Cursor.superClass_.constructor.call(this);
@@ -43,7 +39,7 @@ Blockly.utils.object.inherits(Blockly.Cursor, Blockly.Marker);
* Find the next connection, field, or block.
* @return {Blockly.ASTNode} The next element, or null if the current node is
* not set or there is no next value.
* @protected
* @public
*/
Blockly.Cursor.prototype.next = function() {
var curNode = this.getCurNode();
@@ -53,8 +49,8 @@ Blockly.Cursor.prototype.next = function() {
var newNode = curNode.next();
while (newNode && newNode.next() &&
(newNode.getType() == Blockly.ASTNode.types.NEXT ||
newNode.getType() == Blockly.ASTNode.types.BLOCK)) {
(newNode.getType() == Blockly.ASTNode.types.NEXT ||
newNode.getType() == Blockly.ASTNode.types.BLOCK)) {
newNode = newNode.next();
}
@@ -68,7 +64,7 @@ Blockly.Cursor.prototype.next = function() {
* Find the in connection or field.
* @return {Blockly.ASTNode} The in element, or null if the current node is
* not set or there is no in value.
* @protected
* @public
*/
Blockly.Cursor.prototype.in = function() {
var curNode = this.getCurNode();
@@ -78,7 +74,7 @@ Blockly.Cursor.prototype.in = function() {
// If we are on a previous or output connection, go to the block level before
// performing next operation.
if (curNode.getType() == Blockly.ASTNode.types.PREVIOUS ||
curNode.getType() == Blockly.ASTNode.types.OUTPUT) {
curNode.getType() == Blockly.ASTNode.types.OUTPUT) {
curNode = curNode.next();
}
var newNode = curNode.in();
@@ -93,7 +89,7 @@ Blockly.Cursor.prototype.in = function() {
* Find the previous connection, field, or block.
* @return {Blockly.ASTNode} The previous element, or null if the current node
* is not set or there is no previous value.
* @protected
* @public
*/
Blockly.Cursor.prototype.prev = function() {
var curNode = this.getCurNode();
@@ -103,8 +99,8 @@ Blockly.Cursor.prototype.prev = function() {
var newNode = curNode.prev();
while (newNode && newNode.prev() &&
(newNode.getType() == Blockly.ASTNode.types.NEXT ||
newNode.getType() == Blockly.ASTNode.types.BLOCK)) {
(newNode.getType() == Blockly.ASTNode.types.NEXT ||
newNode.getType() == Blockly.ASTNode.types.BLOCK)) {
newNode = newNode.prev();
}
@@ -118,7 +114,7 @@ Blockly.Cursor.prototype.prev = function() {
* Find the out connection, field, or block.
* @return {Blockly.ASTNode} The out element, or null if the current node is
* not set or there is no out value.
* @protected
* @public
*/
Blockly.Cursor.prototype.out = function() {
var curNode = this.getCurNode();
@@ -137,34 +133,5 @@ Blockly.Cursor.prototype.out = function() {
return newNode;
};
/**
* Handles the given action.
* This is only triggered when keyboard navigation is enabled.
* @param {!Blockly.ShortcutRegistry.KeyboardShortcut} action The action to be handled.
* @return {boolean} True if the action has been handled, false otherwise.
*/
Blockly.Cursor.prototype.onBlocklyAction = function(action) {
// If we are on a field give it the option to handle the action
if (this.getCurNode() &&
this.getCurNode().getType() === Blockly.ASTNode.types.FIELD &&
(/** @type {!Blockly.Field} */ (this.getCurNode().getLocation()))
.onBlocklyAction(action)) {
return true;
}
switch (action.name) {
case Blockly.navigation.actionNames.PREVIOUS:
this.prev();
return true;
case Blockly.navigation.actionNames.OUT:
this.out();
return true;
case Blockly.navigation.actionNames.NEXT:
this.next();
return true;
case Blockly.navigation.actionNames.IN:
this.in();
return true;
default:
return false;
}
};
Blockly.registry.register(
Blockly.registry.Type.CURSOR, Blockly.registry.DEFAULT, Blockly.Cursor);

View File

@@ -1,108 +0,0 @@
/**
* @license
* Copyright 2019 Google LLC
* SPDX-License-Identifier: Apache-2.0
*/
/**
* @fileoverview The class representing a cursor used to navigate the flyout.
* Used primarily for keyboard navigation.
* @author aschmiedt@google.com (Abby Schmiedt)
*/
'use strict';
goog.provide('Blockly.FlyoutCursor');
goog.require('Blockly.Cursor');
goog.require('Blockly.navigation');
goog.require('Blockly.utils.object');
goog.requireType('Blockly.ShortcutRegistry');
/**
* Class for a flyout cursor.
* This controls how a user navigates blocks in the flyout.
* @constructor
* @extends {Blockly.Cursor}
*/
Blockly.FlyoutCursor = function() {
Blockly.FlyoutCursor.superClass_.constructor.call(this);
};
Blockly.utils.object.inherits(Blockly.FlyoutCursor, Blockly.Cursor);
/**
* Handles the given action.
* This is only triggered when keyboard navigation is enabled.
* @param {!Blockly.ShortcutRegistry.KeyboardShortcut} action The action to be handled.
* @return {boolean} True if the action has been handled, false otherwise.
* @override
*/
Blockly.FlyoutCursor.prototype.onBlocklyAction = function(action) {
switch (action.name) {
case Blockly.navigation.actionNames.PREVIOUS:
this.prev();
return true;
case Blockly.navigation.actionNames.NEXT:
this.next();
return true;
default:
return false;
}
};
/**
* Find the next connection, field, or block.
* @return {Blockly.ASTNode} The next element, or null if the current node is
* not set or there is no next value.
* @override
*/
Blockly.FlyoutCursor.prototype.next = function() {
var curNode = this.getCurNode();
if (!curNode) {
return null;
}
var newNode = curNode.next();
if (newNode) {
this.setCurNode(newNode);
}
return newNode;
};
/**
* This is a no-op since a flyout cursor can not go in.
* @return {null} Always null.
* @override
*/
Blockly.FlyoutCursor.prototype.in = function() {
return null;
};
/**
* Find the previous connection, field, or block.
* @return {Blockly.ASTNode} The previous element, or null if the current node
* is not set or there is no previous value.
* @override
*/
Blockly.FlyoutCursor.prototype.prev = function() {
var curNode = this.getCurNode();
if (!curNode) {
return null;
}
var newNode = curNode.prev();
if (newNode) {
this.setCurNode(newNode);
}
return newNode;
};
/**
* This is a no-op since a flyout cursor can not go out.
* @return {null} Always null.
* @override
*/
Blockly.FlyoutCursor.prototype.out = function() {
return null;
};

View File

@@ -14,7 +14,8 @@
goog.provide('Blockly.Marker');
goog.require('Blockly.ASTNode');
goog.require('Blockly.navigation');
goog.requireType('Blockly.blockRendering.MarkerSvg');
/**

File diff suppressed because it is too large Load Diff

View File

@@ -17,6 +17,8 @@ goog.require('Blockly.ASTNode');
goog.require('Blockly.BasicCursor');
goog.require('Blockly.utils.object');
goog.requireType('Blockly.Field');
/**
* A cursor for navigating between tab navigable fields.

View File

@@ -15,6 +15,8 @@ goog.provide('Blockly.MarkerManager');
goog.require('Blockly.Cursor');
goog.require('Blockly.Marker');
goog.requireType('Blockly.WorkspaceSvg');
/**
* Class to manage the multiple markers and the cursor on a workspace.
@@ -52,6 +54,13 @@ Blockly.MarkerManager = function(workspace){
this.workspace_ = workspace;
};
/**
* The name of the local marker.
* @type {string}
* @const
*/
Blockly.MarkerManager.LOCAL_MARKER = 'local_marker_1';
/**
* Register the marker by adding it to the map of markers.
* @param {string} id A unique identifier for the marker.

View File

@@ -12,12 +12,16 @@
goog.provide('Blockly.Menu');
goog.require('Blockly.browserEvents');
goog.require('Blockly.utils.aria');
goog.require('Blockly.utils.Coordinate');
goog.require('Blockly.utils.dom');
goog.require('Blockly.utils.KeyCodes');
goog.require('Blockly.utils.style');
goog.requireType('Blockly.MenuItem');
goog.requireType('Blockly.utils.Size');
/**
* A basic menu class.
@@ -52,35 +56,35 @@ Blockly.Menu = function() {
/**
* Mouse over event data.
* @type {?Blockly.EventData}
* @type {?Blockly.browserEvents.Data}
* @private
*/
this.mouseOverHandler_ = null;
/**
* Click event data.
* @type {?Blockly.EventData}
* @type {?Blockly.browserEvents.Data}
* @private
*/
this.clickHandler_ = null;
/**
* Mouse enter event data.
* @type {?Blockly.EventData}
* @type {?Blockly.browserEvents.Data}
* @private
*/
this.mouseEnterHandler_ = null;
/**
* Mouse leave event data.
* @type {?Blockly.EventData}
* @type {?Blockly.browserEvents.Data}
* @private
*/
this.mouseLeaveHandler_ = null;
/**
* Key down event data.
* @type {?Blockly.EventData}
* @type {?Blockly.browserEvents.Data}
* @private
*/
this.onKeyDownHandler_ = null;
@@ -129,16 +133,16 @@ Blockly.Menu.prototype.render = function(container) {
}
// Add event handlers.
this.mouseOverHandler_ = Blockly.bindEventWithChecks_(element,
'mouseover', this, this.handleMouseOver_, true);
this.clickHandler_ = Blockly.bindEventWithChecks_(element,
'click', this, this.handleClick_, true);
this.mouseEnterHandler_ = Blockly.bindEventWithChecks_(element,
'mouseenter', this, this.handleMouseEnter_, true);
this.mouseLeaveHandler_ = Blockly.bindEventWithChecks_(element,
'mouseleave', this, this.handleMouseLeave_, true);
this.onKeyDownHandler_ = Blockly.bindEventWithChecks_(element,
'keydown', this, this.handleKeyEvent_);
this.mouseOverHandler_ = Blockly.browserEvents.conditionalBind(
element, 'mouseover', this, this.handleMouseOver_, true);
this.clickHandler_ = Blockly.browserEvents.conditionalBind(
element, 'click', this, this.handleClick_, true);
this.mouseEnterHandler_ = Blockly.browserEvents.conditionalBind(
element, 'mouseenter', this, this.handleMouseEnter_, true);
this.mouseLeaveHandler_ = Blockly.browserEvents.conditionalBind(
element, 'mouseleave', this, this.handleMouseLeave_, true);
this.onKeyDownHandler_ = Blockly.browserEvents.conditionalBind(
element, 'keydown', this, this.handleKeyEvent_);
container.appendChild(element);
};
@@ -191,23 +195,23 @@ Blockly.Menu.prototype.setRole = function(roleName) {
Blockly.Menu.prototype.dispose = function() {
// Remove event handlers.
if (this.mouseOverHandler_) {
Blockly.unbindEvent_(this.mouseOverHandler_);
Blockly.browserEvents.unbind(this.mouseOverHandler_);
this.mouseOverHandler_ = null;
}
if (this.clickHandler_) {
Blockly.unbindEvent_(this.clickHandler_);
Blockly.browserEvents.unbind(this.clickHandler_);
this.clickHandler_ = null;
}
if (this.mouseEnterHandler_) {
Blockly.unbindEvent_(this.mouseEnterHandler_);
Blockly.browserEvents.unbind(this.mouseEnterHandler_);
this.mouseEnterHandler_ = null;
}
if (this.mouseLeaveHandler_) {
Blockly.unbindEvent_(this.mouseLeaveHandler_);
Blockly.browserEvents.unbind(this.mouseLeaveHandler_);
this.mouseLeaveHandler_ = null;
}
if (this.onKeyDownHandler_) {
Blockly.unbindEvent_(this.onKeyDownHandler_);
Blockly.browserEvents.unbind(this.onKeyDownHandler_);
this.onKeyDownHandler_ = null;
}

597
core/metrics_manager.js Normal file
View File

@@ -0,0 +1,597 @@
/**
* @license
* Copyright 2021 Google LLC
* SPDX-License-Identifier: Apache-2.0
*/
/**
* @fileoverview Calculates and reports workspace metrics.
* @author aschmiedt@google.com (Abby Schmiedt)
*/
'use strict';
goog.provide('Blockly.FlyoutMetricsManager');
goog.provide('Blockly.MetricsManager');
goog.require('Blockly.IMetricsManager');
goog.require('Blockly.registry');
goog.require('Blockly.utils.Size');
goog.require('Blockly.utils.toolbox');
goog.requireType('Blockly.IFlyout');
goog.requireType('Blockly.IToolbox');
goog.requireType('Blockly.utils.Metrics');
goog.requireType('Blockly.WorkspaceSvg');
/**
* The manager for all workspace metrics calculations.
* @param {!Blockly.WorkspaceSvg} workspace The workspace to calculate metrics
* for.
* @implements {Blockly.IMetricsManager}
* @constructor
*/
Blockly.MetricsManager = function(workspace) {
/**
* The workspace to calculate metrics for.
* @type {!Blockly.WorkspaceSvg}
* @protected
*/
this.workspace_ = workspace;
};
/**
* Describes the width, height and location of the toolbox on the main
* workspace.
* @typedef {{
* width: number,
* height: number,
* position: !Blockly.utils.toolbox.Position
* }}
*/
Blockly.MetricsManager.ToolboxMetrics;
/**
* Describes where the viewport starts in relation to the workspace svg.
* @typedef {{
* left: number,
* top: number
* }}
*/
Blockly.MetricsManager.AbsoluteMetrics;
/**
* All the measurements needed to describe the size and location of a container.
* @typedef {{
* height: number,
* width: number,
* top: number,
* left: number
* }}
*/
Blockly.MetricsManager.ContainerRegion;
/**
* Describes fixed edges of the workspace.
* @typedef {{
* top: (number|undefined),
* bottom: (number|undefined),
* left: (number|undefined),
* right: (number|undefined)
* }}
*/
Blockly.MetricsManager.FixedEdges;
/**
* Common metrics used for ui elements.
* @typedef {{
* viewMetrics: !Blockly.MetricsManager.ContainerRegion,
* absoluteMetrics: !Blockly.MetricsManager.AbsoluteMetrics,
* toolboxMetrics: !Blockly.MetricsManager.ToolboxMetrics
* }}
*/
Blockly.MetricsManager.UiMetrics;
/**
* Gets the dimensions of the given workspace component, in pixel coordinates.
* @param {?Blockly.IToolbox|?Blockly.IFlyout} elem The element to get the
* dimensions of, or null. It should be a toolbox or flyout, and should
* implement getWidth() and getHeight().
* @return {!Blockly.utils.Size} An object containing width and height
* attributes, which will both be zero if elem did not exist.
* @protected
*/
Blockly.MetricsManager.prototype.getDimensionsPx_ = function(elem) {
var width = 0;
var height = 0;
if (elem) {
width = elem.getWidth();
height = elem.getHeight();
}
return new Blockly.utils.Size(width, height);
};
/**
* Gets the width and the height of the flyout on the workspace in pixel
* coordinates. Returns 0 for the width and height if the workspace has a
* category toolbox instead of a simple toolbox.
* @param {boolean=} opt_own Whether to only return the workspace's own flyout.
* @return {!Blockly.MetricsManager.ToolboxMetrics} The width and height of the
* flyout.
* @public
*/
Blockly.MetricsManager.prototype.getFlyoutMetrics = function(opt_own) {
var flyoutDimensions =
this.getDimensionsPx_(this.workspace_.getFlyout(opt_own));
return {
width: flyoutDimensions.width,
height: flyoutDimensions.height,
position: this.workspace_.toolboxPosition
};
};
/**
* Gets the width, height and position of the toolbox on the workspace in pixel
* coordinates. Returns 0 for the width and height if the workspace has a simple
* toolbox instead of a category toolbox. To get the width and height of a
* simple toolbox @see {@link getFlyoutMetrics}.
* @return {!Blockly.MetricsManager.ToolboxMetrics} The object with the width,
* height and position of the toolbox.
* @public
*/
Blockly.MetricsManager.prototype.getToolboxMetrics = function() {
var toolboxDimensions = this.getDimensionsPx_(this.workspace_.getToolbox());
return {
width: toolboxDimensions.width,
height: toolboxDimensions.height,
position: this.workspace_.toolboxPosition
};
};
/**
* Gets the width and height of the workspace's parent svg element in pixel
* coordinates. This area includes the toolbox and the visible workspace area.
* @return {!Blockly.utils.Size} The width and height of the workspace's parent
* svg element.
* @public
*/
Blockly.MetricsManager.prototype.getSvgMetrics = function() {
return this.workspace_.getCachedParentSvgSize();
};
/**
* Gets the absolute left and absolute top in pixel coordinates.
* This is where the visible workspace starts in relation to the svg container.
* @return {!Blockly.MetricsManager.AbsoluteMetrics} The absolute metrics for
* the workspace.
* @public
*/
Blockly.MetricsManager.prototype.getAbsoluteMetrics = function() {
var absoluteLeft = 0;
var toolboxMetrics = this.getToolboxMetrics();
var flyoutMetrics = this.getFlyoutMetrics(true);
var doesToolboxExist = !!this.workspace_.getToolbox();
var doesFlyoutExist = !!this.workspace_.getFlyout(true);
var toolboxPosition =
doesToolboxExist ? toolboxMetrics.position : flyoutMetrics.position;
var atLeft = toolboxPosition == Blockly.utils.toolbox.Position.LEFT;
var atTop = toolboxPosition == Blockly.utils.toolbox.Position.TOP;
if (doesToolboxExist && atLeft) {
absoluteLeft = toolboxMetrics.width;
} else if (doesFlyoutExist && atLeft) {
absoluteLeft = flyoutMetrics.width;
}
var absoluteTop = 0;
if (doesToolboxExist && atTop) {
absoluteTop = toolboxMetrics.height;
} else if (doesFlyoutExist && atTop) {
absoluteTop = flyoutMetrics.height;
}
return {
top: absoluteTop,
left: absoluteLeft,
};
};
/**
* Gets the metrics for the visible workspace in either pixel or workspace
* coordinates. The visible workspace does not include the toolbox or flyout.
* @param {boolean=} opt_getWorkspaceCoordinates True to get the view metrics in
* workspace coordinates, false to get them in pixel coordinates.
* @return {!Blockly.MetricsManager.ContainerRegion} The width, height, top and
* left of the viewport in either workspace coordinates or pixel
* coordinates.
* @public
*/
Blockly.MetricsManager.prototype.getViewMetrics = function(
opt_getWorkspaceCoordinates) {
var scale = opt_getWorkspaceCoordinates ? this.workspace_.scale : 1;
var svgMetrics = this.getSvgMetrics();
var toolboxMetrics = this.getToolboxMetrics();
var flyoutMetrics = this.getFlyoutMetrics(true);
var doesToolboxExist = !!this.workspace_.getToolbox();
var toolboxPosition =
doesToolboxExist ? toolboxMetrics.position : flyoutMetrics.position;
if (this.workspace_.getToolbox()) {
if (toolboxPosition == Blockly.utils.toolbox.Position.TOP ||
toolboxPosition == Blockly.utils.toolbox.Position.BOTTOM) {
svgMetrics.height -= toolboxMetrics.height;
} else if (toolboxPosition == Blockly.utils.toolbox.Position.LEFT ||
toolboxPosition == Blockly.utils.toolbox.Position.RIGHT) {
svgMetrics.width -= toolboxMetrics.width;
}
} else if (this.workspace_.getFlyout(true)) {
if (toolboxPosition == Blockly.utils.toolbox.Position.TOP ||
toolboxPosition == Blockly.utils.toolbox.Position.BOTTOM) {
svgMetrics.height -= flyoutMetrics.height;
} else if (toolboxPosition == Blockly.utils.toolbox.Position.LEFT ||
toolboxPosition == Blockly.utils.toolbox.Position.RIGHT) {
svgMetrics.width -= flyoutMetrics.width;
}
}
return {
height: svgMetrics.height / scale,
width: svgMetrics.width / scale,
top: -this.workspace_.scrollY / scale,
left: -this.workspace_.scrollX / scale,
};
};
/**
* Gets content metrics in either pixel or workspace coordinates.
* The content area is a rectangle around all the top bounded elements on the
* workspace (workspace comments and blocks).
* @param {boolean=} opt_getWorkspaceCoordinates True to get the content metrics
* in workspace coordinates, false to get them in pixel coordinates.
* @return {!Blockly.MetricsManager.ContainerRegion} The
* metrics for the content container.
* @public
*/
Blockly.MetricsManager.prototype.getContentMetrics = function(
opt_getWorkspaceCoordinates) {
var scale = opt_getWorkspaceCoordinates ? 1 : this.workspace_.scale;
// Block bounding box is in workspace coordinates.
var blockBox = this.workspace_.getBlocksBoundingBox();
return {
height: (blockBox.bottom - blockBox.top) * scale,
width: (blockBox.right - blockBox.left) * scale,
top: blockBox.top * scale,
left: blockBox.left * scale,
};
};
/**
* Returns whether the scroll area has fixed edges.
* @return {boolean} Whether the scroll area has fixed edges.
* @package
*/
Blockly.MetricsManager.prototype.hasFixedEdges = function() {
// This exists for optimization of bump logic.
return !this.workspace_.isMovableHorizontally() ||
!this.workspace_.isMovableVertically();
};
/**
* Computes the fixed edges of the scroll area.
* @param {!Blockly.MetricsManager.ContainerRegion=} opt_viewMetrics The view
* metrics if they have been previously computed. Passing in null may cause
* the view metrics to be computed again, if it is needed.
* @return {!Blockly.MetricsManager.FixedEdges} The fixed edges of the scroll
* area.
* @protected
*/
Blockly.MetricsManager.prototype.getComputedFixedEdges_ = function(
opt_viewMetrics) {
if (!this.hasFixedEdges()) {
// Return early if there are no edges.
return {};
}
var hScrollEnabled = this.workspace_.isMovableHorizontally();
var vScrollEnabled = this.workspace_.isMovableVertically();
var viewMetrics = opt_viewMetrics || this.getViewMetrics(false);
var edges = {};
if (!vScrollEnabled) {
edges.top = viewMetrics.top;
edges.bottom = viewMetrics.top + viewMetrics.height;
}
if (!hScrollEnabled) {
edges.left = viewMetrics.left;
edges.right = viewMetrics.left + viewMetrics.width;
}
return edges;
};
/**
* Returns the content area with added padding.
* @param {!Blockly.MetricsManager.ContainerRegion} viewMetrics The view
* metrics.
* @param {!Blockly.MetricsManager.ContainerRegion} contentMetrics The content
* metrics.
* @return {{top: number, bottom: number, left: number, right: number}} The
* padded content area.
* @protected
*/
Blockly.MetricsManager.prototype.getPaddedContent_ = function(
viewMetrics, contentMetrics) {
var contentBottom = contentMetrics.top + contentMetrics.height;
var contentRight = contentMetrics.left + contentMetrics.width;
var viewWidth = viewMetrics.width;
var viewHeight = viewMetrics.height;
var halfWidth = viewWidth / 2;
var halfHeight = viewHeight / 2;
// Add a padding around the content that is at least half a screen wide.
// Ensure padding is wide enough that blocks can scroll over entire screen.
var top =
Math.min(contentMetrics.top - halfHeight, contentBottom - viewHeight);
var left =
Math.min(contentMetrics.left - halfWidth, contentRight - viewWidth);
var bottom =
Math.max(contentBottom + halfHeight, contentMetrics.top + viewHeight);
var right =
Math.max(contentRight + halfWidth, contentMetrics.left + viewWidth);
return {top: top, bottom: bottom, left: left, right: right};
};
/**
* Returns the metrics for the scroll area of the workspace.
* @param {boolean=} opt_getWorkspaceCoordinates True to get the scroll metrics
* in workspace coordinates, false to get them in pixel coordinates.
* @param {!Blockly.MetricsManager.ContainerRegion=} opt_viewMetrics The view
* metrics if they have been previously computed. Passing in null may cause
* the view metrics to be computed again, if it is needed.
* @param {!Blockly.MetricsManager.ContainerRegion=} opt_contentMetrics The
* content metrics if they have been previously computed. Passing in null
* may cause the content metrics to be computed again, if it is needed.
* @return {!Blockly.MetricsManager.ContainerRegion} The metrics for the scroll
* container
*/
Blockly.MetricsManager.prototype.getScrollMetrics = function(
opt_getWorkspaceCoordinates, opt_viewMetrics, opt_contentMetrics) {
var scale = opt_getWorkspaceCoordinates ? this.workspace_.scale : 1;
var viewMetrics = opt_viewMetrics || this.getViewMetrics(false);
var contentMetrics = opt_contentMetrics || this.getContentMetrics();
var fixedEdges = this.getComputedFixedEdges_(viewMetrics);
// Add padding around content
var paddedContent = this.getPaddedContent_(viewMetrics, contentMetrics);
// Use combination of fixed bounds and padded content to make scroll area.
var top = fixedEdges.top !== undefined ?
fixedEdges.top : paddedContent.top;
var left = fixedEdges.left !== undefined ?
fixedEdges.left : paddedContent.left;
var bottom = fixedEdges.bottom !== undefined ?
fixedEdges.bottom : paddedContent.bottom;
var right = fixedEdges.right !== undefined ?
fixedEdges.right : paddedContent.right;
return {
top: top / scale,
left: left / scale,
width: (right - left) / scale,
height: (bottom - top) / scale,
};
};
/**
* Returns common metrics used by ui elements.
* @return {!Blockly.MetricsManager.UiMetrics} The ui metrics.
*/
Blockly.MetricsManager.prototype.getUiMetrics = function() {
return {
viewMetrics: this.getViewMetrics(),
absoluteMetrics: this.getAbsoluteMetrics(),
toolboxMetrics: this.getToolboxMetrics()
};
};
/**
* Returns an object with all the metrics required to size scrollbars for a
* top level workspace. The following properties are computed:
* Coordinate system: pixel coordinates, -left, -up, +right, +down
* .viewHeight: Height of the visible portion of the workspace.
* .viewWidth: Width of the visible portion of the workspace.
* .contentHeight: Height of the content.
* .contentWidth: Width of the content.
* .scrollHeight: Height of the scroll area.
* .scrollWidth: Width of the scroll area.
* .svgHeight: Height of the Blockly div (the view + the toolbox,
* simple or otherwise),
* .svgWidth: Width of the Blockly div (the view + the toolbox,
* simple or otherwise),
* .viewTop: Top-edge of the visible portion of the workspace, relative to
* the workspace origin.
* .viewLeft: Left-edge of the visible portion of the workspace, relative to
* the workspace origin.
* .contentTop: Top-edge of the content, relative to the workspace origin.
* .contentLeft: Left-edge of the content relative to the workspace origin.
* .scrollTop: Top-edge of the scroll area, relative to the workspace origin.
* .scrollLeft: Left-edge of the scroll area relative to the workspace origin.
* .absoluteTop: Top-edge of the visible portion of the workspace, relative
* to the blocklyDiv.
* .absoluteLeft: Left-edge of the visible portion of the workspace, relative
* to the blocklyDiv.
* .toolboxWidth: Width of the toolbox, if it exists. Otherwise zero.
* .toolboxHeight: Height of the toolbox, if it exists. Otherwise zero.
* .flyoutWidth: Width of the flyout if it is always open. Otherwise zero.
* .flyoutHeight: Height of the flyout if it is always open. Otherwise zero.
* .toolboxPosition: Top, bottom, left or right. Use TOOLBOX_AT constants to
* compare.
* @return {!Blockly.utils.Metrics} Contains size and position metrics of a top
* level workspace.
* @public
*/
Blockly.MetricsManager.prototype.getMetrics = function() {
var toolboxMetrics = this.getToolboxMetrics();
var flyoutMetrics = this.getFlyoutMetrics(true);
var svgMetrics = this.getSvgMetrics();
var absoluteMetrics = this.getAbsoluteMetrics();
var viewMetrics = this.getViewMetrics();
var contentMetrics = this.getContentMetrics();
var scrollMetrics = this.getScrollMetrics(false, viewMetrics, contentMetrics);
return {
contentHeight: contentMetrics.height,
contentWidth: contentMetrics.width,
contentTop: contentMetrics.top,
contentLeft: contentMetrics.left,
scrollHeight: scrollMetrics.height,
scrollWidth: scrollMetrics.width,
scrollTop: scrollMetrics.top,
scrollLeft: scrollMetrics.left,
viewHeight: viewMetrics.height,
viewWidth: viewMetrics.width,
viewTop: viewMetrics.top,
viewLeft: viewMetrics.left,
absoluteTop: absoluteMetrics.top,
absoluteLeft: absoluteMetrics.left,
svgHeight: svgMetrics.height,
svgWidth: svgMetrics.width,
toolboxWidth: toolboxMetrics.width,
toolboxHeight: toolboxMetrics.height,
toolboxPosition: toolboxMetrics.position,
flyoutWidth: flyoutMetrics.width,
flyoutHeight: flyoutMetrics.height
};
};
Blockly.registry.register(
Blockly.registry.Type.METRICS_MANAGER, Blockly.registry.DEFAULT,
Blockly.MetricsManager);
/**
* Calculates metrics for a flyout's workspace.
* The metrics are mainly used to size scrollbars for the flyout.
* @param {!Blockly.WorkspaceSvg} workspace The flyout's workspace.
* @param {!Blockly.IFlyout} flyout The flyout.
* @extends {Blockly.MetricsManager}
* @constructor
*/
Blockly.FlyoutMetricsManager = function(workspace, flyout) {
/**
* The flyout that owns the workspace to calculate metrics for.
* @type {!Blockly.IFlyout}
* @protected
*/
this.flyout_ = flyout;
Blockly.FlyoutMetricsManager.superClass_.constructor.call(this, workspace);
};
Blockly.utils.object.inherits(
Blockly.FlyoutMetricsManager, Blockly.MetricsManager);
/**
* Gets the bounding box of the blocks on the flyout's workspace.
* This is in workspace coordinates.
* @returns {!SVGRect|{height: number, y: number, width: number, x: number}} The
* bounding box of the blocks on the workspace.
* @private
*/
Blockly.FlyoutMetricsManager.prototype.getBoundingBox_ = function() {
try {
var blockBoundingBox = this.workspace_.getCanvas().getBBox();
} catch (e) {
// Firefox has trouble with hidden elements (Bug 528969).
// 2021 Update: It looks like this was fixed around Firefox 77 released in
// 2020.
var blockBoundingBox = {height: 0, y: 0, width: 0, x: 0};
}
return blockBoundingBox;
};
/**
* @override
*/
Blockly.FlyoutMetricsManager.prototype.getContentMetrics = function(
opt_getWorkspaceCoordinates) {
// The bounding box is in workspace coordinates.
var blockBoundingBox = this.getBoundingBox_();
var scale = opt_getWorkspaceCoordinates ? 1 : this.workspace_.scale;
return {
height: blockBoundingBox.height * scale,
width: blockBoundingBox.width * scale,
top: blockBoundingBox.y * scale,
left: blockBoundingBox.x * scale,
};
};
/**
* @override
*/
Blockly.FlyoutMetricsManager.prototype.getScrollMetrics = function(
opt_getWorkspaceCoordinates, opt_viewMetrics, opt_contentMetrics) {
var contentMetrics = opt_contentMetrics || this.getContentMetrics();
var margin = this.flyout_.MARGIN * this.workspace_.scale;
var scale = opt_getWorkspaceCoordinates ? this.workspace_.scale : 1;
// The left padding isn't just the margin. Some blocks are also offset by
// tabWidth so that value and statement blocks line up.
// The contentMetrics.left value is equivalent to the variable left padding.
var leftPadding = contentMetrics.left;
return {
height: (contentMetrics.height + 2 * margin) / scale,
width: (contentMetrics.width + leftPadding + margin) / scale,
top: 0,
left: 0,
};
};
/**
* @override
*/
Blockly.FlyoutMetricsManager.prototype.getViewMetrics = function(
opt_getWorkspaceCoordinates) {
var svgMetrics = this.getSvgMetrics();
var scale = opt_getWorkspaceCoordinates ? this.workspace_.scale : 1;
if (this.flyout_.horizontalLayout) {
var viewWidth = svgMetrics.width - 2 * this.flyout_.SCROLLBAR_PADDING;
var viewHeight = svgMetrics.height - this.flyout_.SCROLLBAR_PADDING;
} else {
var viewWidth = svgMetrics.width - this.flyout_.SCROLLBAR_PADDING;
var viewHeight = svgMetrics.height - 2 * this.flyout_.SCROLLBAR_PADDING;
}
return {
height: viewHeight / scale,
width: viewWidth / scale,
top: -this.workspace_.scrollY / scale,
left: -this.workspace_.scrollX / scale,
};
};
/**
* @override
*/
Blockly.FlyoutMetricsManager.prototype.getAbsoluteMetrics = function() {
var scrollbarPadding = this.flyout_.SCROLLBAR_PADDING;
if (this.flyout_.horizontalLayout) {
// The viewWidth is svgWidth - 2 * scrollbarPadding. We want to put half
// of that padding to the left of the blocks.
return {top: 0, left: scrollbarPadding};
} else {
// The viewHeight is svgHeight - 2 * scrollbarPadding. We want to put half
// of that padding to the top of the blocks.
return {top: scrollbarPadding, left: 0};
}
};

View File

@@ -15,13 +15,13 @@ goog.provide('Blockly.Mutator');
goog.require('Blockly.Bubble');
goog.require('Blockly.Events');
/** @suppress {extraRequire} */
goog.require('Blockly.Events.BlockChange');
/** @suppress {extraRequire} */
goog.require('Blockly.Events.BubbleOpen');
goog.require('Blockly.Icon');
goog.require('Blockly.navigation');
goog.require('Blockly.utils');
goog.require('Blockly.utils.dom');
goog.require('Blockly.utils.global');
goog.require('Blockly.utils.object');
goog.require('Blockly.utils.Svg');
goog.require('Blockly.utils.toolbox');
@@ -29,7 +29,12 @@ goog.require('Blockly.utils.xml');
goog.require('Blockly.WorkspaceSvg');
goog.require('Blockly.Xml');
goog.requireType('Blockly.utils.Metrics');
goog.requireType('Blockly.Block');
goog.requireType('Blockly.BlockSvg');
goog.requireType('Blockly.Connection');
goog.requireType('Blockly.Events.Abstract');
goog.requireType('Blockly.utils.Coordinate');
goog.requireType('Blockly.Workspace');
/**
@@ -177,7 +182,6 @@ Blockly.Mutator.prototype.createEditor_ = function() {
if (hasFlyout) {
workspaceOptions.languageTree =
Blockly.utils.toolbox.convertToolboxDefToJson(quarkXml);
workspaceOptions.getMetrics = this.getFlyoutMetrics_.bind(this);
}
this.workspace_ = new Blockly.WorkspaceSvg(workspaceOptions);
this.workspace_.isMutator = true;
@@ -237,8 +241,9 @@ Blockly.Mutator.prototype.resizeBubble_ = function() {
var height = workspaceSize.height + doubleBorderWidth * 3;
var flyout = this.workspace_.getFlyout();
if (flyout) {
var flyoutMetrics = flyout.getMetrics_();
height = Math.max(height, flyoutMetrics.contentHeight + 20);
var flyoutScrollMetrics = flyout.getWorkspace().getMetricsManager()
.getScrollMetrics();
height = Math.max(height, flyoutScrollMetrics.height + 20);
width += flyout.getWidth();
}
if (this.block_.RTL) {
@@ -248,7 +253,7 @@ Blockly.Mutator.prototype.resizeBubble_ = function() {
// Only resize if the size difference is significant. Eliminates shuddering.
if (Math.abs(this.workspaceWidth_ - width) > doubleBorderWidth ||
Math.abs(this.workspaceHeight_ - height) > doubleBorderWidth) {
// Record some layout information for getFlyoutMetrics_.
// Record some layout information for workspace metrics.
this.workspaceWidth_ = width;
this.workspaceHeight_ = height;
// Resize the bubble.
@@ -256,6 +261,8 @@ Blockly.Mutator.prototype.resizeBubble_ = function() {
width + doubleBorderWidth, height + doubleBorderWidth);
this.svgDialog_.setAttribute('width', this.workspaceWidth_);
this.svgDialog_.setAttribute('height', this.workspaceHeight_);
this.workspace_.setCachedParentSvgSize(
this.workspaceWidth_, this.workspaceHeight_);
}
if (this.block_.RTL) {
@@ -285,8 +292,8 @@ Blockly.Mutator.prototype.setVisible = function(visible) {
// No change.
return;
}
Blockly.Events.fire(
new Blockly.Events.BubbleOpen(this.block_, visible, 'mutator'));
Blockly.Events.fire(new (Blockly.Events.get(Blockly.Events.BUBBLE_OPEN))(
this.block_, visible, 'mutator'));
if (visible) {
// Create the bubble.
this.bubble_ = new Blockly.Bubble(
@@ -414,11 +421,6 @@ Blockly.Mutator.prototype.workspaceChanged_ = function(e) {
// Mutation may have added some elements that need initializing.
block.initSvg();
if ((/** @type {!Blockly.WorkspaceSvg} */ (Blockly.getMainWorkspace()))
.keyboardAccessibilityMode) {
Blockly.navigation.moveCursorOnBlockMutation(block);
}
if (block.rendered) {
block.render();
}
@@ -426,7 +428,7 @@ Blockly.Mutator.prototype.workspaceChanged_ = function(e) {
var newMutationDom = block.mutationToDom();
var newMutation = newMutationDom && Blockly.Xml.domToText(newMutationDom);
if (oldMutation != newMutation) {
Blockly.Events.fire(new Blockly.Events.BlockChange(
Blockly.Events.fire(new (Blockly.Events.get(Blockly.Events.BLOCK_CHANGE))(
block, 'mutation', null, oldMutation, newMutation));
// Ensure that any bump is part of this mutation's event group.
var group = Blockly.Events.getGroup();
@@ -446,39 +448,6 @@ Blockly.Mutator.prototype.workspaceChanged_ = function(e) {
}
};
/**
* Return an object with all the metrics required to size scrollbars for the
* mutator flyout. The following properties are computed:
* .viewHeight: Height of the visible rectangle,
* .viewWidth: Width of the visible rectangle,
* .absoluteTop: Top-edge of view.
* .absoluteLeft: Left-edge of view.
* @return {!Blockly.utils.Metrics} Contains size and position metrics of
* mutator dialog's workspace.
* @private
*/
Blockly.Mutator.prototype.getFlyoutMetrics_ = function() {
// The mutator workspace only uses a subset of Blockly.utils.Metrics
// properties as features such as scroll and zoom are unsupported.
var unsupported = 0;
var flyout = this.workspace_.getFlyout();
var flyoutWidth = flyout ? flyout.getWidth() : 0;
return {
contentHeight: unsupported,
contentWidth: unsupported,
contentTop: unsupported,
contentLeft: unsupported,
viewHeight: this.workspaceHeight_,
viewWidth: this.workspaceWidth_ - flyoutWidth,
viewTop: unsupported,
viewLeft: unsupported,
absoluteTop: unsupported,
absoluteLeft: this.workspace_.RTL ? 0 : flyoutWidth
};
};
/**
* Dispose of this mutator.
*/

View File

@@ -12,9 +12,12 @@
goog.provide('Blockly.Names');
/** @suppress {extraRequire} */
goog.require('Blockly.constants');
goog.require('Blockly.Msg');
goog.requireType('Blockly.VariableMap');
/**
* Class for a database of entity names (variables, functions, etc).

View File

@@ -12,14 +12,12 @@
goog.provide('Blockly.Options');
goog.require('Blockly.registry');
goog.require('Blockly.Theme');
goog.require('Blockly.Themes.Classic');
goog.require('Blockly.registry');
goog.require('Blockly.utils.IdGenerator');
goog.require('Blockly.utils.Metrics');
goog.require('Blockly.utils.toolbox');
goog.require('Blockly.utils.userAgent');
goog.require('Blockly.Xml');
goog.requireType('Blockly.WorkspaceSvg');
@@ -134,7 +132,7 @@ Blockly.Options = function(options) {
/** @type {!Blockly.Options.MoveOptions} */
this.moveOptions = Blockly.Options.parseMoveOptions_(options, hasCategories);
/** @deprecated January 2019 */
this.hasScrollbars = this.moveOptions.scrollbars;
this.hasScrollbars = !!this.moveOptions.scrollbars;
/** @type {boolean} */
this.hasTrashcan = hasTrashcan;
/** @type {number} */
@@ -205,12 +203,21 @@ Blockly.Options.GridOptions;
* Move Options.
* @typedef {{
* drag: boolean,
* scrollbars: boolean,
* scrollbars: (boolean | !Blockly.Options.ScrollbarOptions),
* wheel: boolean
* }}
*/
Blockly.Options.MoveOptions;
/**
* Scrollbar Options.
* @typedef {{
* horizontal: boolean,
* vertical: boolean
* }}
*/
Blockly.Options.ScrollbarOptions;
/**
* Zoom Options.
* @typedef {{
@@ -252,12 +259,26 @@ Blockly.Options.parseMoveOptions_ = function(options, hasCategories) {
var moveOptions = {};
if (move['scrollbars'] === undefined && options['scrollbars'] === undefined) {
moveOptions.scrollbars = hasCategories;
} else if (typeof move['scrollbars'] == 'object') {
moveOptions.scrollbars = {};
moveOptions.scrollbars.horizontal = !!move['scrollbars']['horizontal'];
moveOptions.scrollbars.vertical = !!move['scrollbars']['vertical'];
// Convert scrollbars object to boolean if they have the same value.
// This allows us to easily check for whether any scrollbars exist using
// !!moveOptions.scrollbars.
if (moveOptions.scrollbars.horizontal && moveOptions.scrollbars.vertical) {
moveOptions.scrollbars = true;
} else if (!moveOptions.scrollbars.horizontal &&
!moveOptions.scrollbars.vertical) {
moveOptions.scrollbars = false;
}
} else {
moveOptions.scrollbars = !!move['scrollbars'] || !!options['scrollbars'];
}
if (!moveOptions.scrollbars || move['wheel'] === undefined) {
// Defaults to false so that developers' settings don't appear to change.
moveOptions.wheel = false;
// Defaults to true if single-direction scroll is enabled.
moveOptions.wheel = typeof moveOptions.scrollbars == 'object';
} else {
moveOptions.wheel = !!move['wheel'];
}

137
core/plugin_manager.js Normal file
View File

@@ -0,0 +1,137 @@
/**
* @license
* Copyright 2021 Google LLC
* SPDX-License-Identifier: Apache-2.0
*/
/**
* @fileoverview Manager for all items registered with the workspace.
* @author kozbial@google.com (Monica Kozbial)
*/
'use strict';
goog.provide('Blockly.PluginManager');
/**
* Manager for all items registered with the workspace.
* @constructor
*/
Blockly.PluginManager = function() {
/**
* A map of the plugins registered with the workspace, mapped to id.
* @type {!Object<string, !Blockly.PluginManager.PluginDatum>}
* @private
*/
this.pluginData_ = {};
/**
* A map of types to plugin ids.
* @type {!Object<string, Array<string>>}
* @private
*/
this.typeToPluginIds_ = {};
};
/**
* An object storing plugin information.
* @typedef {{
* id: string,
* plugin: !Blockly.IPlugin,
* types: !Array<string|!Blockly.PluginManager.Type<Blockly.IPlugin>>,
* weight: number
* }}
*/
Blockly.PluginManager.PluginDatum;
/**
* Adds a plugin.
* @param {!Blockly.PluginManager.PluginDatum} pluginDataObject The plugin.
* @template T
*/
Blockly.PluginManager.prototype.addPlugin = function(pluginDataObject) {
this.pluginData_[pluginDataObject.id] = pluginDataObject;
for (var i = 0, type; (type = pluginDataObject.types[i]); i++) {
var typeKey = String(type).toLowerCase();
if (this.typeToPluginIds_[typeKey] === undefined) {
this.typeToPluginIds_[typeKey] = [pluginDataObject.id];
} else {
this.typeToPluginIds_[typeKey].push(pluginDataObject.id);
}
}
};
/**
* Gets the plugin with the given id and the given type.
* @param {string} id The id of the plugin to get.
* @return {!Blockly.IPlugin|undefined} The plugin with the given name
* or undefined if not found.
*/
Blockly.PluginManager.prototype.getPlugin = function(id) {
return this.pluginData_[id] && this.pluginData_[id].plugin;
};
/**
* Gets all the plugins of the specified type.
* @param {!Blockly.PluginManager.Type<T>} type The type of the plugin.
* @param {boolean} sorted Whether to return list ordered by weights.
* @return {!Array<T>} The plugins that match the
* specified type.
* @template T
*/
Blockly.PluginManager.prototype.getPlugins = function(type, sorted) {
var typeKey = String(type).toLowerCase();
var pluginIds = this.typeToPluginIds_[typeKey];
if (!pluginIds) {
return [];
}
var plugins = [];
if (sorted) {
var pluginDataList = [];
var pluginData = this.pluginData_;
pluginIds.forEach(function(id) {
pluginDataList.push(pluginData[id]);
});
pluginDataList.sort(function(a, b) {
return a.weight - b.weight;
});
pluginDataList.forEach(function(pluginDatum) {
plugins.push(pluginDatum.plugin);
});
} else {
var pluginData = this.pluginData_;
pluginIds.forEach(function(id) {
plugins.push(pluginData[id].plugin);
});
}
return plugins;
};
/**
* A name with the type of the element stored in the generic.
* @param {string} name The name of the plugin type.
* @constructor
* @template T
*/
Blockly.PluginManager.Type = function(name) {
/**
* @type {string}
* @private
*/
this.name_ = name;
};
/**
* Returns the name of the type.
* @return {string} The name.
* @override
*/
Blockly.PluginManager.Type.prototype.toString = function() {
return this.name_;
};
/** @type {!Blockly.PluginManager.Type<!Blockly.IPositionable>} */
Blockly.PluginManager.Type.POSITIONABLE =
new Blockly.PluginManager.Type('positionable');

View File

@@ -17,8 +17,10 @@
goog.provide('Blockly.Procedures');
goog.require('Blockly.Blocks');
/** @suppress {extraRequire} */
goog.require('Blockly.constants');
goog.require('Blockly.Events');
/** @suppress {extraRequire} */
goog.require('Blockly.Events.BlockChange');
goog.require('Blockly.Field');
goog.require('Blockly.Msg');
@@ -27,6 +29,10 @@ goog.require('Blockly.utils.xml');
goog.require('Blockly.Workspace');
goog.require('Blockly.Xml');
goog.requireType('Blockly.Block');
goog.requireType('Blockly.Events.Abstract');
goog.requireType('Blockly.WorkspaceSvg');
/**
* Constant to separate procedure names from variables and generated functions
@@ -374,7 +380,7 @@ Blockly.Procedures.mutateCallers = function(defBlock) {
// undo action since it is deterministically tied to the procedure's
// definition mutation.
Blockly.Events.recordUndo = false;
Blockly.Events.fire(new Blockly.Events.BlockChange(
Blockly.Events.fire(new (Blockly.Events.get(Blockly.Events.BLOCK_CHANGE))(
caller, 'mutation', null, oldMutation, newMutation));
Blockly.Events.recordUndo = oldRecordUndo;
}

View File

@@ -14,12 +14,16 @@
goog.provide('Blockly.registry');
goog.requireType('Blockly.blockRendering.Renderer');
goog.requireType('Blockly.Cursor');
goog.requireType('Blockly.Events.Abstract');
goog.requireType('Blockly.Field');
goog.requireType('Blockly.IConnectionChecker');
goog.requireType('Blockly.IFlyout');
goog.requireType('Blockly.IMetricsManager');
goog.requireType('Blockly.IToolbox');
goog.requireType('Blockly.Options');
goog.requireType('Blockly.Theme');
goog.requireType('Blockly.ToolboxItem');
/**
@@ -64,6 +68,9 @@ Blockly.registry.Type.prototype.toString = function() {
Blockly.registry.Type.CONNECTION_CHECKER =
new Blockly.registry.Type('connectionChecker');
/** @type {!Blockly.registry.Type<Blockly.Cursor>} */
Blockly.registry.Type.CURSOR = new Blockly.registry.Type('cursor');
/** @type {!Blockly.registry.Type<Blockly.Events.Abstract>} */
Blockly.registry.Type.EVENT = new Blockly.registry.Type('event');
@@ -90,6 +97,10 @@ Blockly.registry.Type.FLYOUTS_VERTICAL_TOOLBOX =
Blockly.registry.Type.FLYOUTS_HORIZONTAL_TOOLBOX =
new Blockly.registry.Type('flyoutsHorizontalToolbox');
/** @type {!Blockly.registry.Type<Blockly.IMetricsManager>} */
Blockly.registry.Type.METRICS_MANAGER =
new Blockly.registry.Type('metricsManager');
/**
* Registers a class based on a type and name.
* @param {string|!Blockly.registry.Type<T>} type The type of the plugin.
@@ -97,22 +108,27 @@ Blockly.registry.Type.FLYOUTS_HORIZONTAL_TOOLBOX =
* @param {string} name The plugin's name. (Ex. field_angle, geras)
* @param {?function(new:T, ...?)|Object} registryItem The class or object to
* register.
* @param {boolean=} opt_allowOverrides True to prevent an error when overriding an
* already registered item.
* @param {boolean=} opt_allowOverrides True to prevent an error when overriding
* an already registered item.
* @throws {Error} if the type or name is empty, a name with the given type has
* already been registered, or if the given class or object is not valid for it's type.
* already been registered, or if the given class or object is not valid for
* it's type.
* @template T
*/
Blockly.registry.register = function(type, name, registryItem, opt_allowOverrides) {
if ((!(type instanceof Blockly.registry.Type) && typeof type != 'string') || String(type).trim() == '') {
throw Error('Invalid type "' + type + '". The type must be a' +
' non-empty string or a Blockly.registry.Type.');
Blockly.registry.register = function(
type, name, registryItem, opt_allowOverrides) {
if ((!(type instanceof Blockly.registry.Type) && typeof type != 'string') ||
String(type).trim() == '') {
throw Error(
'Invalid type "' + type + '". The type must be a' +
' non-empty string or a Blockly.registry.Type.');
}
type = String(type).toLowerCase();
if ((typeof name != 'string') || (name.trim() == '')) {
throw Error('Invalid name "' + name + '". The name must be a' +
' non-empty string.');
throw Error(
'Invalid name "' + name + '". The name must be a' +
' non-empty string.');
}
name = name.toLowerCase();
if (!registryItem) {
@@ -129,7 +145,8 @@ Blockly.registry.register = function(type, name, registryItem, opt_allowOverride
// Don't throw an error if opt_allowOverrides is true.
if (!opt_allowOverrides && typeRegistry[name]) {
throw Error('Name "' + name + '" with type "' + type + '" already registered.');
throw Error(
'Name "' + name + '" with type "' + type + '" already registered.');
}
typeRegistry[name] = registryItem;
};
@@ -163,12 +180,9 @@ Blockly.registry.unregister = function(type, name) {
type = String(type).toLowerCase();
name = name.toLowerCase();
var typeRegistry = Blockly.registry.typeMap_[type];
if (!typeRegistry) {
console.warn('No type "' + type + '" found');
return;
}
if (!typeRegistry[name]) {
console.warn('No name "' + name + '" with type "' + type + '" found');
if (!typeRegistry || !typeRegistry[name]) {
console.warn('Unable to unregister [' + name + '][' + type + '] from the ' +
'registry.');
return;
}
delete Blockly.registry.typeMap_[type][name];
@@ -180,20 +194,24 @@ Blockly.registry.unregister = function(type, name) {
* @param {string|!Blockly.registry.Type<T>} type The type of the plugin.
* (e.g. Field, Renderer)
* @param {string} name The plugin's name. (Ex. field_angle, geras)
* @param {boolean=} opt_throwIfMissing Whether or not to throw an error if we
* are unable to find the plugin.
* @return {?function(new:T, ...?)|Object} The class or object with the given
* name and type or null if none exists.
* @template T
*/
Blockly.registry.getItem_ = function(type, name) {
Blockly.registry.getItem_ = function(type, name, opt_throwIfMissing) {
type = String(type).toLowerCase();
name = name.toLowerCase();
var typeRegistry = Blockly.registry.typeMap_[type];
if (!typeRegistry) {
console.warn('No type "' + type + '" found');
return null;
}
if (!typeRegistry[name]) {
console.warn('No name "' + name + '" with type "' + type + '" found');
if (!typeRegistry || !typeRegistry[name]) {
var msg = 'Unable to find [' + name + '][' + type + '] in the registry.';
if (opt_throwIfMissing) {
throw new Error(msg + ' You must require or register a ' + type +
' plugin.');
} else {
console.warn(msg);
}
return null;
}
return typeRegistry[name];
@@ -224,12 +242,15 @@ Blockly.registry.hasItem = function(type, name) {
* @param {string|!Blockly.registry.Type<T>} type The type of the plugin.
* (e.g. Field, Renderer)
* @param {string} name The plugin's name. (Ex. field_angle, geras)
* @param {boolean=} opt_throwIfMissing Whether or not to throw an error if we
* are unable to find the plugin.
* @return {?function(new:T, ...?)} The class with the given name and type or
* null if none exists.
* @template T
*/
Blockly.registry.getClass = function(type, name) {
return /** @type {?function(new:T, ...?)} */ (Blockly.registry.getItem_(type, name));
Blockly.registry.getClass = function(type, name, opt_throwIfMissing) {
return /** @type {?function(new:T, ...?)} */ (
Blockly.registry.getItem_(type, name, opt_throwIfMissing));
};
/**
@@ -237,11 +258,14 @@ Blockly.registry.getClass = function(type, name) {
* @param {string|!Blockly.registry.Type<T>} type The type of the plugin.
* (e.g. Category)
* @param {string} name The plugin's name. (Ex. logic_category)
* @param {boolean=} opt_throwIfMissing Whether or not to throw an error if we
* are unable to find the object.
* @returns {T} The object with the given name and type or null if none exists.
* @template T
*/
Blockly.registry.getObject = function(type, name) {
return /** @type {T} */ (Blockly.registry.getItem_(type, name));
Blockly.registry.getObject = function(type, name, opt_throwIfMissing) {
return /** @type {T} */ (
Blockly.registry.getItem_(type, name, opt_throwIfMissing));
};
/**
@@ -250,10 +274,13 @@ Blockly.registry.getObject = function(type, name) {
* @param {!Blockly.registry.Type<T>} type The type of the plugin.
* @param {!Blockly.Options} options The option object to check for the given
* plugin.
* @param {boolean=} opt_throwIfMissing Whether or not to throw an error if we
* are unable to find the plugin.
* @return {?function(new:T, ...?)} The class for the plugin.
* @template T
*/
Blockly.registry.getClassFromOptions = function(type, options) {
Blockly.registry.getClassFromOptions = function(type, options,
opt_throwIfMissing) {
var typeName = type.toString();
var plugin = options.plugins[typeName] || Blockly.registry.DEFAULT;
@@ -261,5 +288,5 @@ Blockly.registry.getClassFromOptions = function(type, options) {
if (typeof plugin == 'function') {
return plugin;
}
return Blockly.registry.getClass(type, plugin);
return Blockly.registry.getClass(type, plugin, opt_throwIfMissing);
};

View File

@@ -13,8 +13,9 @@
goog.provide('Blockly.RenderedConnection');
goog.require('Blockly.Connection');
goog.require('Blockly.connectionTypes');
/** @suppress {extraRequire} */
goog.require('Blockly.constants');
goog.require('Blockly.Events');
goog.require('Blockly.utils');
goog.require('Blockly.utils.Coordinate');
goog.require('Blockly.utils.deprecation');
@@ -22,6 +23,10 @@ goog.require('Blockly.utils.dom');
goog.require('Blockly.utils.object');
goog.require('Blockly.utils.Svg');
goog.requireType('Blockly.Block');
goog.requireType('Blockly.BlockSvg');
goog.requireType('Blockly.ConnectionDB');
/**
* Class for a connection between blocks that may be rendered on screen.
@@ -284,7 +289,8 @@ Blockly.RenderedConnection.prototype.highlight = function() {
var sourceBlockSvg = /** @type {!Blockly.BlockSvg} */ (this.sourceBlock_);
var renderConstants = sourceBlockSvg.workspace.getRenderer().getConstants();
var shape = renderConstants.shapeFor(this);
if (this.type == Blockly.INPUT_VALUE || this.type == Blockly.OUTPUT_VALUE) {
if (this.type == Blockly.connectionTypes.INPUT_VALUE ||
this.type == Blockly.connectionTypes.OUTPUT_VALUE) {
// Vertical line, puzzle tab, vertical line.
var yLen = renderConstants.TAB_OFFSET_FROM_TOP;
steps = Blockly.utils.svgPaths.moveBy(0, -yLen) +
@@ -389,7 +395,8 @@ Blockly.RenderedConnection.prototype.startTrackingAll = function() {
// of lower blocks. Also, since rendering a block renders all its parents,
// we only need to render the leaf nodes.
var renderList = [];
if (this.type != Blockly.INPUT_VALUE && this.type != Blockly.NEXT_STATEMENT) {
if (this.type != Blockly.connectionTypes.INPUT_VALUE &&
this.type != Blockly.connectionTypes.NEXT_STATEMENT) {
// Only spider down.
return renderList;
}
@@ -529,8 +536,8 @@ Blockly.RenderedConnection.prototype.connect_ = function(childConnection) {
childBlock.updateDisabled();
}
if (parentRendered && childRendered) {
if (parentConnection.type == Blockly.NEXT_STATEMENT ||
parentConnection.type == Blockly.PREVIOUS_STATEMENT) {
if (parentConnection.type == Blockly.connectionTypes.NEXT_STATEMENT ||
parentConnection.type == Blockly.connectionTypes.PREVIOUS_STATEMENT) {
// Child block may need to square off its corners if it is in a stack.
// Rendering a child will render its parent.
childBlock.render();

View File

@@ -17,7 +17,9 @@
goog.provide('Blockly.blockRendering');
goog.require('Blockly.registry');
goog.require('Blockly.utils.object');
goog.requireType('Blockly.blockRendering.Renderer');
goog.requireType('Blockly.Theme');
/**

View File

@@ -12,6 +12,8 @@
goog.provide('Blockly.blockRendering.ConstantProvider');
goog.require('Blockly.connectionTypes');
/** @suppress {extraRequire} */
goog.require('Blockly.constants');
goog.require('Blockly.utils');
goog.require('Blockly.utils.colour');
@@ -21,6 +23,8 @@ goog.require('Blockly.utils.svgPaths');
goog.require('Blockly.utils.userAgent');
goog.requireType('Blockly.blockRendering.Debug');
goog.requireType('Blockly.RenderedConnection');
goog.requireType('Blockly.Theme');
/**
@@ -993,11 +997,11 @@ Blockly.blockRendering.ConstantProvider.prototype.makeOutsideCorners = function(
Blockly.blockRendering.ConstantProvider.prototype.shapeFor = function(
connection) {
switch (connection.type) {
case Blockly.INPUT_VALUE:
case Blockly.OUTPUT_VALUE:
case Blockly.connectionTypes.INPUT_VALUE:
case Blockly.connectionTypes.OUTPUT_VALUE:
return this.PUZZLE_TAB;
case Blockly.PREVIOUS_STATEMENT:
case Blockly.NEXT_STATEMENT:
case Blockly.connectionTypes.PREVIOUS_STATEMENT:
case Blockly.connectionTypes.NEXT_STATEMENT:
return this.NOTCH;
default:
throw Error('Unknown connection type');

View File

@@ -12,18 +12,21 @@
goog.provide('Blockly.blockRendering.Debug');
goog.require('Blockly.blockRendering.BottomRow');
goog.require('Blockly.blockRendering.InputRow');
goog.require('Blockly.blockRendering.Measurable');
goog.require('Blockly.blockRendering.RenderInfo');
goog.require('Blockly.blockRendering.Row');
goog.require('Blockly.blockRendering.SpacerRow');
goog.require('Blockly.blockRendering.TopRow');
goog.require('Blockly.blockRendering.Types');
goog.require('Blockly.connectionTypes');
/** @suppress {extraRequire} */
goog.require('Blockly.constants');
goog.require('Blockly.utils.dom');
goog.require('Blockly.utils.Svg');
goog.requireType('Blockly.blockRendering.ConstantProvider');
goog.requireType('Blockly.blockRendering.InRowSpacer');
goog.requireType('Blockly.BlockSvg');
goog.requireType('Blockly.RenderedConnection');
/**
* An object that renders rectangles and dots for debugging rendering code.
@@ -223,19 +226,19 @@ Blockly.blockRendering.Debug.prototype.drawConnection = function(conn) {
var colour;
var size;
var fill;
if (conn.type == Blockly.INPUT_VALUE) {
if (conn.type == Blockly.connectionTypes.INPUT_VALUE) {
size = 4;
colour = 'magenta';
fill = 'none';
} else if (conn.type == Blockly.OUTPUT_VALUE) {
} else if (conn.type == Blockly.connectionTypes.OUTPUT_VALUE) {
size = 2;
colour = 'magenta';
fill = colour;
} else if (conn.type == Blockly.NEXT_STATEMENT) {
} else if (conn.type == Blockly.connectionTypes.NEXT_STATEMENT) {
size = 4;
colour = 'goldenrod';
fill = 'none';
} else if (conn.type == Blockly.PREVIOUS_STATEMENT) {
} else if (conn.type == Blockly.connectionTypes.PREVIOUS_STATEMENT) {
size = 2;
colour = 'goldenrod';
fill = colour;

View File

@@ -12,16 +12,17 @@
goog.provide('Blockly.blockRendering.Drawer');
goog.require('Blockly.blockRendering.BottomRow');
goog.require('Blockly.blockRendering.InputRow');
goog.require('Blockly.blockRendering.Measurable');
goog.require('Blockly.blockRendering.RenderInfo');
goog.require('Blockly.blockRendering.Row');
goog.require('Blockly.blockRendering.SpacerRow');
goog.require('Blockly.blockRendering.TopRow');
goog.require('Blockly.blockRendering.Types');
goog.require('Blockly.utils.svgPaths');
goog.requireType('Blockly.blockRendering.ConstantProvider');
goog.requireType('Blockly.blockRendering.Field');
goog.requireType('Blockly.blockRendering.Icon');
goog.requireType('Blockly.blockRendering.InlineInput');
goog.requireType('Blockly.BlockSvg');
/**
* An object that draws a block based on the given rendering information.

View File

@@ -14,6 +14,7 @@
goog.provide('Blockly.blockRendering.IPathObject');
goog.requireType('Blockly.Block');
goog.requireType('Blockly.blockRendering.ConstantProvider');
goog.requireType('Blockly.Theme');

View File

@@ -16,8 +16,8 @@ goog.require('Blockly.blockRendering.BottomRow');
goog.require('Blockly.blockRendering.ExternalValueInput');
goog.require('Blockly.blockRendering.Hat');
goog.require('Blockly.blockRendering.InlineInput');
goog.require('Blockly.blockRendering.InRowSpacer');
goog.require('Blockly.blockRendering.InputRow');
goog.require('Blockly.blockRendering.InRowSpacer');
goog.require('Blockly.blockRendering.Measurable');
goog.require('Blockly.blockRendering.NextConnection');
goog.require('Blockly.blockRendering.OutputConnection');
@@ -25,11 +25,20 @@ goog.require('Blockly.blockRendering.PreviousConnection');
goog.require('Blockly.blockRendering.RoundCorner');
goog.require('Blockly.blockRendering.Row');
goog.require('Blockly.blockRendering.SpacerRow');
goog.require('Blockly.blockRendering.StatementInput');
goog.require('Blockly.blockRendering.SquareCorner');
goog.require('Blockly.blockRendering.StatementInput');
goog.require('Blockly.blockRendering.TopRow');
goog.require('Blockly.blockRendering.Types');
/** @suppress {extraRequire} */
goog.require('Blockly.constants');
goog.require('Blockly.inputTypes');
goog.requireType('Blockly.blockRendering.ConstantProvider');
goog.requireType('Blockly.blockRendering.Icon');
goog.requireType('Blockly.blockRendering.Renderer');
goog.requireType('Blockly.BlockSvg');
goog.requireType('Blockly.Input');
goog.requireType('Blockly.RenderedConnection');
/**
@@ -279,7 +288,7 @@ Blockly.blockRendering.RenderInfo.prototype.populateTopRow_ = function() {
}
var precedesStatement = this.block_.inputList.length &&
this.block_.inputList[0].type == Blockly.NEXT_STATEMENT;
this.block_.inputList[0].type == Blockly.inputTypes.STATEMENT;
// This is the minimum height for the row. If one of its elements has a
// greater height it will be overwritten in the compute pass.
@@ -308,10 +317,9 @@ Blockly.blockRendering.RenderInfo.prototype.populateTopRow_ = function() {
Blockly.blockRendering.RenderInfo.prototype.populateBottomRow_ = function() {
this.bottomRow.hasNextConnection = !!this.block_.nextConnection;
var followsStatement =
this.block_.inputList.length &&
this.block_.inputList[this.block_.inputList.length - 1]
.type == Blockly.NEXT_STATEMENT;
var followsStatement = this.block_.inputList.length &&
this.block_.inputList[this.block_.inputList.length - 1].type ==
Blockly.inputTypes.STATEMENT;
// This is the minimum height for the row. If one of its elements has a
// greater height it will be overwritten in the compute pass.
@@ -360,19 +368,19 @@ Blockly.blockRendering.RenderInfo.prototype.populateBottomRow_ = function() {
*/
Blockly.blockRendering.RenderInfo.prototype.addInput_ = function(input, activeRow) {
// Non-dummy inputs have visual representations onscreen.
if (this.isInline && input.type == Blockly.INPUT_VALUE) {
if (this.isInline && input.type == Blockly.inputTypes.VALUE) {
activeRow.elements.push(
new Blockly.blockRendering.InlineInput(this.constants_, input));
activeRow.hasInlineInput = true;
} else if (input.type == Blockly.NEXT_STATEMENT) {
} else if (input.type == Blockly.inputTypes.STATEMENT) {
activeRow.elements.push(
new Blockly.blockRendering.StatementInput(this.constants_, input));
activeRow.hasStatement = true;
} else if (input.type == Blockly.INPUT_VALUE) {
} else if (input.type == Blockly.inputTypes.VALUE) {
activeRow.elements.push(
new Blockly.blockRendering.ExternalValueInput(this.constants_, input));
activeRow.hasExternalInput = true;
} else if (input.type == Blockly.DUMMY_INPUT) {
} else if (input.type == Blockly.inputTypes.DUMMY) {
// Dummy inputs have no visual representation, but the information is still
// important.
activeRow.minHeight = Math.max(activeRow.minHeight,
@@ -400,12 +408,13 @@ Blockly.blockRendering.RenderInfo.prototype.shouldStartNewRow_ = function(input,
return false;
}
// A statement input or an input following one always gets a new row.
if (input.type == Blockly.NEXT_STATEMENT ||
lastInput.type == Blockly.NEXT_STATEMENT) {
if (input.type == Blockly.inputTypes.STATEMENT ||
lastInput.type == Blockly.inputTypes.STATEMENT) {
return true;
}
// Value and dummy inputs get new row if inputs are not inlined.
if (input.type == Blockly.INPUT_VALUE || input.type == Blockly.DUMMY_INPUT) {
if (input.type == Blockly.inputTypes.VALUE ||
input.type == Blockly.inputTypes.DUMMY) {
return !this.isInline;
}
return false;
@@ -584,14 +593,14 @@ Blockly.blockRendering.RenderInfo.prototype.addAlignmentPadding_ = function(row,
}
// Decide where the extra padding goes.
if (row.align == Blockly.ALIGN_LEFT) {
if (row.align == Blockly.constants.ALIGN.LEFT) {
// Add padding to the end of the row.
lastSpacer.width += missingSpace;
} else if (row.align == Blockly.ALIGN_CENTRE) {
} else if (row.align == Blockly.constants.ALIGN.CENTRE) {
// Split the padding between the beginning and end of the row.
firstSpacer.width += missingSpace / 2;
lastSpacer.width += missingSpace / 2;
} else if (row.align == Blockly.ALIGN_RIGHT) {
} else if (row.align == Blockly.constants.ALIGN.RIGHT) {
// Add padding at the beginning of the row.
firstSpacer.width += missingSpace;
} else {

View File

@@ -14,11 +14,24 @@
goog.provide('Blockly.blockRendering.MarkerSvg');
goog.require('Blockly.ASTNode');
goog.require('Blockly.connectionTypes');
/** @suppress {extraRequire} */
goog.require('Blockly.constants');
goog.require('Blockly.Events');
/** @suppress {extraRequire} */
goog.require('Blockly.Events.MarkerMove');
goog.require('Blockly.utils.dom');
goog.require('Blockly.utils.Svg');
goog.requireType('Blockly.blockRendering.ConstantProvider');
goog.requireType('Blockly.BlockSvg');
goog.requireType('Blockly.Connection');
goog.requireType('Blockly.Field');
goog.requireType('Blockly.IASTNodeLocationSvg');
goog.requireType('Blockly.Marker');
goog.requireType('Blockly.RenderedConnection');
goog.requireType('Blockly.WorkspaceSvg');
/**
* Class for a marker.
@@ -196,13 +209,14 @@ Blockly.blockRendering.MarkerSvg.prototype.draw = function(oldNode, curNode) {
Blockly.blockRendering.MarkerSvg.prototype.showAtLocation_ = function(curNode) {
var curNodeAsConnection =
/** @type {!Blockly.Connection} */ (curNode.getLocation());
var connectionType = curNodeAsConnection.type;
if (curNode.getType() == Blockly.ASTNode.types.BLOCK) {
this.showWithBlock_(curNode);
} else if (curNode.getType() == Blockly.ASTNode.types.OUTPUT) {
this.showWithOutput_(curNode);
} else if (curNodeAsConnection.type == Blockly.INPUT_VALUE) {
} else if (connectionType == Blockly.connectionTypes.INPUT_VALUE) {
this.showWithInput_(curNode);
} else if (curNodeAsConnection.type == Blockly.NEXT_STATEMENT) {
} else if (connectionType == Blockly.connectionTypes.NEXT_STATEMENT) {
this.showWithNext_(curNode);
} else if (curNode.getType() == Blockly.ASTNode.types.PREVIOUS) {
this.showWithPrevious_(curNode);
@@ -552,7 +566,7 @@ Blockly.blockRendering.MarkerSvg.prototype.hide = function() {
Blockly.blockRendering.MarkerSvg.prototype.fireMarkerEvent_ = function(
oldNode, curNode) {
var curBlock = curNode.getSourceBlock();
var event = new Blockly.Events.MarkerMove(
var event = new (Blockly.Events.get(Blockly.Events.MARKER_MOVE))(
curBlock, this.isCursor(), oldNode, curNode);
Blockly.Events.fire(event);
};

View File

@@ -19,6 +19,9 @@ goog.require('Blockly.Theme');
goog.require('Blockly.utils.dom');
goog.require('Blockly.utils.Svg');
goog.requireType('Blockly.Block');
goog.requireType('Blockly.Connection');
/**
* An object that handles creating and setting each of the SVG elements

Some files were not shown because too many files have changed in this diff Show More