diff --git a/blockly_uncompressed.js b/blockly_uncompressed.js
index f0a828915..687a3731f 100644
--- a/blockly_uncompressed.js
+++ b/blockly_uncompressed.js
@@ -21,17 +21,17 @@ this.BLOCKLY_DIR = (function(root) {
this.BLOCKLY_BOOT = function(root) {
// Execute after Closure has loaded.
-goog.addDependency("../../core/block.js", ['Blockly.Block'], ['Blockly.Blocks', 'Blockly.Connection', 'Blockly.Events', 'Blockly.Events.BlockChange', 'Blockly.Events.BlockCreate', 'Blockly.Events.BlockDelete', 'Blockly.Events.BlockMove', 'Blockly.Extensions', 'Blockly.Input', 'Blockly.utils', 'Blockly.utils.Coordinate', 'Blockly.utils.object', 'Blockly.fieldRegistry', 'Blockly.utils.string', 'Blockly.Workspace']);
+goog.addDependency("../../core/block.js", ['Blockly.Block'], ['Blockly.Blocks', 'Blockly.Connection', 'Blockly.Events', 'Blockly.Events.BlockChange', 'Blockly.Events.BlockCreate', 'Blockly.Events.BlockDelete', 'Blockly.Events.BlockMove', 'Blockly.Extensions', 'Blockly.fieldRegistry', 'Blockly.Input', 'Blockly.navigation', 'Blockly.utils', 'Blockly.utils.Coordinate', 'Blockly.utils.object', 'Blockly.utils.string', 'Blockly.Workspace']);
goog.addDependency("../../core/block_animations.js", ['Blockly.blockAnimations'], ['Blockly.utils.dom']);
goog.addDependency("../../core/block_drag_surface.js", ['Blockly.BlockDragSurfaceSvg'], ['Blockly.utils', 'Blockly.utils.Coordinate', 'Blockly.utils.dom']);
goog.addDependency("../../core/block_dragger.js", ['Blockly.BlockDragger'], ['Blockly.blockAnimations', 'Blockly.Events', 'Blockly.Events.BlockMove', 'Blockly.Events.Ui', 'Blockly.InsertionMarkerManager', 'Blockly.utils.Coordinate', 'Blockly.utils.dom']);
goog.addDependency("../../core/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.utils.Coordinate', 'Blockly.utils.object', 'Blockly.utils.xml']);
-goog.addDependency("../../core/block_svg.js", ['Blockly.BlockSvg'], ['Blockly.Block', 'Blockly.blockAnimations', 'Blockly.blockRendering.IPathObject', 'Blockly.ContextMenu', 'Blockly.Events', 'Blockly.Events.Ui', 'Blockly.Events.BlockMove', 'Blockly.Msg', 'Blockly.RenderedConnection', 'Blockly.TabNavigateCursor', 'Blockly.Tooltip', 'Blockly.Touch', 'Blockly.utils', 'Blockly.utils.Coordinate', 'Blockly.utils.dom', 'Blockly.utils.object', 'Blockly.utils.Rect']);
+goog.addDependency("../../core/block_svg.js", ['Blockly.BlockSvg'], ['Blockly.ASTNode', 'Blockly.Block', 'Blockly.blockAnimations', 'Blockly.blockRendering.IPathObject', 'Blockly.ContextMenu', 'Blockly.Events', 'Blockly.Events.Ui', 'Blockly.Events.BlockMove', 'Blockly.Msg', 'Blockly.navigation', 'Blockly.RenderedConnection', 'Blockly.TabNavigateCursor', 'Blockly.Tooltip', 'Blockly.Touch', 'Blockly.utils', 'Blockly.utils.Coordinate', 'Blockly.utils.dom', 'Blockly.utils.object', 'Blockly.utils.Rect']);
goog.addDependency("../../core/blockly.js", ['Blockly'], ['Blockly.constants', 'Blockly.Events', 'Blockly.Events.Ui', 'Blockly.inject', 'Blockly.navigation', 'Blockly.Procedures', 'Blockly.Tooltip', 'Blockly.Touch', 'Blockly.utils', 'Blockly.utils.colour', 'Blockly.Variables', 'Blockly.WidgetDiv', 'Blockly.WorkspaceSvg', 'Blockly.Xml']);
goog.addDependency("../../core/blocks.js", ['Blockly.Blocks'], []);
goog.addDependency("../../core/bubble.js", ['Blockly.Bubble'], ['Blockly.Scrollbar', 'Blockly.Touch', 'Blockly.utils', 'Blockly.utils.Coordinate', 'Blockly.utils.dom', 'Blockly.utils.math', 'Blockly.utils.userAgent', 'Blockly.Workspace']);
goog.addDependency("../../core/bubble_dragger.js", ['Blockly.BubbleDragger'], ['Blockly.Bubble', 'Blockly.Events', 'Blockly.Events.CommentMove', 'Blockly.utils', 'Blockly.utils.Coordinate']);
-goog.addDependency("../../core/comment.js", ['Blockly.Comment'], ['Blockly.Bubble', 'Blockly.Events', 'Blockly.Events.BlockChange', 'Blockly.Events.Ui', 'Blockly.Icon', 'Blockly.utils.dom', 'Blockly.utils.object', 'Blockly.utils.userAgent', 'Blockly.Warning']);
+goog.addDependency("../../core/comment.js", ['Blockly.Comment'], ['Blockly.Bubble', 'Blockly.Css', 'Blockly.Events', 'Blockly.Events.BlockChange', 'Blockly.Events.Ui', 'Blockly.Icon', 'Blockly.utils.dom', 'Blockly.utils.object', 'Blockly.utils.userAgent', 'Blockly.Warning']);
goog.addDependency("../../core/components/component.js", ['Blockly.Component', 'Blockly.Component.Error'], ['Blockly.utils.dom', 'Blockly.utils.IdGenerator', 'Blockly.utils.style']);
goog.addDependency("../../core/components/menu/menu.js", ['Blockly.Menu'], ['Blockly.Component', 'Blockly.utils.aria', 'Blockly.utils.dom', 'Blockly.utils.object']);
goog.addDependency("../../core/components/menu/menuitem.js", ['Blockly.MenuItem'], ['Blockly.Component', 'Blockly.utils.aria', 'Blockly.utils.dom', 'Blockly.utils.object']);
@@ -67,37 +67,37 @@ goog.addDependency("../../core/flyout_dragger.js", ['Blockly.FlyoutDragger'], ['
goog.addDependency("../../core/flyout_horizontal.js", ['Blockly.HorizontalFlyout'], ['Blockly.Block', 'Blockly.Flyout', 'Blockly.Scrollbar', 'Blockly.utils', 'Blockly.utils.object', 'Blockly.utils.Rect', 'Blockly.WidgetDiv']);
goog.addDependency("../../core/flyout_vertical.js", ['Blockly.VerticalFlyout'], ['Blockly.Block', 'Blockly.Flyout', 'Blockly.Scrollbar', 'Blockly.utils', 'Blockly.utils.object', 'Blockly.utils.Rect', 'Blockly.utils.userAgent', 'Blockly.WidgetDiv']);
goog.addDependency("../../core/generator.js", ['Blockly.Generator'], ['Blockly.Block']);
-goog.addDependency("../../core/gesture.js", ['Blockly.Gesture'], ['Blockly.blockAnimations', 'Blockly.BlockDragger', 'Blockly.BubbleDragger', 'Blockly.constants', 'Blockly.Events', 'Blockly.Events.Ui', 'Blockly.FlyoutDragger', 'Blockly.Tooltip', 'Blockly.Touch', 'Blockly.utils', 'Blockly.utils.Coordinate', 'Blockly.WorkspaceDragger']);
+goog.addDependency("../../core/gesture.js", ['Blockly.Gesture'], ['Blockly.ASTNode', 'Blockly.blockAnimations', 'Blockly.BlockDragger', 'Blockly.BubbleDragger', 'Blockly.constants', 'Blockly.Events', 'Blockly.Events.Ui', 'Blockly.FlyoutDragger', 'Blockly.navigation', 'Blockly.Tooltip', 'Blockly.Touch', 'Blockly.utils', 'Blockly.utils.Coordinate', 'Blockly.WorkspaceDragger']);
goog.addDependency("../../core/grid.js", ['Blockly.Grid'], ['Blockly.utils.dom', 'Blockly.utils.userAgent']);
goog.addDependency("../../core/icon.js", ['Blockly.Icon'], ['Blockly.utils', 'Blockly.utils.Coordinate', 'Blockly.utils.dom', 'Blockly.utils.Size']);
-goog.addDependency("../../core/inject.js", ['Blockly.inject'], ['Blockly.BlockDragSurfaceSvg', 'Blockly.Component', 'Blockly.Css', 'Blockly.DropDownDiv', 'Blockly.Events', 'Blockly.Grid', 'Blockly.Options', 'Blockly.ScrollbarPair', 'Blockly.Tooltip', 'Blockly.utils', 'Blockly.utils.dom', 'Blockly.utils.userAgent', 'Blockly.WorkspaceDragSurfaceSvg', 'Blockly.WorkspaceSvg']);
+goog.addDependency("../../core/inject.js", ['Blockly.inject'], ['Blockly.BlockDragSurfaceSvg', 'Blockly.Component', 'Blockly.Css', 'Blockly.DropDownDiv', 'Blockly.Events', 'Blockly.Grid', 'Blockly.Msg', 'Blockly.Options', 'Blockly.ScrollbarPair', 'Blockly.Tooltip', 'Blockly.user.keyMap', 'Blockly.utils', 'Blockly.utils.dom', 'Blockly.utils.userAgent', 'Blockly.WorkspaceDragSurfaceSvg', 'Blockly.WorkspaceSvg']);
goog.addDependency("../../core/input.js", ['Blockly.Input'], ['Blockly.Connection', 'Blockly.FieldLabel']);
goog.addDependency("../../core/insertion_marker_manager.js", ['Blockly.InsertionMarkerManager'], ['Blockly.blockAnimations', 'Blockly.Events']);
goog.addDependency("../../core/keyboard_nav/action.js", ['Blockly.Action'], []);
goog.addDependency("../../core/keyboard_nav/ast_node.js", ['Blockly.ASTNode'], ['Blockly.utils.Coordinate']);
-goog.addDependency("../../core/keyboard_nav/cursor.js", ['Blockly.Cursor'], []);
-goog.addDependency("../../core/keyboard_nav/cursor_svg.js", ['Blockly.CursorSvg'], ['Blockly.Cursor', 'Blockly.utils.object']);
-goog.addDependency("../../core/keyboard_nav/flyout_cursor.js", ['Blockly.FlyoutCursor'], ['Blockly.Cursor', 'Blockly.utils.object']);
+goog.addDependency("../../core/keyboard_nav/cursor.js", ['Blockly.Cursor'], ['Blockly.ASTNode', 'Blockly.navigation']);
+goog.addDependency("../../core/keyboard_nav/flyout_cursor.js", ['Blockly.FlyoutCursor'], ['Blockly.Cursor', 'Blockly.navigation', 'Blockly.utils.object']);
goog.addDependency("../../core/keyboard_nav/key_map.js", ['Blockly.user.keyMap'], ['Blockly.utils.KeyCodes', 'Blockly.utils.object']);
goog.addDependency("../../core/keyboard_nav/marker_cursor.js", ['Blockly.MarkerCursor'], ['Blockly.Cursor', 'Blockly.utils.object']);
goog.addDependency("../../core/keyboard_nav/navigation.js", ['Blockly.navigation'], ['Blockly.Action', 'Blockly.ASTNode', 'Blockly.utils.Coordinate', 'Blockly.user.keyMap']);
goog.addDependency("../../core/keyboard_nav/tab_navigate_cursor.js", ['Blockly.TabNavigateCursor'], ['Blockly.ASTNode', 'Blockly.Cursor', 'Blockly.utils.object']);
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.Ui', 'Blockly.Icon', 'Blockly.utils', 'Blockly.utils.dom', 'Blockly.utils.global', 'Blockly.utils.object', 'Blockly.utils.xml', 'Blockly.WorkspaceSvg', 'Blockly.Xml']);
+goog.addDependency("../../core/mutator.js", ['Blockly.Mutator'], ['Blockly.Bubble', 'Blockly.Events', 'Blockly.Events.BlockChange', 'Blockly.Events.Ui', 'Blockly.Icon', 'Blockly.navigation', 'Blockly.utils', 'Blockly.utils.dom', 'Blockly.utils.global', 'Blockly.utils.object', 'Blockly.utils.xml', 'Blockly.WorkspaceSvg', 'Blockly.Xml']);
goog.addDependency("../../core/names.js", ['Blockly.Names'], ['Blockly.Msg']);
-goog.addDependency("../../core/options.js", ['Blockly.Options'], ['Blockly.Theme', 'Blockly.Themes.Classic', 'Blockly.utils.userAgent', 'Blockly.Xml']);
+goog.addDependency("../../core/options.js", ['Blockly.Options'], ['Blockly.Theme', 'Blockly.Themes.Classic', 'Blockly.user.keyMap', 'Blockly.utils.userAgent', 'Blockly.Xml']);
goog.addDependency("../../core/procedures.js", ['Blockly.Procedures'], ['Blockly.Blocks', 'Blockly.constants', 'Blockly.Events', 'Blockly.Events.BlockChange', 'Blockly.Field', 'Blockly.Msg', 'Blockly.Names', 'Blockly.utils.xml', 'Blockly.Workspace', 'Blockly.Xml']);
goog.addDependency("../../core/rendered_connection.js", ['Blockly.RenderedConnection'], ['Blockly.Connection', 'Blockly.Events', 'Blockly.utils', 'Blockly.utils.Coordinate', 'Blockly.utils.dom', 'Blockly.utils.object']);
goog.addDependency("../../core/renderers/common/block_rendering.js", ['Blockly.blockRendering'], ['Blockly.utils.object']);
goog.addDependency("../../core/renderers/common/constants.js", ['Blockly.blockRendering.ConstantProvider'], ['Blockly.utils.dom', 'Blockly.utils.svgPaths']);
+goog.addDependency("../../core/renderers/common/cursor_svg.js", ['Blockly.blockRendering.CursorSvg'], ['Blockly.ASTNode']);
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']);
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/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.InlineInput', 'Blockly.blockRendering.InRowSpacer', '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.StatementInput', 'Blockly.blockRendering.SquareCorner', 'Blockly.blockRendering.TopRow', 'Blockly.blockRendering.Types']);
goog.addDependency("../../core/renderers/common/path_object.js", ['Blockly.blockRendering.PathObject'], ['Blockly.blockRendering.ConstantProvider', 'Blockly.blockRendering.IPathObject', 'Blockly.Theme', 'Blockly.utils.dom']);
-goog.addDependency("../../core/renderers/common/renderer.js", ['Blockly.blockRendering.Renderer'], ['Blockly.blockRendering.ConstantProvider', 'Blockly.blockRendering.Drawer', 'Blockly.blockRendering.IPathObject', 'Blockly.blockRendering.PathObject', 'Blockly.blockRendering.RenderInfo', 'Blockly.CursorSvg']);
+goog.addDependency("../../core/renderers/common/renderer.js", ['Blockly.blockRendering.Renderer'], ['Blockly.blockRendering.ConstantProvider', 'Blockly.blockRendering.Drawer', 'Blockly.blockRendering.IPathObject', 'Blockly.blockRendering.PathObject', 'Blockly.blockRendering.RenderInfo', 'Blockly.blockRendering.CursorSvg']);
goog.addDependency("../../core/renderers/geras/constants.js", ['Blockly.geras.ConstantProvider'], ['Blockly.blockRendering.ConstantProvider', 'Blockly.utils.object']);
-goog.addDependency("../../core/renderers/geras/drawer.js", ['Blockly.geras.Drawer'], ['Blockly.blockRendering.ConstantProvider', 'Blockly.blockRendering.Drawer', 'Blockly.geras.Highlighter', 'Blockly.geras.PathObject', 'Blockly.geras.RenderInfo', 'Blockly.utils.object', 'Blockly.utils.svgPaths']);
+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/highlight_constants.js", ['Blockly.geras.HighlightConstantProvider'], ['Blockly.blockRendering.ConstantProvider', 'Blockly.utils.svgPaths']);
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.InputRow', 'Blockly.blockRendering.Measurable', 'Blockly.blockRendering.NextConnection', 'Blockly.blockRendering.OutputConnection', 'Blockly.blockRendering.PreviousConnection', 'Blockly.blockRendering.RenderInfo', 'Blockly.blockRendering.BottomRow', 'Blockly.blockRendering.InputRow', 'Blockly.blockRendering.Measurable', 'Blockly.blockRendering.NextConnection', 'Blockly.blockRendering.OutputConnection', 'Blockly.blockRendering.PreviousConnection', 'Blockly.blockRendering.Types', 'Blockly.blockRendering.ExternalValueInput', 'Blockly.geras.InlineInput', 'Blockly.geras.StatementInput', 'Blockly.utils.object']);
@@ -117,16 +117,17 @@ goog.addDependency("../../core/renderers/minimalist/renderer.js", ['Blockly.mini
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/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.utils.dom', 'Blockly.utils.object', 'Blockly.utils.svgPaths']);
+goog.addDependency("../../core/renderers/zelos/cursor_svg.js", ['Blockly.zelos.CursorSvg'], ['Blockly.blockRendering.CursorSvg']);
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.SquareCorner', 'Blockly.blockRendering.SpacerRow', 'Blockly.blockRendering.StatementInput', 'Blockly.blockRendering.TopRow', 'Blockly.blockRendering.Types', 'Blockly.utils.object', 'Blockly.zelos.AfterStatementSpacerRow', 'Blockly.zelos.BeforeStatementSpacerRow', 'Blockly.zelos.BottomRow', 'Blockly.zelos.TopRow']);
goog.addDependency("../../core/renderers/zelos/measurables/rows.js", ['Blockly.zelos.BottomRow', 'Blockly.zelos.TopRow', 'Blockly.zelos.AfterStatementSpacerRow', 'Blockly.zelos.BeforeStatementSpacerRow'], ['Blockly.blockRendering.BottomRow', 'Blockly.blockRendering.TopRow', 'Blockly.blockRendering.SpacerRow', 'Blockly.utils.object']);
goog.addDependency("../../core/renderers/zelos/path_object.js", ['Blockly.zelos.PathObject'], ['Blockly.blockRendering.PathObject', 'Blockly.zelos.ConstantProvider', 'Blockly.utils.dom', 'Blockly.utils.object']);
-goog.addDependency("../../core/renderers/zelos/renderer.js", ['Blockly.zelos.Renderer'], ['Blockly.blockRendering', 'Blockly.blockRendering.Renderer', 'Blockly.utils.object', 'Blockly.zelos.ConstantProvider', 'Blockly.zelos.Drawer', 'Blockly.zelos.PathObject', 'Blockly.zelos.RenderInfo']);
+goog.addDependency("../../core/renderers/zelos/renderer.js", ['Blockly.zelos.Renderer'], ['Blockly.blockRendering', 'Blockly.blockRendering.Renderer', 'Blockly.utils.object', 'Blockly.zelos.ConstantProvider', 'Blockly.zelos.Drawer', 'Blockly.zelos.PathObject', 'Blockly.zelos.RenderInfo', 'Blockly.zelos.CursorSvg']);
goog.addDependency("../../core/requires.js", ['Blockly.requires'], ['Blockly', 'Blockly.Comment', 'Blockly.HorizontalFlyout', 'Blockly.VerticalFlyout', 'Blockly.FlyoutButton', 'Blockly.Generator', 'Blockly.Toolbox', 'Blockly.Trashcan', 'Blockly.VariablesDynamic', 'Blockly.ZoomControls', 'Blockly.Mutator', 'Blockly.Warning', 'Blockly.FieldAngle', 'Blockly.FieldCheckbox', 'Blockly.FieldColour', 'Blockly.FieldDropdown', 'Blockly.FieldLabelSerializable', 'Blockly.FieldImage', 'Blockly.FieldTextInput', 'Blockly.FieldMultilineInput', 'Blockly.FieldNumber', 'Blockly.FieldVariable', 'Blockly.geras.Renderer', 'Blockly.thrasos.Renderer', 'Blockly.zelos.Renderer', 'Blockly.Themes.Classic', 'Blockly.Themes.Dark', 'Blockly.Themes.Deuteranopia', 'Blockly.Themes.HighContrast', 'Blockly.Themes.Tritanopia']);
goog.addDependency("../../core/scrollbar.js", ['Blockly.Scrollbar', 'Blockly.ScrollbarPair'], ['Blockly.Touch', 'Blockly.utils', 'Blockly.utils.Coordinate', 'Blockly.utils.dom']);
goog.addDependency("../../core/theme.js", ['Blockly.Theme'], ['Blockly.utils', 'Blockly.utils.colour']);
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/dark.js", ['Blockly.Themes.Dark'], ['Blockly.Css', 'Blockly.Theme']);
goog.addDependency("../../core/theme/deuteranopia.js", ['Blockly.Themes.Deuteranopia'], ['Blockly.Theme']);
goog.addDependency("../../core/theme/highcontrast.js", ['Blockly.Themes.HighContrast'], ['Blockly.Theme']);
goog.addDependency("../../core/theme/modern.js", ['Blockly.Themes.Modern'], ['Blockly.Theme']);
@@ -167,11 +168,11 @@ goog.addDependency("../../core/workspace.js", ['Blockly.Workspace'], ['Blockly.C
goog.addDependency("../../core/workspace_audio.js", ['Blockly.WorkspaceAudio'], ['Blockly.utils', 'Blockly.utils.global', 'Blockly.utils.userAgent']);
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.dom']);
-goog.addDependency("../../core/workspace_comment_svg.js", ['Blockly.WorkspaceCommentSvg'], ['Blockly.Events', 'Blockly.Events.CommentCreate', 'Blockly.Events.CommentDelete', 'Blockly.Events.CommentMove', 'Blockly.Events.Ui', 'Blockly.utils', 'Blockly.utils.Coordinate', 'Blockly.utils.dom', 'Blockly.utils.object', 'Blockly.utils.Rect', 'Blockly.WorkspaceComment']);
+goog.addDependency("../../core/workspace_comment_svg.js", ['Blockly.WorkspaceCommentSvg'], ['Blockly.Css', 'Blockly.Events', 'Blockly.Events.CommentCreate', 'Blockly.Events.CommentDelete', 'Blockly.Events.CommentMove', 'Blockly.Events.Ui', 'Blockly.utils', 'Blockly.utils.Coordinate', 'Blockly.utils.dom', 'Blockly.utils.object', 'Blockly.utils.Rect', 'Blockly.WorkspaceComment']);
goog.addDependency("../../core/workspace_drag_surface_svg.js", ['Blockly.WorkspaceDragSurfaceSvg'], ['Blockly.utils', 'Blockly.utils.dom']);
goog.addDependency("../../core/workspace_dragger.js", ['Blockly.WorkspaceDragger'], ['Blockly.utils.Coordinate']);
goog.addDependency("../../core/workspace_events.js", ['Blockly.Events.FinishedLoading'], ['Blockly.Events', 'Blockly.Events.Ui', 'Blockly.utils.object']);
-goog.addDependency("../../core/workspace_svg.js", ['Blockly.WorkspaceSvg'], ['Blockly.BlockSvg', 'Blockly.blockRendering', 'Blockly.ConnectionDB', 'Blockly.constants', 'Blockly.Events', 'Blockly.Events.BlockCreate', 'Blockly.Gesture', 'Blockly.Grid', 'Blockly.Msg', 'Blockly.Options', 'Blockly.ThemeManager', 'Blockly.Themes.Classic', 'Blockly.TouchGesture', 'Blockly.utils', 'Blockly.utils.Coordinate', 'Blockly.utils.dom', 'Blockly.utils.object', 'Blockly.utils.Rect', 'Blockly.Workspace', 'Blockly.WorkspaceAudio', 'Blockly.WorkspaceDragSurfaceSvg', 'Blockly.Xml']);
+goog.addDependency("../../core/workspace_svg.js", ['Blockly.WorkspaceSvg'], ['Blockly.BlockSvg', 'Blockly.blockRendering', 'Blockly.ConnectionDB', 'Blockly.constants', 'Blockly.Events', 'Blockly.Events.BlockCreate', 'Blockly.Gesture', 'Blockly.Grid', 'Blockly.Msg', 'Blockly.navigation', 'Blockly.Options', 'Blockly.ThemeManager', 'Blockly.Themes.Classic', 'Blockly.TouchGesture', 'Blockly.utils', 'Blockly.utils.Coordinate', 'Blockly.utils.dom', 'Blockly.utils.object', 'Blockly.utils.Rect', 'Blockly.Workspace', 'Blockly.WorkspaceAudio', 'Blockly.WorkspaceDragSurfaceSvg', 'Blockly.Xml']);
goog.addDependency("../../core/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.utils.Coordinate', 'Blockly.utils.object', 'Blockly.utils.xml']);
goog.addDependency("../../core/xml.js", ['Blockly.Xml'], ['Blockly.Events', 'Blockly.Events.BlockCreate', 'Blockly.Events.FinishedLoading', 'Blockly.Events.VarCreate', '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.utils.dom']);
diff --git a/core/block_svg.js b/core/block_svg.js
index a30725695..e160e4bd0 100644
--- a/core/block_svg.js
+++ b/core/block_svg.js
@@ -1640,6 +1640,11 @@ Blockly.BlockSvg.prototype.render = function(opt_bubble) {
}
}
Blockly.utils.dom.stopTextWidthCache();
+
+ var cursor = this.workspace.getCursor();
+ if (this.pathObject.cursorSvg_) {
+ cursor.draw();
+ }
};
/**
diff --git a/core/keyboard_nav/cursor.js b/core/keyboard_nav/cursor.js
index 861fe04b5..a129c958e 100644
--- a/core/keyboard_nav/cursor.js
+++ b/core/keyboard_nav/cursor.js
@@ -42,7 +42,7 @@ Blockly.Cursor = function() {
/**
* The object in charge of drawing the visual representation of the current node.
- * @type {Blockly.CursorSvg}
+ * @type {Blockly.blockRendering.CursorSvg}
* @private
*/
this.drawer_ = null;
@@ -50,7 +50,7 @@ Blockly.Cursor = function() {
/**
* Sets the object in charge of drawing the cursor.
- * @param {Blockly.CursorSvg} drawer The object in charge of drawing the cursor.
+ * @param {Blockly.blockRendering.CursorSvg} drawer The object in charge of drawing the cursor.
*/
Blockly.Cursor.prototype.setDrawer = function(drawer) {
this.drawer_ = drawer;
@@ -58,7 +58,7 @@ Blockly.Cursor.prototype.setDrawer = function(drawer) {
/**
* Get the current drawer for the cursor.
- * @return {Blockly.CursorSvg} The object in charge of drawing the cursor.
+ * @return {Blockly.blockRendering.CursorSvg} The object in charge of drawing the cursor.
*/
Blockly.Cursor.prototype.getDrawer = function() {
return this.drawer_;
@@ -87,6 +87,16 @@ Blockly.Cursor.prototype.setCurNode = function(newNode) {
}
};
+/**
+ * Redraw the current cursor.
+ * @package
+ */
+Blockly.Cursor.prototype.draw = function() {
+ if (this.drawer_) {
+ this.drawer_.draw(this.curNode_, this.curNode_);
+ }
+};
+
/**
* Hide the cursor SVG.
*/
diff --git a/core/renderers/common/constants.js b/core/renderers/common/constants.js
index 92eaf8c7d..d53abadbb 100644
--- a/core/renderers/common/constants.js
+++ b/core/renderers/common/constants.js
@@ -261,6 +261,56 @@ Blockly.blockRendering.ConstantProvider = function() {
this.disabledPattern_ = null;
/**
+ * Cursor colour.
+ * @type {string}
+ * @package
+ */
+ this.CURSOR_COLOUR = '#cc0a0a';
+
+ /**
+ * Immovable marker colour.
+ * @type {string}
+ * @package
+ */
+ this.MARKER_COLOUR = '#4286f4';
+
+ /**
+ * Width of the horizontal cursor.
+ * @type {number}
+ * @package
+ */
+ this.CURSOR_WS_WIDTH = 100;
+
+ /**
+ * Height of the horizontal cursor.
+ * @type {number}
+ * @package
+ */
+ this.WS_CURSOR_HEIGHT = 5;
+
+ /**
+ * Padding around a stack.
+ * @type {number}
+ * @package
+ */
+ this.CURSOR_STACK_PADDING = 10;
+
+ /**
+ * Padding around a block.
+ * @type {number}
+ * @package
+ */
+ this.CURSOR_BLOCK_PADDING = 2;
+
+ /**
+ * Stroke of the cursor.
+ * @type {number}
+ * @package
+ */
+ this.CURSOR_STROKE_WIDTH = 4;
+
+
+ /*
* Whether text input and colour fields fill up the entire source block.
* @type {boolean}
* @package
diff --git a/core/keyboard_nav/cursor_svg.js b/core/renderers/common/cursor_svg.js
similarity index 74%
rename from core/keyboard_nav/cursor_svg.js
rename to core/renderers/common/cursor_svg.js
index 68c10e6c8..0bb0edc87 100644
--- a/core/keyboard_nav/cursor_svg.js
+++ b/core/renderers/common/cursor_svg.js
@@ -21,22 +21,23 @@
*/
'use strict';
-goog.provide('Blockly.CursorSvg');
+
+goog.provide('Blockly.blockRendering.CursorSvg');
goog.require('Blockly.ASTNode');
-goog.require('Blockly.Cursor');
-goog.require('Blockly.utils.object');
/**
* Class for a cursor.
* @param {!Blockly.WorkspaceSvg} workspace The workspace the cursor belongs to.
- * @param {boolean=} opt_marker True if the cursor is a marker. A marker is used
+ * @param {!Blockly.blockRendering.ConstantProvider} constants The constants for
+ * the renderer.
+ * @param {boolean=} opt_marker True if the cursor is a marker. A marker is used
* to save a location and is an immovable cursor. False or undefined if the
* cursor is not a marker.
* @constructor
*/
-Blockly.CursorSvg = function(workspace, opt_marker) {
+Blockly.blockRendering.CursorSvg = function(workspace, constants, opt_marker) {
/**
* The workspace the cursor belongs to.
* @type {!Blockly.WorkspaceSvg}
@@ -48,10 +49,10 @@ Blockly.CursorSvg = function(workspace, opt_marker) {
* True if the cursor should be drawn as a marker, false otherwise.
* A marker is drawn as a solid blue line, while the cursor is drawns as a
* flashing red one.
- * @type {boolean|undefined}
+ * @type {boolean}
* @private
*/
- this.isMarker_ = opt_marker;
+ this.isMarker_ = !!opt_marker;
/**
* The workspace, field, or block that the cursor SVG element should be
@@ -64,52 +65,28 @@ Blockly.CursorSvg = function(workspace, opt_marker) {
/**
* The constants necessary to draw the cursor.
* @type {Blockly.blockRendering.ConstantProvider}
- * @private
+ * @protected
*/
- this.constants_ = workspace.getRenderer().getConstants();
+ this.constants_ = constants;
+
+ /**
+ * The current SVG element for the cursor.
+ * @type {Element}
+ */
+ this.currentCursorSvg = null;
};
/**
- * Height of the horizontal cursor.
- * @type {number}
- * @const
+ * The name of the CSS class for a cursor.
+ * @const {string}
*/
-Blockly.CursorSvg.CURSOR_HEIGHT = 5;
+Blockly.blockRendering.CursorSvg.CURSOR_CLASS = 'blocklyCursor';
/**
- * Width of the horizontal cursor.
- * @type {number}
- * @const
+ * The name of the CSS class for a marker.
+ * @const {string}
*/
-Blockly.CursorSvg.CURSOR_WIDTH = 100;
-
-/**
- * The start length of the notch.
- * @type {number}
- * @const
- */
-Blockly.CursorSvg.NOTCH_START_LENGTH = 24;
-
-/**
- * Padding around the input.
- * @type {number}
- * @const
- */
-Blockly.CursorSvg.VERTICAL_PADDING = 5;
-
-/**
- * Padding around a stack.
- * @type {number}
- * @const
- */
-Blockly.CursorSvg.STACK_PADDING = 10;
-
-/**
- * Padding around a block.
- * @type {number}
- * @const
- */
-Blockly.CursorSvg.BLOCK_PADDING = 2;
+Blockly.blockRendering.CursorSvg.MARKER_CLASS = 'blocklyMarker';
/**
* What we multiply the height by to get the height of the cursor.
@@ -117,63 +94,42 @@ Blockly.CursorSvg.BLOCK_PADDING = 2;
* @type {number}
* @const
*/
-Blockly.CursorSvg.HEIGHT_MULTIPLIER = 3 / 4;
-
-/**
- * Cursor colour.
- * @type {string}
- * @const
- */
-Blockly.CursorSvg.CURSOR_COLOUR = '#cc0a0a';
-
-/**
- * Immovable marker colour.
- * @type {string}
- * @const
- */
-Blockly.CursorSvg.MARKER_COLOUR = '#4286f4';
-
-/**
- * The name of the CSS class for a cursor.
- * @const {string}
- */
-Blockly.CursorSvg.CURSOR_CLASS = 'blocklyCursor';
-
-/**
- * The name of the CSS class for a marker.
- * @const {string}
- */
-Blockly.CursorSvg.MARKER_CLASS = 'blocklyMarker';
-
-/**
- * The current SVG element for the cursor.
- * @type {Element}
- */
-Blockly.CursorSvg.prototype.currentCursorSvg = null;
+Blockly.blockRendering.CursorSvg.HEIGHT_MULTIPLIER = 3 / 4;
/**
* Return the root node of the SVG or null if none exists.
* @return {SVGElement} The root SVG node.
*/
-Blockly.CursorSvg.prototype.getSvgRoot = function() {
+Blockly.blockRendering.CursorSvg.prototype.getSvgRoot = function() {
return this.svgGroup_;
};
+/**
+ * True if the cursor should be drawn as a marker, false otherwise.
+ * A marker is drawn as a solid blue line, while the cursor is drawns as a
+ * flashing red one.
+ * @return {boolean} The root SVG node.
+ */
+Blockly.blockRendering.CursorSvg.prototype.isMarker = function() {
+ return this.isMarker_;
+};
+
/**
* Create the DOM element for the cursor.
* @return {!SVGElement} The cursor controls SVG group.
* @package
*/
-Blockly.CursorSvg.prototype.createDom = function() {
- var className = this.isMarker_ ?
- Blockly.CursorSvg.MARKER_CLASS : Blockly.CursorSvg.CURSOR_CLASS;
+Blockly.blockRendering.CursorSvg.prototype.createDom = function() {
+ var className = this.isMarker() ?
+ Blockly.blockRendering.CursorSvg.MARKER_CLASS :
+ Blockly.blockRendering.CursorSvg.CURSOR_CLASS;
this.svgGroup_ =
Blockly.utils.dom.createSvgElement('g', {
'class': className
}, null);
- this.createCursorSvg_();
+ this.createDomInternal_();
return this.svgGroup_;
};
@@ -182,9 +138,9 @@ Blockly.CursorSvg.prototype.createDom = function() {
* @param {!Blockly.WorkspaceSvg|!Blockly.Field|!Blockly.BlockSvg} newParent
* The workspace, field, or block that the cursor SVG element should be
* attached to.
- * @private
+ * @protected
*/
-Blockly.CursorSvg.prototype.setParent_ = function(newParent) {
+Blockly.blockRendering.CursorSvg.prototype.setParent_ = function(newParent) {
if (this.isMarker_) {
if (this.parent_) {
this.parent_.setMarkerSvg(null);
@@ -207,16 +163,16 @@ Blockly.CursorSvg.prototype.setParent_ = function(newParent) {
* Show the cursor as a combination of the previous connection and block,
* the output connection and block, or just the block.
* @param {Blockly.BlockSvg} block The block the cursor is currently on.
- * @private
+ * @protected
*/
-Blockly.CursorSvg.prototype.showWithBlockPrevOutput_ = function(block) {
+Blockly.blockRendering.CursorSvg.prototype.showWithBlockPrevOutput_ = function(block) {
if (!block) {
return;
}
var width = block.width;
var height = block.height;
- var cursorHeight = height * Blockly.CursorSvg.HEIGHT_MULTIPLIER;
- var cursorOffset = Blockly.CursorSvg.BLOCK_PADDING;
+ var cursorHeight = height * Blockly.blockRendering.CursorSvg.HEIGHT_MULTIPLIER;
+ var cursorOffset = this.constants_.CURSOR_BLOCK_PADDING;
if (block.previousConnection) {
this.positionPrevious_(width, cursorOffset, cursorHeight);
@@ -234,18 +190,18 @@ Blockly.CursorSvg.prototype.showWithBlockPrevOutput_ = function(block) {
* Show the visual representation of a workspace coordinate.
* This is a horizontal line.
* @param {!Blockly.ASTNode} curNode The node that we want to draw the cursor for.
- * @private
+ * @protected
*/
-Blockly.CursorSvg.prototype.showWithCoordinates_ = function(curNode) {
+Blockly.blockRendering.CursorSvg.prototype.showWithCoordinates_ = function(curNode) {
var wsCoordinate = curNode.getWsCoordinate();
var x = wsCoordinate.x;
var y = wsCoordinate.y;
if (this.workspace_.RTL) {
- x -= Blockly.CursorSvg.CURSOR_WIDTH;
+ x -= this.constants_.CURSOR_WS_WIDTH;
}
- this.positionLine_(x, y, Blockly.CursorSvg.CURSOR_WIDTH);
+ this.positionLine_(x, y, this.constants_.CURSOR_WS_WIDTH);
this.setParent_(this.workspace_);
this.showCurrent_();
};
@@ -254,9 +210,9 @@ Blockly.CursorSvg.prototype.showWithCoordinates_ = function(curNode) {
* Show the visual representation of a field.
* This is a box around the field.
* @param {!Blockly.ASTNode} curNode The node that we want to draw the cursor for.
- * @private
+ * @protected
*/
-Blockly.CursorSvg.prototype.showWithField_ = function(curNode) {
+Blockly.blockRendering.CursorSvg.prototype.showWithField_ = function(curNode) {
var field = /** @type {Blockly.Field} */ (curNode.getLocation());
var width = field.getSize().width;
var height = field.getSize().height;
@@ -270,9 +226,9 @@ Blockly.CursorSvg.prototype.showWithField_ = function(curNode) {
* Show the visual representation of an input.
* This is a puzzle piece.
* @param {!Blockly.ASTNode} curNode The node that we want to draw the cursor for.
- * @private
+ * @protected
*/
-Blockly.CursorSvg.prototype.showWithInput_ = function(curNode) {
+Blockly.blockRendering.CursorSvg.prototype.showWithInput_ = function(curNode) {
var connection = /** @type {Blockly.Connection} */
(curNode.getLocation());
var sourceBlock = /** @type {!Blockly.BlockSvg} */ (connection.getSourceBlock());
@@ -287,9 +243,9 @@ Blockly.CursorSvg.prototype.showWithInput_ = function(curNode) {
* Show the visual representation of a next connection.
* This is a horizontal line.
* @param {!Blockly.ASTNode} curNode The node that we want to draw the cursor for.
- * @private
+ * @protected
*/
-Blockly.CursorSvg.prototype.showWithNext_ = function(curNode) {
+Blockly.blockRendering.CursorSvg.prototype.showWithNext_ = function(curNode) {
var connection = curNode.getLocation();
var targetBlock = /** @type {Blockly.BlockSvg} */ (connection.getSourceBlock());
var x = 0;
@@ -307,21 +263,21 @@ Blockly.CursorSvg.prototype.showWithNext_ = function(curNode) {
* Show the visual representation of a stack.
* This is a box with extra padding around the entire stack of blocks.
* @param {!Blockly.ASTNode} curNode The node that we want to draw the cursor for.
- * @private
+ * @protected
*/
-Blockly.CursorSvg.prototype.showWithStack_ = function(curNode) {
+Blockly.blockRendering.CursorSvg.prototype.showWithStack_ = function(curNode) {
var block = /** @type {Blockly.BlockSvg} */ (curNode.getLocation());
// Gets the height and width of entire stack.
var heightWidth = block.getHeightWidth();
// Add padding so that being on a stack looks different than being on a block.
- var width = heightWidth.width + Blockly.CursorSvg.STACK_PADDING;
- var height = heightWidth.height + Blockly.CursorSvg.STACK_PADDING;
+ var width = heightWidth.width + this.constants_.CURSOR_STACK_PADDING;
+ var height = heightWidth.height + this.constants_.CURSOR_STACK_PADDING;
// Shift the rectangle slightly to upper left so padding is equal on all sides.
- var xPadding = -Blockly.CursorSvg.STACK_PADDING / 2;
- var yPadding = -Blockly.CursorSvg.STACK_PADDING / 2;
+ var xPadding = -this.constants_.CURSOR_STACK_PADDING / 2;
+ var yPadding = -this.constants_.CURSOR_STACK_PADDING / 2;
var x = xPadding;
var y = yPadding;
@@ -336,9 +292,9 @@ Blockly.CursorSvg.prototype.showWithStack_ = function(curNode) {
/**
* Show the current cursor.
- * @private
+ * @protected
*/
-Blockly.CursorSvg.prototype.showCurrent_ = function() {
+Blockly.blockRendering.CursorSvg.prototype.showCurrent_ = function() {
this.hide();
this.currentCursorSvg.style.display = '';
};
@@ -355,7 +311,8 @@ Blockly.CursorSvg.prototype.showCurrent_ = function() {
* @param {number} cursorHeight The height of the cursor.
* @private
*/
-Blockly.CursorSvg.prototype.positionBlock_ = function(width, cursorOffset, cursorHeight) {
+Blockly.blockRendering.CursorSvg.prototype.positionBlock_ = function(
+ width, cursorOffset, cursorHeight) {
var cursorPath = Blockly.utils.svgPaths.moveBy(-cursorOffset, cursorHeight) +
Blockly.utils.svgPaths.lineOnAxis('V', -cursorOffset) +
Blockly.utils.svgPaths.lineOnAxis('H', width + cursorOffset * 2) +
@@ -373,7 +330,7 @@ Blockly.CursorSvg.prototype.positionBlock_ = function(width, cursorOffset, curso
* @param {!Blockly.Connection} connection The connection to position cursor around.
* @private
*/
-Blockly.CursorSvg.prototype.positionInput_ = function(connection) {
+Blockly.blockRendering.CursorSvg.prototype.positionInput_ = function(connection) {
var x = connection.getOffsetInBlock().x;
var y = connection.getOffsetInBlock().y;
@@ -392,9 +349,9 @@ Blockly.CursorSvg.prototype.positionInput_ = function(connection) {
* @param {number} x The new x, in workspace units.
* @param {number} y The new y, in workspace units.
* @param {number} width The new width, in workspace units.
- * @private
+ * @protected
*/
-Blockly.CursorSvg.prototype.positionLine_ = function(x, y, width) {
+Blockly.blockRendering.CursorSvg.prototype.positionLine_ = function(x, y, width) {
this.cursorSvgLine_.setAttribute('x', x);
this.cursorSvgLine_.setAttribute('y', y);
this.cursorSvgLine_.setAttribute('width', width);
@@ -408,7 +365,7 @@ Blockly.CursorSvg.prototype.positionLine_ = function(x, y, width) {
* @param {number} height The height of the block.
* @private
*/
-Blockly.CursorSvg.prototype.positionOutput_ = function(width, height) {
+Blockly.blockRendering.CursorSvg.prototype.positionOutput_ = function(width, height) {
var cursorPath = Blockly.utils.svgPaths.moveBy(width, 0) +
Blockly.utils.svgPaths.lineOnAxis('h', -(width - this.constants_.PUZZLE_TAB.width)) +
Blockly.utils.svgPaths.lineOnAxis('v', this.constants_.TAB_OFFSET_FROM_TOP) +
@@ -431,7 +388,8 @@ Blockly.CursorSvg.prototype.positionOutput_ = function(width, height) {
* @param {number} cursorHeight The height of the cursor.
* @private
*/
-Blockly.CursorSvg.prototype.positionPrevious_ = function(width, cursorOffset, cursorHeight) {
+Blockly.blockRendering.CursorSvg.prototype.positionPrevious_ = function(
+ width, cursorOffset, cursorHeight) {
var cursorPath = Blockly.utils.svgPaths.moveBy(-cursorOffset, cursorHeight) +
Blockly.utils.svgPaths.lineOnAxis('V', -cursorOffset) +
Blockly.utils.svgPaths.lineOnAxis('H', this.constants_.NOTCH_OFFSET_LEFT) +
@@ -452,9 +410,9 @@ Blockly.CursorSvg.prototype.positionPrevious_ = function(width, cursorOffset, cu
* @param {number} y The new y, in workspace units.
* @param {number} width The new width, in workspace units.
* @param {number} height The new height, in workspace units.
- * @private
+ * @protected
*/
-Blockly.CursorSvg.prototype.positionRect_ = function(x, y, width, height) {
+Blockly.blockRendering.CursorSvg.prototype.positionRect_ = function(x, y, width, height) {
this.cursorSvgRect_.setAttribute('x', x);
this.cursorSvgRect_.setAttribute('y', y);
this.cursorSvgRect_.setAttribute('width', width);
@@ -467,7 +425,7 @@ Blockly.CursorSvg.prototype.positionRect_ = function(x, y, width, height) {
* @param {!SVGElement} cursor The cursor that we want to flip.
* @private
*/
-Blockly.CursorSvg.prototype.flipRtl_ = function(cursor) {
+Blockly.blockRendering.CursorSvg.prototype.flipRtl_ = function(cursor) {
cursor.setAttribute('transform', 'scale(-1 1)');
};
@@ -475,7 +433,7 @@ Blockly.CursorSvg.prototype.flipRtl_ = function(cursor) {
* Hide the cursor.
* @package
*/
-Blockly.CursorSvg.prototype.hide = function() {
+Blockly.blockRendering.CursorSvg.prototype.hide = function() {
this.cursorSvgLine_.style.display = 'none';
this.cursorSvgRect_.style.display = 'none';
this.cursorInput_.style.display = 'none';
@@ -488,12 +446,30 @@ Blockly.CursorSvg.prototype.hide = function() {
* @param {Blockly.ASTNode} curNode The node that we want to draw the cursor for.
* @package
*/
-Blockly.CursorSvg.prototype.draw = function(oldNode, curNode) {
+Blockly.blockRendering.CursorSvg.prototype.draw = function(oldNode, curNode) {
if (!curNode) {
this.hide();
return;
}
+ this.showAtLocation_(curNode);
+
+ this.fireCursorEvent_(oldNode, curNode);
+
+ // Ensures the cursor will be visible immediately after the move.
+ var animate = this.currentCursorSvg.childNodes[0];
+ if (animate !== undefined) {
+ animate.beginElement && animate.beginElement();
+ }
+};
+
+
+/**
+ * Update the cursor's visible state based on the type of curNode..
+ * @param {Blockly.ASTNode} curNode The node that we want to draw the cursor for.
+ * @protected
+ */
+Blockly.blockRendering.CursorSvg.prototype.showAtLocation_ = function(curNode) {
if (curNode.getType() == Blockly.ASTNode.types.BLOCK) {
var block = /** @type {Blockly.BlockSvg} */ (curNode.getLocation());
this.showWithBlockPrevOutput_(block);
@@ -514,14 +490,6 @@ Blockly.CursorSvg.prototype.draw = function(oldNode, curNode) {
} else if (curNode.getType() == Blockly.ASTNode.types.STACK) {
this.showWithStack_(curNode);
}
-
- this.fireCursorEvent_(oldNode, curNode);
-
- // Ensures the cursor will be visible immediately after the move.
- var animate = this.currentCursorSvg.childNodes[0];
- if (animate !== undefined) {
- animate.beginElement && animate.beginElement();
- }
};
/**
@@ -530,7 +498,7 @@ Blockly.CursorSvg.prototype.draw = function(oldNode, curNode) {
* @param {!Blockly.ASTNode} curNode The new node the cursor is currently on.
* @private
*/
-Blockly.CursorSvg.prototype.fireCursorEvent_ = function(oldNode, curNode) {
+Blockly.blockRendering.CursorSvg.prototype.fireCursorEvent_ = function(oldNode, curNode) {
var curBlock = curNode.getSourceBlock();
var eventType = this.isMarker_ ? 'markedNode' : 'cursorMove';
var event = new Blockly.Events.Ui(curBlock, eventType, oldNode, curNode);
@@ -540,12 +508,28 @@ Blockly.CursorSvg.prototype.fireCursorEvent_ = function(oldNode, curNode) {
Blockly.Events.fire(event);
};
+/**
+ * Get the properties to make a cursor blink.
+ * @return {!Object} The object holding attributes to make the cursor blink.
+ * @protected
+ */
+Blockly.blockRendering.CursorSvg.prototype.getBlinkProperties_ = function() {
+ return {
+ 'attributeType': 'XML',
+ 'attributeName': 'fill',
+ 'dur': '1s',
+ 'values': this.constants_.CURSOR_COLOUR + ';transparent;transparent;',
+ 'repeatCount': 'indefinite'
+ };
+};
+
+
/**
* Create the cursor SVG.
* @return {Element} The SVG node created.
- * @private
+ * @protected
*/
-Blockly.CursorSvg.prototype.createCursorSvg_ = function() {
+Blockly.blockRendering.CursorSvg.prototype.createDomInternal_ = function() {
/* This markup will be generated and added to the .svgGroup_:
@@ -555,22 +539,20 @@ Blockly.CursorSvg.prototype.createCursorSvg_ = function() {
*/
- var colour = this.isMarker_ ? Blockly.CursorSvg.MARKER_COLOUR :
- Blockly.CursorSvg.CURSOR_COLOUR;
+ var colour = this.isMarker_ ? this.constants_.MARKER_COLOUR :
+ this.constants_.CURSOR_COLOUR;
this.cursorSvg_ = Blockly.utils.dom.createSvgElement('g',
{
- 'width': Blockly.CursorSvg.CURSOR_WIDTH,
- 'height': Blockly.CursorSvg.CURSOR_HEIGHT
+ 'width': this.constants_.CURSOR_WS_WIDTH,
+ 'height': this.constants_.WS_CURSOR_HEIGHT
}, this.svgGroup_);
// A horizontal line used to represent a workspace coordinate or next connection.
this.cursorSvgLine_ = Blockly.utils.dom.createSvgElement('rect',
{
- 'x': 0,
- 'y': 0,
'fill': colour,
- 'width': Blockly.CursorSvg.CURSOR_WIDTH,
- 'height': Blockly.CursorSvg.CURSOR_HEIGHT,
+ 'width': this.constants_.CURSOR_WS_WIDTH,
+ 'height': this.constants_.WS_CURSOR_HEIGHT,
'style': 'display: none'
},
this.cursorSvg_);
@@ -579,8 +561,6 @@ Blockly.CursorSvg.prototype.createCursorSvg_ = function() {
this.cursorSvgRect_ = Blockly.utils.dom.createSvgElement('rect',
{
'class': 'blocklyVerticalCursor',
- 'x': 0,
- 'y': 0,
'rx': 10, 'ry': 10,
'style': 'display: none',
'stroke': colour
@@ -588,11 +568,8 @@ Blockly.CursorSvg.prototype.createCursorSvg_ = function() {
this.cursorSvg_);
// A filled in puzzle piece used to represent an input value.
- this.cursorInput_ = Blockly.utils.dom.createSvgElement(
- 'path',
+ this.cursorInput_ = Blockly.utils.dom.createSvgElement('path',
{
- 'width': Blockly.CursorSvg.CURSOR_WIDTH,
- 'height': Blockly.CursorSvg.CURSOR_HEIGHT,
'transform': '',
'style': 'display: none',
'fill': colour
@@ -601,34 +578,25 @@ Blockly.CursorSvg.prototype.createCursorSvg_ = function() {
// A path used to represent a previous connection and a block, an output
// connection and a block, or a block.
- this.cursorBlock_ = Blockly.utils.dom.createSvgElement(
- 'path',
+ this.cursorBlock_ = Blockly.utils.dom.createSvgElement('path',
{
- 'width': Blockly.CursorSvg.CURSOR_WIDTH,
- 'height': Blockly.CursorSvg.CURSOR_HEIGHT,
'transform': '',
'style': 'display: none',
'fill': 'none',
'stroke': colour,
- 'stroke-width': 4
+ 'stroke-width': this.constants_.CURSOR_STROKE_WIDTH
},
this.cursorSvg_);
// Markers and stack cursors don't blink.
if (!this.isMarker_) {
- var properties = {
- 'attributeType': 'XML',
- 'attributeName': 'fill',
- 'dur': '1s',
- 'values': Blockly.CursorSvg.CURSOR_COLOUR + ';transparent;transparent;',
- 'repeatCount': 'indefinite'
- };
- Blockly.utils.dom.createSvgElement('animate', properties,
+ var blinkProperties = this.getBlinkProperties_();
+ Blockly.utils.dom.createSvgElement('animate', this.getBlinkProperties_(),
this.cursorSvgLine_);
- Blockly.utils.dom.createSvgElement('animate', properties,
+ Blockly.utils.dom.createSvgElement('animate', blinkProperties,
this.cursorInput_);
- properties['attributeName'] = 'stroke';
- Blockly.utils.dom.createSvgElement('animate', properties,
+ blinkProperties['attributeName'] = 'stroke';
+ Blockly.utils.dom.createSvgElement('animate', blinkProperties,
this.cursorBlock_);
}
@@ -639,7 +607,7 @@ Blockly.CursorSvg.prototype.createCursorSvg_ = function() {
* Dispose of this cursor.
* @package
*/
-Blockly.CursorSvg.prototype.dispose = function() {
+Blockly.blockRendering.CursorSvg.prototype.dispose = function() {
if (this.svgGroup_) {
Blockly.utils.dom.removeNode(this.svgGroup_);
}
diff --git a/core/renderers/common/renderer.js b/core/renderers/common/renderer.js
index a25e52825..35d8bdb60 100644
--- a/core/renderers/common/renderer.js
+++ b/core/renderers/common/renderer.js
@@ -24,11 +24,11 @@
goog.provide('Blockly.blockRendering.Renderer');
goog.require('Blockly.blockRendering.ConstantProvider');
+goog.require('Blockly.blockRendering.CursorSvg');
goog.require('Blockly.blockRendering.Drawer');
goog.require('Blockly.blockRendering.IPathObject');
goog.require('Blockly.blockRendering.PathObject');
goog.require('Blockly.blockRendering.RenderInfo');
-goog.require('Blockly.CursorSvg');
goog.requireType('Blockly.blockRendering.Debug');
@@ -107,12 +107,12 @@ Blockly.blockRendering.Renderer.prototype.makeDebugger_ = function() {
* @param {boolean=} opt_marker True if the cursor is a marker. A marker is used
* to save a location and is an immovable cursor. False or undefined if the
* cursor is not a marker.
- * @return {!Blockly.CursorSvg} The cursor drawer.
+ * @return {!Blockly.blockRendering.CursorSvg} The cursor drawer.
* @package
*/
Blockly.blockRendering.Renderer.prototype.makeCursorDrawer = function(
workspace, opt_marker) {
- return new Blockly.CursorSvg(workspace, opt_marker);
+ return new Blockly.blockRendering.CursorSvg(workspace, this.getConstants(), opt_marker);
};
/**
diff --git a/core/renderers/zelos/constants.js b/core/renderers/zelos/constants.js
index f982a6307..37fe00172 100644
--- a/core/renderers/zelos/constants.js
+++ b/core/renderers/zelos/constants.js
@@ -127,6 +127,23 @@ Blockly.zelos.ConstantProvider = function() {
*/
this.DUMMY_INPUT_MIN_HEIGHT = 6 * this.GRID_UNIT;
+ /**
+ * @override
+ */
+ this.CURSOR_WS_WIDTH = 20 * this.GRID_UNIT;
+
+ /**
+ * @override
+ */
+ this.CURSOR_COLOUR = '#ffa200';
+
+ /**
+ * Radius of the cursor for input and output connections.
+ * @type {number}
+ * @package
+ */
+ this.CURSOR_RADIUS = 5;
+
/**
* @override
*/
diff --git a/core/renderers/zelos/cursor_svg.js b/core/renderers/zelos/cursor_svg.js
new file mode 100644
index 000000000..dd578bcd6
--- /dev/null
+++ b/core/renderers/zelos/cursor_svg.js
@@ -0,0 +1,152 @@
+/**
+ * @license
+ * Copyright 2019 Google LLC
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * @fileoverview Methods for graphically rendering a cursor as SVG.
+ * @author samelh@microsoft.com (Sam El-Husseini)
+ */
+'use strict';
+
+goog.provide('Blockly.zelos.CursorSvg');
+
+goog.require('Blockly.blockRendering.CursorSvg');
+
+
+/**
+ * Class for a cursor.
+ * @param {!Blockly.WorkspaceSvg} workspace The workspace the cursor belongs to.
+ * @param {!Blockly.blockRendering.ConstantProvider} constants The constants for
+ * the renderer.
+ * @param {boolean=} opt_marker True if the cursor is a marker. A marker is used
+ * to save a location and is an immovable cursor. False or undefined if the
+ * cursor is not a marker.
+ * @constructor
+ * @extends {Blockly.blockRendering.CursorSvg}
+ */
+Blockly.zelos.CursorSvg = function(workspace, constants, opt_marker) {
+ Blockly.zelos.CursorSvg.superClass_.constructor.call(
+ this, workspace, constants, opt_marker);
+};
+Blockly.utils.object.inherits(Blockly.zelos.CursorSvg,
+ Blockly.blockRendering.CursorSvg);
+
+/**
+ * @override
+ */
+Blockly.zelos.CursorSvg.prototype.showWithInput_ = function(curNode) {
+ var block = /** @type {!Blockly.BlockSvg} */ (curNode.getSourceBlock());
+ var connection = curNode.getLocation();
+ var offsetInBlock = connection.getOffsetInBlock();
+
+ var y = offsetInBlock.y + this.constants_.CURSOR_RADIUS;
+
+ this.positionCircle_(offsetInBlock.x, y);
+ this.setParent_(block);
+ this.showCurrent_();
+};
+
+/**
+ * Draw a rectangle around the block.
+ * @param {!Blockly.ASTNode} curNode The current node of the cursor.
+ */
+Blockly.zelos.CursorSvg.prototype.showWithBlock_ = function(curNode) {
+ var block = /** @type {!Blockly.BlockSvg} */ (curNode.getLocation());
+
+ // Gets the height and width of entire stack.
+ var heightWidth = block.getHeightWidth();
+
+ // Add padding so that being on a stack looks different than being on a block.
+ this.positionRect_(0, 0, heightWidth.width, heightWidth.height);
+ this.setParent_(block);
+ this.showCurrent_();
+};
+
+/**
+ * Position the circle we use for input and output connections.
+ * @param {number} x The x position of the circle.
+ * @param {number} y The y position of the circle.
+ * @private
+ */
+Blockly.zelos.CursorSvg.prototype.positionCircle_ = function(x, y) {
+ this.cursorCircle_.setAttribute('cx', x);
+ this.cursorCircle_.setAttribute('cy', y);
+ this.currentCursorSvg = this.cursorCircle_;
+};
+
+/**
+ * @override
+ */
+Blockly.zelos.CursorSvg.prototype.showAtLocation_ = function(curNode) {
+ var handled = false;
+ if (curNode.getType() == Blockly.ASTNode.types.OUTPUT) {
+ // Inputs and outputs are drawn the same.
+ this.showWithInput_(curNode);
+ handled = true;
+ } else if (curNode.getType() == Blockly.ASTNode.types.BLOCK) {
+ this.showWithBlock_(curNode);
+ handled = true;
+ }
+
+ if (!handled) {
+ Blockly.zelos.CursorSvg.superClass_.showAtLocation_.call(this, curNode);
+ }
+};
+
+/**
+ * @override
+ */
+Blockly.zelos.CursorSvg.prototype.hide = function() {
+ Blockly.zelos.CursorSvg.superClass_.hide.call(this);
+ this.cursorCircle_.style.display = 'none';
+};
+
+/**
+ * @override
+ */
+Blockly.zelos.CursorSvg.prototype.createDomInternal_ = function() {
+ /* This markup will be generated and added to the .svgGroup_:
+
+
+
+
+
+ */
+
+ Blockly.zelos.CursorSvg.superClass_.createDomInternal_.call(this);
+ var colour = this.isMarker() ? this.constants_.MARKER_COLOUR :
+ this.constants_.CURSOR_COLOUR;
+
+ this.cursorCircle_ = Blockly.utils.dom.createSvgElement('circle', {
+ 'r': this.constants_.CURSOR_RADIUS,
+ 'style': 'display: none',
+ 'fill': colour,
+ 'stroke': colour,
+ 'stroke-width': this.constants_.CURSOR_STROKE_WIDTH
+ },
+ this.cursorSvg_);
+
+ // Markers and stack cursors don't blink.
+ if (!this.isMarker()) {
+ var blinkProperties = this.getBlinkProperties_();
+ Blockly.utils.dom.createSvgElement('animate', blinkProperties,
+ this.cursorCircle_);
+ }
+
+ return this.cursorSvg_;
+};
+
diff --git a/core/renderers/zelos/renderer.js b/core/renderers/zelos/renderer.js
index 47d4134da..773d51c7f 100644
--- a/core/renderers/zelos/renderer.js
+++ b/core/renderers/zelos/renderer.js
@@ -30,6 +30,7 @@ goog.require('Blockly.zelos.ConstantProvider');
goog.require('Blockly.zelos.Drawer');
goog.require('Blockly.zelos.PathObject');
goog.require('Blockly.zelos.RenderInfo');
+goog.require('Blockly.zelos.CursorSvg');
/**
@@ -79,6 +80,21 @@ Blockly.zelos.Renderer.prototype.makeDrawer_ = function(block, info) {
/** @type {!Blockly.zelos.RenderInfo} */ (info));
};
+/**
+ * Create a new instance of the renderer's cursor drawer.
+ * @param {!Blockly.WorkspaceSvg} workspace The workspace the cursor belongs to.
+ * @param {boolean=} opt_marker True if the cursor is a marker. A marker is used
+ * to save a location and is an immovable cursor. False or undefined if the
+ * cursor is not a marker.
+ * @return {!Blockly.blockRendering.CursorSvg} The cursor drawer.
+ * @package
+ * @override
+ */
+Blockly.zelos.Renderer.prototype.makeCursorDrawer = function(
+ workspace, opt_marker) {
+ return new Blockly.zelos.CursorSvg(workspace, this.getConstants(), opt_marker);
+};
+
/**
* Create a new instance of a renderer path object.
* @param {!SVGElement} root The root SVG element.