From 481fe63302d24c3dc5b8268e8af8957cac211f76 Mon Sep 17 00:00:00 2001 From: alschmiedt Date: Tue, 10 Dec 2019 10:53:34 -0800 Subject: [PATCH] Marker manager (#3497) * Adds a marker manager --- blockly_uncompressed.js | 3 +- core/flyout_base.js | 3 +- core/keyboard_nav/marker.js | 9 ++ core/keyboard_nav/navigation.js | 35 +++-- core/marker_manager.js | 182 ++++++++++++++++++++++++++ core/workspace.js | 49 ------- core/workspace_svg.js | 172 +++++++++++------------- tests/mocha/cursor_test.js | 5 +- tests/mocha/navigation_modify_test.js | 19 +-- tests/mocha/navigation_test.js | 50 ++++--- 10 files changed, 341 insertions(+), 186 deletions(-) create mode 100644 core/marker_manager.js diff --git a/blockly_uncompressed.js b/blockly_uncompressed.js index ee5292084..cc4b87d52 100644 --- a/blockly_uncompressed.js +++ b/blockly_uncompressed.js @@ -82,6 +82,7 @@ goog.addDependency("../../core/keyboard_nav/key_map.js", ['Blockly.user.keyMap'] goog.addDependency("../../core/keyboard_nav/marker.js", ['Blockly.Marker'], ['Blockly.ASTNode', 'Blockly.navigation']); 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.BasicCursor', 'Blockly.utils.object']); +goog.addDependency("../../core/marker_manager.js", ['Blockly.MarkerManager'], ['Blockly.Marker', 'Blockly.Cursor']); 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.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']); @@ -167,7 +168,7 @@ goog.addDependency("../../core/variables.js", ['Blockly.Variables'], ['Blockly.B goog.addDependency("../../core/variables_dynamic.js", ['Blockly.VariablesDynamic'], ['Blockly.Variables', 'Blockly.Blocks', 'Blockly.Msg', 'Blockly.utils.xml', 'Blockly.VariableModel']); goog.addDependency("../../core/warning.js", ['Blockly.Warning'], ['Blockly.Bubble', 'Blockly.Events', 'Blockly.Events.Ui', 'Blockly.Icon', 'Blockly.utils.dom', 'Blockly.utils.object']); goog.addDependency("../../core/widgetdiv.js", ['Blockly.WidgetDiv'], ['Blockly.utils.style']); -goog.addDependency("../../core/workspace.js", ['Blockly.Workspace'], ['Blockly.Cursor', 'Blockly.Marker', 'Blockly.Events', 'Blockly.utils', 'Blockly.utils.math', 'Blockly.VariableMap']); +goog.addDependency("../../core/workspace.js", ['Blockly.Workspace'], ['Blockly.Cursor', 'Blockly.Marker', 'Blockly.MarkerManager', 'Blockly.Events', 'Blockly.utils', 'Blockly.utils.math', 'Blockly.VariableMap']); 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']); diff --git a/core/flyout_base.js b/core/flyout_base.js index 310cb6c33..395421873 100644 --- a/core/flyout_base.js +++ b/core/flyout_base.js @@ -57,8 +57,6 @@ Blockly.Flyout = function(workspaceOptions) { */ this.workspace_ = new Blockly.WorkspaceSvg(workspaceOptions); this.workspace_.isFlyout = true; - this.workspace_.setCursor(new Blockly.FlyoutCursor()); - this.workspace_.setMarker(new Blockly.Marker()); /** * Is RTL vs LTR. @@ -233,6 +231,7 @@ Blockly.Flyout.prototype.createDom = function(tagName) { this.svgBackground_, 'flyout', 'fill'); this.workspace_.getThemeManager().subscribe( this.svgBackground_, 'flyoutOpacity', 'fill-opacity'); + this.workspace_.getMarkerManager().setCursor(new Blockly.FlyoutCursor()); return this.svgGroup_; }; diff --git a/core/keyboard_nav/marker.js b/core/keyboard_nav/marker.js index 16ae24061..f70fa0eea 100644 --- a/core/keyboard_nav/marker.js +++ b/core/keyboard_nav/marker.js @@ -122,3 +122,12 @@ Blockly.Marker.prototype.hide = function() { } }; +/** + * Dispose of this marker. + */ +Blockly.Marker.prototype.dispose = function() { + if (this.getDrawer()) { + this.getDrawer().dispose(); + } +}; + diff --git a/core/keyboard_nav/navigation.js b/core/keyboard_nav/navigation.js index 0a076b9da..e383dfe69 100644 --- a/core/keyboard_nav/navigation.js +++ b/core/keyboard_nav/navigation.js @@ -86,10 +86,25 @@ Blockly.navigation.actionNames = { TOGGLE_KEYBOARD_NAV: 'toggle_keyboard_nav' }; +/** + * The name of the marker reserved for internal use. + * @type {string} + * @const + */ +Blockly.navigation.MARKER_NAME = 'local_marker_1'; + /** ****** */ /** Focus */ /** ****** */ +/** + * Get the local marker. + * @return {!Blockly.Marker} The local marker for the main workspace. + */ +Blockly.navigation.getMarker = function() { + return Blockly.getMainWorkspace().getMarker(Blockly.navigation.MARKER_NAME); +}; + /** * If a toolbox exists, set the navigation state to toolbox and select the first * category in the toolbox. @@ -103,7 +118,7 @@ Blockly.navigation.focusToolbox_ = function() { Blockly.navigation.currentState_ = Blockly.navigation.STATE_TOOLBOX; Blockly.navigation.resetFlyout_(false /* shouldHide */); - if (!workspace.getMarker().getCurNode()) { + if (!Blockly.navigation.getMarker().getCurNode()) { Blockly.navigation.markAtCursor_(); } toolbox.selectFirstCategory(); @@ -121,7 +136,7 @@ Blockly.navigation.focusFlyout_ = function() { var toolbox = workspace.getToolbox(); var flyout = toolbox ? toolbox.flyout_ : workspace.getFlyout(); - if (!workspace.getMarker().getCurNode()) { + if (!Blockly.navigation.getMarker().getCurNode()) { Blockly.navigation.markAtCursor_(); } @@ -242,7 +257,7 @@ Blockly.navigation.resetFlyout_ = function(shouldHide) { * @private */ Blockly.navigation.modifyWarn_ = function() { - var markerNode = Blockly.getMainWorkspace().getMarker().getCurNode(); + var markerNode = Blockly.navigation.getMarker().getCurNode(); var cursorNode = Blockly.getMainWorkspace().getCursor().getCurNode(); if (!markerNode) { @@ -313,7 +328,7 @@ Blockly.navigation.moveBlockToWorkspace_ = function(block, wsNode) { * @private */ Blockly.navigation.modify_ = function() { - var markerNode = Blockly.getMainWorkspace().getMarker().getCurNode(); + var markerNode = Blockly.navigation.getMarker().getCurNode(); var cursorNode = Blockly.getMainWorkspace().getCursor().getCurNode(); if (!Blockly.navigation.modifyWarn_()) { return false; @@ -566,8 +581,8 @@ Blockly.navigation.disconnectBlocks_ = function() { * @private */ Blockly.navigation.markAtCursor_ = function() { - var workspace = Blockly.getMainWorkspace(); - workspace.getMarker().setCurNode(workspace.getCursor().getCurNode()); + Blockly.navigation.getMarker().setCurNode( + Blockly.getMainWorkspace().getCursor().getCurNode()); }; /** @@ -575,9 +590,9 @@ Blockly.navigation.markAtCursor_ = function() { * @private */ Blockly.navigation.removeMark_ = function() { - var workspace = Blockly.getMainWorkspace(); - workspace.getMarker().setCurNode(null); - workspace.getMarker().hide(); + var marker = Blockly.navigation.getMarker(); + marker.setCurNode(null); + marker.hide(); }; /** @@ -680,7 +695,7 @@ Blockly.navigation.disableKeyboardAccessibility = function() { var workspace = Blockly.getMainWorkspace(); Blockly.getMainWorkspace().keyboardAccessibilityMode = false; workspace.getCursor().hide(); - workspace.getMarker().hide(); + Blockly.navigation.getMarker().hide(); if (Blockly.navigation.getFlyoutCursor_()) { Blockly.navigation.getFlyoutCursor_().hide(); } diff --git a/core/marker_manager.js b/core/marker_manager.js new file mode 100644 index 000000000..e64ff2d74 --- /dev/null +++ b/core/marker_manager.js @@ -0,0 +1,182 @@ +/** + * @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 Object in charge of managing markers and the cursor. + * @author aschmiedt@google.com (Abby Schmiedt) + */ +'use strict'; + +goog.provide('Blockly.MarkerManager'); + +goog.require('Blockly.Cursor'); +goog.require('Blockly.Marker'); + + +/** + * Class to manage the multiple markers and the cursor on a workspace. + * @param {!Blockly.WorkspaceSvg} workspace The workspace for the marker manager. + * @constructor + * @package + */ +Blockly.MarkerManager = function(workspace){ + /** + * The cursor. + * @type {Blockly.Cursor} + * @private + */ + this.cursor_ = null; + + /** + * The cursor's svg element. + * @type {SVGElement} + * @private + */ + this.cursorSvg_ = null; + + /** + * The map of markers for the workspace. + * @type {!Object} + * @private + */ + this.markers_ = {}; + + /** + * The workspace this marker manager is associated with. + * @type {!Blockly.WorkspaceSvg} + * @private + */ + this.workspace_ = workspace; +}; + +/** + * Register the marker by adding it to the map of markers. + * @param {string} id A unique identifier for the marker. + * @param {!Blockly.Marker} marker The marker to register. + */ +Blockly.MarkerManager.prototype.registerMarker = function(id, marker) { + if (this.markers_[id]) { + this.unregisterMarker(id); + } + marker.setDrawer(this.workspace_.getRenderer() + .makeMarkerDrawer(this.workspace_, marker)); + this.setMarkerSvg(marker.getDrawer().createDom()); + this.markers_[id] = marker; +}; + +/** + * Unregister the marker by removing it from the map of markers. + * @param {string} id The id of the marker to unregister. + */ +Blockly.MarkerManager.prototype.unregisterMarker = function(id) { + var marker = this.markers_[id]; + if (marker) { + marker.dispose(); + delete this.markers_[id]; + } else { + throw Error('Marker with id ' + id + ' does not exist. Can only unregister' + + 'markers that exist.'); + } +}; + +/** + * Get the cursor for the workspace. + * @return {Blockly.Cursor} The cursor for this workspace. + */ +Blockly.MarkerManager.prototype.getCursor = function() { + return this.cursor_; +}; + +/** + * Get a single marker that corresponds to the given id. + * @param {string} id A unique identifier for the marker. + * @return {Blockly.Marker} The marker that corresponds to the given id, or null + * if none exists. + */ +Blockly.MarkerManager.prototype.getMarker = function(id) { + return this.markers_[id]; +}; + +/** + * Sets the cursor and initializes the drawer for use with keyboard navigation. + * @param {Blockly.Cursor} cursor The cursor used to move around this workspace. + */ +Blockly.MarkerManager.prototype.setCursor = function(cursor) { + if (this.cursor_ && this.cursor_.getDrawer()) { + this.cursor_.getDrawer().dispose(); + } + this.cursor_ = cursor; + if (this.cursor_) { + var drawer = this.workspace_.getRenderer() + .makeMarkerDrawer(this.workspace_, this.cursor_); + this.cursor_.setDrawer(drawer); + this.setCursorSvg(this.cursor_.getDrawer().createDom()); + } +}; + +/** + * Add the cursor svg to this workspace svg group. + * @param {SVGElement} cursorSvg The svg root of the cursor to be added to the + * workspace svg group. + * @package + */ +Blockly.MarkerManager.prototype.setCursorSvg = function(cursorSvg) { + if (!cursorSvg) { + this.cursorSvg_ = null; + return; + } + + this.workspace_.getBlockCanvas().appendChild(cursorSvg); + this.cursorSvg_ = cursorSvg; +}; + +/** + * Add the marker svg to this workspaces svg group. + * @param {SVGElement} markerSvg The svg root of the marker to be added to the + * workspace svg group. + * @package + */ +Blockly.MarkerManager.prototype.setMarkerSvg = function(markerSvg) { + if (!markerSvg) { + this.markerSvg_ = null; + return; + } + + if (this.workspace_.getBlockCanvas()) { + if (this.cursorSvg_) { + this.workspace_.getBlockCanvas().insertBefore(markerSvg, this.cursorSvg_); + } else { + this.workspace_.getBlockCanvas().appendChild(markerSvg); + } + } +}; + +/** + * Dispose of the marker manager. + * Go through and delete all markers associated with this marker manager. + * @suppress {checkTypes} + * @package + */ +Blockly.MarkerManager.prototype.dispose = function() { + var markerIds = Object.keys(this.markers_); + for (var i = 0, markerId; (markerId = markerIds[i]); i++) { + this.unregisterMarker(markerId); + } + this.markers_ = null; + this.cursor_.dispose(); + this.cursor_ = null; +}; diff --git a/core/workspace.js b/core/workspace.js index 87cd0b2f9..3f9749a75 100644 --- a/core/workspace.js +++ b/core/workspace.js @@ -112,20 +112,6 @@ Blockly.Workspace = function(opt_options) { */ this.potentialVariableMap_ = null; - /** - * The cursor used to navigate around the AST for keyboard navigation. - * @type {!Blockly.Cursor} - * @protected - */ - this.cursor_ = new Blockly.Cursor(); - - /** - * The marker used to mark a location for keyboard navigation. - * @type {!Blockly.Marker} - * @protected - */ - this.marker_ = new Blockly.Marker(); - /** * True if keyboard accessibility mode is on, false otherwise. * @type {boolean} @@ -160,41 +146,6 @@ Blockly.Workspace.prototype.MAX_UNDO = 1024; */ Blockly.Workspace.prototype.connectionDBList = null; -/** - * Sets the cursor for keyboard navigation. - * @param {!Blockly.Cursor} cursor The cursor used to navigate around the Blockly - * AST for keyboard navigation. - */ -Blockly.Workspace.prototype.setCursor = function(cursor) { - this.cursor_ = cursor; -}; - -/** - * Sets the marker for keyboard navigation. - * @param {!Blockly.Marker} marker The marker used to mark a location for - * keyboard navigation. - */ -Blockly.Workspace.prototype.setMarker = function(marker) { - this.marker_ = marker; -}; - -/** - * Get the cursor used to navigate around the AST for keyboard navigation. - * @return {Blockly.Cursor} The cursor for this workspace. - */ -Blockly.Workspace.prototype.getCursor = function() { - return this.cursor_; -}; - -/** - * Get the marker used to mark a location for keyboard navigation. - * @return {Blockly.Marker} The marker used to mark a location for keyboard - * navigation. - */ -Blockly.Workspace.prototype.getMarker = function() { - return this.marker_; -}; - /** * Dispose of this workspace. * Unlink from all DOM elements to prevent memory leaks. diff --git a/core/workspace_svg.js b/core/workspace_svg.js index d9c9a781a..17fcf2811 100644 --- a/core/workspace_svg.js +++ b/core/workspace_svg.js @@ -31,6 +31,7 @@ goog.require('Blockly.Events'); goog.require('Blockly.Events.BlockCreate'); goog.require('Blockly.Gesture'); goog.require('Blockly.Grid'); +goog.require('Blockly.MarkerManager'); goog.require('Blockly.Msg'); goog.require('Blockly.navigation'); goog.require('Blockly.Options'); @@ -109,20 +110,11 @@ Blockly.WorkspaceSvg = function(options, new Blockly.Grid(options.gridPattern, options.gridOptions) : null; /** - * Holds the cursors svg element when the cursor is attached to the workspace. - * This is null if there is no cursor on the workspace. - * @type {SVGElement} + * Manager in charge of markers and cursors. + * @type {!Blockly.MarkerManager} * @private */ - this.cursorSvg_ = null; - - /** - * Holds the markers svg element when the marker is attached to the workspace. - * This is null if there is no marker on the workspace. - * @type {SVGElement} - * @private - */ - this.markerSvg_ = null; + this.markerManager_ = new Blockly.MarkerManager(this); if (Blockly.Variables && Blockly.Variables.flyoutCategory) { this.registerToolboxCategoryCallback(Blockly.VARIABLE_CATEGORY_NAME, @@ -432,6 +424,59 @@ Blockly.WorkspaceSvg.prototype.inverseScreenCTM_ = null; */ Blockly.WorkspaceSvg.prototype.inverseScreenCTMDirty_ = true; +/** + * Get the marker manager for this workspace. + * @return {Blockly.MarkerManager} The marker manager. + */ +Blockly.WorkspaceSvg.prototype.getMarkerManager = function() { + return this.markerManager_; +}; + +/** + * Add the cursor svg to this workspaces svg group. + * @param {SVGElement} cursorSvg The svg root of the cursor to be added to the + * workspace svg group. + * @package + */ +Blockly.WorkspaceSvg.prototype.setCursorSvg = function(cursorSvg) { + this.markerManager_.setCursorSvg(cursorSvg); +}; + +/** + * Add the marker svg to this workspaces svg group. + * @param {SVGElement} markerSvg The svg root of the marker to be added to the + * workspace svg group. + * @package + */ +Blockly.WorkspaceSvg.prototype.setMarkerSvg = function(markerSvg) { + this.markerManager_.setMarkerSvg(markerSvg); +}; + +/** + * Get the marker with the given id. + * @param {string} id The id of the marker. + * @return {Blockly.Marker} The marker with the given id or null if no marker + * with the given id exists. + * @package + */ +Blockly.WorkspaceSvg.prototype.getMarker = function(id) { + if (this.markerManager_) { + return this.markerManager_.getMarker(id); + } + return null; +}; + +/** + * The cursor for this workspace. + * @return {Blockly.Cursor} The cursor for the workspace. + */ +Blockly.WorkspaceSvg.prototype.getCursor = function() { + if (this.markerManager_) { + return this.markerManager_.getCursor(); + } + return null; +}; + /** * Get the block renderer attached to this workspace. * @return {!Blockly.blockRendering.Renderer} The renderer attached to this workspace. @@ -512,74 +557,6 @@ Blockly.WorkspaceSvg.prototype.updateBlockStyles_ = function(blocks) { } }; -/** - * Sets the cursor for use with keyboard navigation. - * @param {!Blockly.Cursor} cursor The cursor used to move around this workspace. - * @override - */ -Blockly.WorkspaceSvg.prototype.setCursor = function(cursor) { - if (this.cursor_.getDrawer()) { - this.cursor_.getDrawer().dispose(); - } - this.cursor_ = cursor; - this.cursor_.setDrawer(this.getRenderer().makeMarkerDrawer(this, this.cursor_)); - this.setCursorSvg(this.cursor_.getDrawer().createDom()); -}; - -/** - * Sets the marker for use with keyboard navigation. - * @param {!Blockly.Marker} marker Used to save a location in the Blockly AST. - * @override - */ -Blockly.WorkspaceSvg.prototype.setMarker = function(marker) { - if (this.marker_.getDrawer()) { - this.marker_.getDrawer().dispose(); - } - this.marker_ = marker; - this.marker_.setDrawer(this.getRenderer().makeMarkerDrawer(this, this.marker_)); - this.setMarkerSvg(this.marker_.getDrawer().createDom()); -}; - -/** - * Add the cursor svg to this workspaces svg group. - * @param {SVGElement} cursorSvg The svg root of the cursor to be added to the - * workspace svg group. - * @package - */ -Blockly.WorkspaceSvg.prototype.setCursorSvg = function(cursorSvg) { - if (!cursorSvg) { - this.cursorSvg_ = null; - return; - } - - if (this.svgBlockCanvas_) { - this.svgBlockCanvas_.appendChild(cursorSvg); - this.cursorSvg_ = cursorSvg; - } -}; - -/** - * Add the marker svg to this workspaces svg group. - * @param {SVGElement} markerSvg The svg root of the marker to be added to the - * workspace svg group. - * @package - */ -Blockly.WorkspaceSvg.prototype.setMarkerSvg = function(markerSvg) { - if (!markerSvg) { - this.markerSvg_ = null; - return; - } - - if (this.svgBlockCanvas_) { - if (this.cursorSvg_) { - this.svgBlockCanvas_.insertBefore(markerSvg, this.cursorSvg_); - } else { - this.svgBlockCanvas_.appendChild(markerSvg); - } - this.markerSvg_ = markerSvg; - } -}; - /** * Getter for the inverted screen CTM. * @return {SVGMatrix} The matrix to use in mouseToSvg @@ -684,6 +661,15 @@ Blockly.WorkspaceSvg.prototype.getInjectionDiv = function() { return /** @type {!Element} */ (this.injectionDiv_); }; +/** + * Get the svg block canvas for the workspace. + * @return {SVGElement} The svg group for the workspace. + * @package + */ +Blockly.WorkspaceSvg.prototype.getBlockCanvas = function() { + return this.svgBlockCanvas_; +}; + /** * Save resize handler data so we can delete it later in dispose. * @param {!Array.} handler Data that can be passed to unbindEvent_. @@ -754,13 +740,9 @@ Blockly.WorkspaceSvg.prototype.createDom = function(opt_backgroundClass) { } this.recordDeleteAreas(); - this.cursor_.setDrawer(this.getRenderer().makeMarkerDrawer(this, this.cursor_)); - var svgCursor = this.cursor_.getDrawer().createDom(); - this.svgGroup_.appendChild(svgCursor); - - this.marker_.setDrawer(this.getRenderer().makeMarkerDrawer(this, this.marker_)); - var svgMarker = this.marker_.getDrawer().createDom(); - this.svgGroup_.appendChild(svgMarker); + this.markerManager_.setCursor(new Blockly.Cursor()); + this.markerManager_.registerMarker(Blockly.navigation.MARKER_NAME, + new Blockly.Marker()); this.getRenderer().getConstants().createDom(this.svgGroup_); return this.svgGroup_; @@ -804,14 +786,6 @@ Blockly.WorkspaceSvg.prototype.dispose = function() { this.zoomControls_ = null; } - if (this.marker_ && this.marker_.getDrawer()) { - this.marker_.getDrawer().dispose(); - } - - if (this.getCursor() && this.getCursor().getDrawer()) { - this.getCursor().getDrawer().dispose(); - } - if (this.audioManager_) { this.audioManager_.dispose(); this.audioManager_ = null; @@ -832,6 +806,12 @@ Blockly.WorkspaceSvg.prototype.dispose = function() { this.themeManager_ = null; } } + + if (this.markerManager_) { + this.markerManager_.dispose(); + this.markerManager_ = null; + } + Blockly.WorkspaceSvg.superClass_.dispose.call(this); this.connectionDBList = null; @@ -1292,7 +1272,7 @@ Blockly.WorkspaceSvg.prototype.pasteBlock_ = function(xmlBlock) { var block = Blockly.Xml.domToBlock(xmlBlock, this); // Handle paste for keyboard navigation - var markedNode = this.getMarker().getCurNode(); + var markedNode = this.getMarker(Blockly.navigation.MARKER_NAME).getCurNode(); if (this.keyboardAccessibilityMode && markedNode && markedNode.isConnection()) { var markedLocation = diff --git a/tests/mocha/cursor_test.js b/tests/mocha/cursor_test.js index efe38a812..0afad6888 100644 --- a/tests/mocha/cursor_test.js +++ b/tests/mocha/cursor_test.js @@ -62,8 +62,7 @@ suite('Cursor', function() { "helpUrl": "" } ]); - this.workspace = new Blockly.Workspace(); - this.workspace.setCursor(new Blockly.Cursor()); + this.workspace = Blockly.inject('blocklyDiv', {}); this.cursor = this.workspace.getCursor(); var blockA = this.workspace.newBlock('input_statement'); var blockB = this.workspace.newBlock('input_statement'); @@ -74,7 +73,7 @@ suite('Cursor', function() { blockA.nextConnection.connect(blockB.previousConnection); blockA.inputList[0].connection.connect(blockE.outputConnection); blockB.inputList[1].connection.connect(blockC.previousConnection); - + this.cursor.drawer_ = null; this.blocks = { A: blockA, B: blockB, diff --git a/tests/mocha/navigation_modify_test.js b/tests/mocha/navigation_modify_test.js index 6fa8d5d61..18e146c88 100644 --- a/tests/mocha/navigation_modify_test.js +++ b/tests/mocha/navigation_modify_test.js @@ -54,7 +54,7 @@ suite('Insert/Modify', function() { // TODO: Marked connection or cursor connection is already connected. suite('Marker on next', function() { setup(function() { - this.workspace.getMarker().setCurNode( + this.workspace.getMarker(Blockly.navigation.MARKER_NAME).setCurNode( Blockly.ASTNode.createConnectionNode( this.stack_block_1.nextConnection)); }); @@ -98,7 +98,7 @@ suite('Insert/Modify', function() { suite('Marker on previous', function() { setup(function() { - this.workspace.getMarker().setCurNode( + this.workspace.getMarker(Blockly.navigation.MARKER_NAME).setCurNode( Blockly.ASTNode.createConnectionNode( this.stack_block_1.previousConnection)); }); @@ -141,7 +141,7 @@ suite('Insert/Modify', function() { suite('Marker on value input', function() { setup(function() { - this.workspace.getMarker().setCurNode( + this.workspace.getMarker(Blockly.navigation.MARKER_NAME).setCurNode( Blockly.ASTNode.createConnectionNode( this.row_block_1.inputList[0].connection)); }); @@ -182,7 +182,7 @@ suite('Insert/Modify', function() { this.statement_block_1.inputList[0].connection.connect( this.stack_block_1.previousConnection); this.stack_block_1.nextConnection.connect(this.stack_block_2.previousConnection); - this.workspace.getMarker().setCurNode( + this.workspace.getMarker(Blockly.navigation.MARKER_NAME).setCurNode( Blockly.ASTNode.createInputNode( this.statement_block_1.inputList[0])); }); @@ -213,7 +213,7 @@ suite('Insert/Modify', function() { suite('Marker on output', function() { setup(function() { - this.workspace.getMarker().setCurNode( + this.workspace.getMarker(Blockly.navigation.MARKER_NAME).setCurNode( Blockly.ASTNode.createConnectionNode( this.row_block_1.outputConnection)); }); @@ -249,7 +249,8 @@ suite('Insert/Modify', function() { suite('Marked Workspace', function() { setup(function() { - this.workspace.getMarker().setCurNode( + this.workspace.getMarker(Blockly.navigation.MARKER_NAME).drawer_ = null; + this.workspace.getMarker(Blockly.navigation.MARKER_NAME).setCurNode( Blockly.ASTNode.createWorkspaceNode( this.workspace, new Blockly.utils.Coordinate(100, 200))); }); @@ -344,7 +345,7 @@ suite('Insert/Modify', function() { // These tests are using a stack block, but do not depend on the type of // the block. setup(function() { - this.workspace.getMarker().setCurNode( + this.workspace.getMarker(Blockly.navigation.MARKER_NAME).setCurNode( Blockly.ASTNode.createBlockNode( this.stack_block_1)); }); @@ -358,7 +359,7 @@ suite('Insert/Modify', function() { }); suite('Marked stack block', function() { setup(function() { - this.workspace.getMarker().setCurNode( + this.workspace.getMarker(Blockly.navigation.MARKER_NAME).setCurNode( Blockly.ASTNode.createBlockNode( this.stack_block_1)); }); @@ -389,7 +390,7 @@ suite('Insert/Modify', function() { }); suite('Marked row block', function() { setup(function() { - this.workspace.getMarker().setCurNode( + this.workspace.getMarker(Blockly.navigation.MARKER_NAME).setCurNode( Blockly.ASTNode.createBlockNode( this.row_block_1)); }); diff --git a/tests/mocha/navigation_test.js b/tests/mocha/navigation_test.js index b2c2b501a..ddbefcd36 100644 --- a/tests/mocha/navigation_test.js +++ b/tests/mocha/navigation_test.js @@ -166,6 +166,7 @@ suite('Navigation', function() { ] }]); this.workspace = createNavigationWorkspace(true); + Blockly.mainWorkspace = this.workspace; Blockly.navigation.focusToolbox_(); Blockly.navigation.focusFlyout_(); this.mockEvent = { @@ -329,7 +330,7 @@ suite('Navigation', function() { Blockly.ASTNode.createConnectionNode(this.basicBlock.previousConnection)); this.mockEvent.keyCode = Blockly.utils.KeyCodes.ENTER; chai.assert.isTrue(Blockly.navigation.onKeyPress(this.mockEvent)); - var markedNode = this.workspace.getMarker().getCurNode(); + var markedNode = this.workspace.getMarker(Blockly.navigation.MARKER_NAME).getCurNode(); chai.assert.equal(markedNode.getLocation(), this.basicBlock.previousConnection); chai.assert.equal(Blockly.navigation.currentState_, Blockly.navigation.STATE_WS); @@ -346,7 +347,26 @@ suite('Navigation', function() { suite('Test key press', function() { setup(function() { - this.workspace = new Blockly.Workspace({readOnly: false}); + Blockly.defineBlocksWithJsonArray([{ + "type": "basic_block", + "message0": "%1", + "args0": [ + { + "type": "field_dropdown", + "name": "OP", + "options": [ + ["%{BKY_MATH_ADDITION_SYMBOL}", "ADD"], + ["%{BKY_MATH_SUBTRACTION_SYMBOL}", "MINUS"], + ["%{BKY_MATH_MULTIPLICATION_SYMBOL}", "MULTIPLY"], + ["%{BKY_MATH_DIVISION_SYMBOL}", "DIVIDE"], + ["%{BKY_MATH_POWER_SYMBOL}", "POWER"] + ] + } + ] + }]); + this.workspace = createNavigationWorkspace(true); + this.workspace.getCursor().drawer_ = null; + this.basicBlock = this.workspace.newBlock('basic_block'); Blockly.user.keyMap.setKeyMap(Blockly.user.keyMap.createDefaultKeyMap()); Blockly.mainWorkspace = this.workspace; Blockly.getMainWorkspace().keyboardAccessibilityMode = true; @@ -359,12 +379,10 @@ suite('Navigation', function() { }; }); test('Action does not exist', function() { - var block = new Blockly.Block(this.workspace); - var field = new Blockly.FieldDropdown([['a','b'], ['c','d']]); - field.setSourceBlock(block); + var block = this.workspace.getTopBlocks()[0]; + var field = block.inputList[0].fieldRow[0]; sinon.spy(field, 'onBlocklyAction'); this.workspace.getCursor().setCurNode(Blockly.ASTNode.createFieldNode(field)); - this.mockEvent.keyCode = Blockly.utils.KeyCodes.N; var isHandled = Blockly.navigation.onKeyPress(this.mockEvent); chai.assert.isFalse(isHandled); @@ -374,9 +392,9 @@ suite('Navigation', function() { }); test('Action exists - field handles action', function() { - var block = new Blockly.Block(this.workspace); - var field = new Blockly.FieldDropdown([['a','b'], ['c','d']]); - field.setSourceBlock(block); + var block = this.workspace.getTopBlocks()[0]; + var field = block.inputList[0].fieldRow[0]; + sinon.stub(field, 'onBlocklyAction').callsFake(function(){ return true; }); @@ -390,9 +408,8 @@ suite('Navigation', function() { }); test('Action exists - field does not handle action', function() { - var block = new Blockly.Block(this.workspace); - var field = new Blockly.FieldDropdown([['a','b'], ['c','d']]); - field.setSourceBlock(block); + var block = this.workspace.getTopBlocks()[0]; + var field = block.inputList[0].fieldRow[0]; sinon.spy(field, 'onBlocklyAction'); this.workspace.getCursor().setCurNode(Blockly.ASTNode.createFieldNode(field)); @@ -456,9 +473,10 @@ suite('Navigation', function() { "tooltip": "", "helpUrl": "" }]); - this.workspace = new Blockly.Workspace({readOnly: true}); - this.workspace.setCursor(new Blockly.Cursor()); + this.workspace = Blockly.inject('blocklyDiv', {readOnly: true}); + Blockly.mainWorkspace = this.workspace; + this.workspace.getCursor().drawer_ = null; Blockly.getMainWorkspace().keyboardAccessibilityMode = true; Blockly.navigation.currentState_ = Blockly.navigation.STATE_WS; @@ -525,7 +543,7 @@ suite('Navigation', function() { test('Insert from flyout with a valid connection marked', function() { var previousConnection = this.basicBlock.previousConnection; var prevNode = Blockly.ASTNode.createConnectionNode(previousConnection); - this.workspace.getMarker().setCurNode(prevNode); + this.workspace.getMarker(Blockly.navigation.MARKER_NAME).setCurNode(prevNode); Blockly.navigation.focusToolbox_(); Blockly.navigation.focusFlyout_(); @@ -557,7 +575,7 @@ suite('Navigation', function() { test('Connect two blocks that are on the workspace', function() { var targetNode = Blockly.ASTNode.createConnectionNode(this.basicBlock.previousConnection); - this.workspace.getMarker().setCurNode(targetNode); + this.workspace.getMarker(Blockly.navigation.MARKER_NAME).setCurNode(targetNode); var sourceNode = Blockly.ASTNode.createConnectionNode(this.basicBlock2.nextConnection); this.workspace.getCursor().setCurNode(sourceNode);