Merge toolbox navigation (#3054)

* Merge both types of keyboard navigation (with and without accessibility mode).
This commit is contained in:
Sam El-Husseini
2019-09-19 16:36:39 -07:00
committed by GitHub
parent 1c3db256fa
commit cb564053b3
9 changed files with 228 additions and 200 deletions

View File

@@ -40,7 +40,7 @@ goog.require('Blockly.utils.style');
*
* @param {string} content The content of the node label treated as
* plain-text and will be HTML escaped.
* @param {Blockly.tree.BaseNode.Config} config The configuration for the tree.
* @param {!Blockly.tree.BaseNode.Config} config The configuration for the tree.
* @constructor
* @extends {Blockly.Component}
*/
@@ -49,7 +49,7 @@ Blockly.tree.BaseNode = function(content, config) {
/**
* The configuration for the tree.
* @type {Blockly.tree.BaseNode.Config}
* @type {!Blockly.tree.BaseNode.Config}
* @private
*/
this.config_ = config;
@@ -487,6 +487,17 @@ Blockly.tree.BaseNode.prototype.select = function() {
}
};
/**
* Selects the first node.
* @protected
*/
Blockly.tree.BaseNode.prototype.selectFirst = function() {
var tree = this.getTree();
if (tree && this.firstChild_) {
tree.setSelectedItem(this.firstChild_);
}
};
/**
* Called from the tree to instruct the node change its selection state.
* @param {boolean} selected The new selection state.
@@ -885,7 +896,7 @@ Blockly.tree.BaseNode.prototype.getElement = function() {
/**
* @return {Element} The row is the div that is used to draw the node without
* the children.
* @protected
* @package
*/
Blockly.tree.BaseNode.prototype.getRowElement = function() {
var el = this.getElement();
@@ -1116,43 +1127,22 @@ Blockly.tree.BaseNode.prototype.onKeyDown = function(e) {
if (e.altKey) {
break;
}
if (this.hasChildren()) {
if (!this.getExpanded()) {
this.setExpanded(true);
} else {
this.getFirstChild().select();
}
}
handled = this.selectChild();
break;
case Blockly.utils.KeyCodes.LEFT:
if (e.altKey) {
break;
}
if (this.hasChildren() && this.getExpanded() && this.isUserCollapsible_) {
this.setExpanded(false);
} else {
var parent = this.getParent();
var tree = this.getTree();
// don't go to root if hidden
if (parent && (parent != tree)) {
parent.select();
}
}
handled = this.selectParent();
break;
case Blockly.utils.KeyCodes.DOWN:
var nextNode = this.getNextShownNode();
if (nextNode) {
nextNode.select();
}
handled = this.selectNext();
break;
case Blockly.utils.KeyCodes.UP:
var previousNode = this.getPreviousShownNode();
if (previousNode) {
previousNode.select();
}
handled = this.selectPrevious();
break;
default:
@@ -1166,6 +1156,70 @@ Blockly.tree.BaseNode.prototype.onKeyDown = function(e) {
return handled;
};
/**
* Select the next node.
* @return {boolean} True if the action has been handled, false otherwise.
* @package
*/
Blockly.tree.BaseNode.prototype.selectNext = function() {
var nextNode = this.getNextShownNode();
if (nextNode) {
nextNode.select();
}
return true;
};
/**
* Select the previous node.
* @return {boolean} True if the action has been handled, false otherwise.
* @package
*/
Blockly.tree.BaseNode.prototype.selectPrevious = function() {
var previousNode = this.getPreviousShownNode();
if (previousNode) {
previousNode.select();
}
return true;
};
/**
* Select the parent node or collapse the current node.
* @return {boolean} True if the action has been handled, false otherwise.
* @package
*/
Blockly.tree.BaseNode.prototype.selectParent = function() {
if (this.hasChildren() && this.getExpanded() && this.isUserCollapsible_) {
this.setExpanded(false);
} else {
var parent = this.getParent();
var tree = this.getTree();
// don't go to root if hidden
if (parent && (parent != tree)) {
parent.select();
}
}
return true;
};
/**
* Expand the current node if it's not already expanded, or select the
* child node.
* @return {boolean} True if the action has been handled, false otherwise.
* @package
*/
Blockly.tree.BaseNode.prototype.selectChild = function() {
if (this.hasChildren()) {
if (!this.getExpanded()) {
this.setExpanded(true);
} else {
this.getFirstChild().select();
}
return true;
}
return false;
};
/**
* @return {Blockly.tree.BaseNode} The last shown descendant.
* @protected
@@ -1222,7 +1276,7 @@ Blockly.tree.BaseNode.prototype.getPreviousShownNode = function() {
};
/**
* @return {Blockly.tree.BaseNode.Config} The configuration for the tree.
* @return {!Blockly.tree.BaseNode.Config} The configuration for the tree.
* @protected
*/
Blockly.tree.BaseNode.prototype.getConfig = function() {

View File

@@ -40,7 +40,7 @@ goog.require('Blockly.utils.style');
* Similar to Closure's goog.ui.tree.TreeControl
*
* @param {Blockly.Toolbox} toolbox The parent toolbox for this tree.
* @param {Blockly.tree.BaseNode.Config} config The configuration for the tree.
* @param {!Blockly.tree.BaseNode.Config} config The configuration for the tree.
* @constructor
* @extends {Blockly.tree.BaseNode}
*/

View File

@@ -39,7 +39,7 @@ goog.require('Blockly.utils.KeyCodes');
* @param {Blockly.Toolbox} toolbox The parent toolbox for this tree.
* @param {string} content The content of the node label treated as
* plain-text and will be HTML escaped.
* @param {Blockly.tree.BaseNode.Config} config The configuration for the tree.
* @param {!Blockly.tree.BaseNode.Config} config The configuration for the tree.
* @constructor
* @extends {Blockly.tree.BaseNode}
*/

View File

@@ -31,6 +31,7 @@ goog.require('Blockly.Events');
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');

View File

@@ -33,14 +33,6 @@ goog.require('Blockly.utils.Coordinate');
goog.require('Blockly.user.keyMap');
/**
* The current selected category if the toolbox is open or
* last selected category if focus is on a different element.
* @type {Blockly.tree.BaseNode}
* @private
*/
Blockly.navigation.currentCategory_ = null;
/**
* A function to call to give feedback to the user about logs, warnings, and
* errors. You can override this to customize feedback (e.g. warning sounds,
@@ -154,94 +146,7 @@ Blockly.navigation.focusToolbox_ = function() {
if (!Blockly.getMainWorkspace().getMarker().getCurNode()) {
Blockly.navigation.markAtCursor_();
}
if (workspace && !Blockly.navigation.currentCategory_) {
Blockly.navigation.currentCategory_ = toolbox.tree_.firstChild_;
}
toolbox.tree_.setSelectedItem(Blockly.navigation.currentCategory_);
};
/**
* Select the next category.
* Taken from closure/goog/ui/tree/basenode.js
* @private
*/
Blockly.navigation.nextCategory_ = function() {
if (!Blockly.navigation.currentCategory_) {
return;
}
var curCategory = Blockly.navigation.currentCategory_;
var nextNode = curCategory.getNextShownNode();
if (nextNode) {
nextNode.select();
Blockly.navigation.currentCategory_ = nextNode;
}
};
/**
* Select the previous category.
* Taken from closure/goog/ui/tree/basenode.js
* @private
*/
Blockly.navigation.previousCategory_ = function() {
if (!Blockly.navigation.currentCategory_) {
return;
}
var curCategory = Blockly.navigation.currentCategory_;
var previousNode = curCategory.getPreviousShownNode();
if (previousNode) {
previousNode.select();
Blockly.navigation.currentCategory_ = previousNode;
}
};
/**
* Go to child category if there is a nested category.
* Taken from closure/goog/ui/tree/basenode.js
* @private
*/
Blockly.navigation.inCategory_ = function() {
if (!Blockly.navigation.currentCategory_) {
return;
}
var curCategory = Blockly.navigation.currentCategory_;
if (curCategory.hasChildren()) {
if (!curCategory.getExpanded()) {
curCategory.setExpanded(true);
} else {
curCategory.getFirstChild().select();
Blockly.navigation.currentCategory_ = curCategory.getFirstChild();
}
} else {
Blockly.navigation.focusFlyout_();
}
};
/**
* Go to parent category if we are in a child category.
* Taken from closure/goog/ui/tree/basenode.js
* @private
*/
Blockly.navigation.outCategory_ = function() {
if (!Blockly.navigation.currentCategory_) {
return;
}
var curCategory = Blockly.navigation.currentCategory_;
if (curCategory.hasChildren() && curCategory.getExpanded() && curCategory.isUserCollapsible()) {
curCategory.setExpanded(false);
} else {
var parent = curCategory.getParent();
var tree = curCategory.getTree();
if (parent && parent != tree) {
parent.select();
Blockly.navigation.currentCategory_ = /** @type {Blockly.tree.BaseNode} */
(parent);
}
}
toolbox.selectFirstCategory();
};
/***********************/
@@ -923,25 +828,18 @@ Blockly.navigation.flyoutOnAction_ = function(action) {
* @private
*/
Blockly.navigation.toolboxOnAction_ = function(action) {
switch (action.name) {
case Blockly.navigation.actionNames.PREVIOUS:
Blockly.navigation.previousCategory_();
return true;
case Blockly.navigation.actionNames.OUT:
Blockly.navigation.outCategory_();
return true;
case Blockly.navigation.actionNames.NEXT:
Blockly.navigation.nextCategory_();
return true;
case Blockly.navigation.actionNames.IN:
Blockly.navigation.inCategory_();
return true;
case Blockly.navigation.actionNames.EXIT:
Blockly.navigation.focusWorkspace_();
return true;
default:
return false;
if (action.name === Blockly.navigation.actionNames.EXIT) {
Blockly.navigation.focusWorkspace_();
return true;
}
var toolbox = Blockly.getMainWorkspace().getToolbox();
var handled = toolbox.onBlocklyAction(action);
if (!handled && action.name === Blockly.navigation.actionNames.IN) {
Blockly.navigation.focusFlyout_();
return true;
}
return handled;
};
/**

View File

@@ -26,6 +26,20 @@
goog.provide('Blockly.Theme');
/**
* Class for a theme.
* @param {!Object.<string, Blockly.Theme.BlockStyle>} blockStyles A map from style
* names (strings) to objects with style attributes relating to blocks.
* @param {!Object.<string, Blockly.Theme.CategoryStyle>} categoryStyles A map from
* style names (strings) to objects with style attributes relating to
* categories.
* @constructor
*/
Blockly.Theme = function(blockStyles, categoryStyles) {
this.blockStyles_ = blockStyles;
this.categoryStyles_ = categoryStyles;
};
/**
* A block style.
* @typedef {{
@@ -45,20 +59,6 @@ Blockly.Theme.BlockStyle;
*/
Blockly.Theme.CategoryStyle;
/**
* Class for a theme.
* @param {!Object.<string, Blockly.Theme.BlockStyle>} blockStyles A map from style
* names (strings) to objects with style attributes relating to blocks.
* @param {!Object.<string, Blockly.Theme.CategoryStyle>} categoryStyles A map from
* style names (strings) to objects with style attributes relating to
* categories.
* @constructor
*/
Blockly.Theme = function(blockStyles, categoryStyles) {
this.blockStyles_ = blockStyles;
this.categoryStyles_ = categoryStyles;
};
/**
* Overrides or adds all values from blockStyles to blockStyles_
* @param {Object.<string, Blockly.Theme.BlockStyle>} blockStyles Map of

View File

@@ -30,6 +30,7 @@ goog.require('Blockly.Events');
goog.require('Blockly.Events.Ui');
goog.require('Blockly.Flyout');
goog.require('Blockly.HorizontalFlyout');
goog.require('Blockly.navigation');
goog.require('Blockly.Touch');
goog.require('Blockly.tree.TreeControl');
goog.require('Blockly.tree.TreeNode');
@@ -77,7 +78,7 @@ Blockly.Toolbox = function(workspace) {
/**
* Configuration constants for Closure's tree UI.
* @type {Object.<string,*>}
* @type {!Object.<string,*>}
* @private
*/
this.config_ = {
@@ -96,7 +97,7 @@ Blockly.Toolbox = function(workspace) {
/**
* Configuration constants for tree separator.
* @type {Object.<string,*>}
* @type {!Object.<string,*>}
* @private
*/
this.treeSeparatorConfig_ = {
@@ -198,12 +199,16 @@ Blockly.Toolbox.prototype.init = function() {
this.config_['cleardotPath'] = workspace.options.pathToMedia + '1x1.gif';
this.config_['cssCollapsedFolderIcon'] =
'blocklyTreeIconClosed' + (workspace.RTL ? 'Rtl' : 'Ltr');
var tree = new Blockly.tree.TreeControl(this, this.config_);
var tree = new Blockly.tree.TreeControl(this,
/** @type {!Blockly.tree.BaseNode.Config} */ (this.config_));
this.tree_ = tree;
tree.setSelectedItem(null);
tree.onBeforeSelected(this.handleBeforeTreeSelected_);
tree.onAfterSelected(this.handleAfterTreeSelected_);
var openNode = this.populate_(workspace.options.languageTree);
var openNode = null;
if (workspace.options.languageTree) {
openNode = this.populate_(workspace.options.languageTree);
}
tree.render(this.HtmlDiv);
if (openNode) {
tree.setSelectedItem(openNode);
@@ -214,7 +219,7 @@ Blockly.Toolbox.prototype.init = function() {
// Trees have an implicit orientation of vertical, so we only need to set this
// when the toolbox is in horizontal mode.
if (this.horizontalLayout_) {
Blockly.utils.aria.setState(this.tree_.getElement(),
Blockly.utils.aria.setState(/** @type {!Element} */ (this.tree_.getElement()),
Blockly.utils.aria.State.ORIENTATION, 'horizontal');
}
};
@@ -281,6 +286,32 @@ Blockly.Toolbox.prototype.handleNodeSizeChanged_ = function() {
Blockly.svgResize(this.workspace_);
};
/**
* Handles the given Blockly action on a toolbox.
* This is only triggered when keyboard accessibility mode is enabled.
* @param {!Blockly.Action} action The action to be handled.
* @return {boolean} True if the field handled the action, false otherwise.
* @package
*/
Blockly.Toolbox.prototype.onBlocklyAction = function(action) {
var selected = this.tree_.getSelectedItem();
if (!selected) {
return false;
}
switch (action.name) {
case Blockly.navigation.actionNames.PREVIOUS:
return selected.selectPrevious();
case Blockly.navigation.actionNames.OUT:
return selected.selectParent();
case Blockly.navigation.actionNames.NEXT:
return selected.selectNext();
case Blockly.navigation.actionNames.IN:
return selected.selectChild();
default:
return false;
}
};
/**
* Dispose of this toolbox.
*/
@@ -344,7 +375,7 @@ Blockly.Toolbox.prototype.position = function() {
/**
* Fill the toolbox with categories and blocks.
* @param {!Node} newTree DOM tree of blocks.
* @return {Node} Tree node to open at startup (or null).
* @return {Blockly.tree.BaseNode} Tree node to open at startup (or null).
* @private
*/
Blockly.Toolbox.prototype.populate_ = function(newTree) {
@@ -370,7 +401,7 @@ Blockly.Toolbox.prototype.populate_ = function(newTree) {
* @param {!Blockly.tree.BaseNode} treeOut The TreeControl or TreeNode
* object built from treeIn.
* @param {string} pathToMedia The path to the Blockly media directory.
* @return {Node} Tree node to open at startup (or null).
* @return {Blockly.tree.BaseNode} Tree node to open at startup (or null).
* @private
*/
Blockly.Toolbox.prototype.syncTrees_ = function(treeIn, treeOut, pathToMedia) {
@@ -432,7 +463,7 @@ Blockly.Toolbox.prototype.syncTrees_ = function(treeIn, treeOut, pathToMedia) {
// Separator between two categories.
// <sep></sep>
treeOut.add(new Blockly.Toolbox.TreeSeparator(
this.treeSeparatorConfig_));
/** @type {!Blockly.tree.BaseNode.Config} */ (this.treeSeparatorConfig_)));
break;
}
// Otherwise falls through.
@@ -648,9 +679,20 @@ Blockly.Toolbox.prototype.refreshSelection = function() {
}
};
/**
* Select the first toolbox category if no category is selected.
* @package
*/
Blockly.Toolbox.prototype.selectFirstCategory = function() {
var selectedItem = this.tree_.getSelectedItem();
if (!selectedItem) {
this.tree_.selectFirst();
}
};
/**
* A blank separator node in the tree.
* @param {Blockly.tree.BaseNode.Config} config The configuration for the tree.
* @param {!Blockly.tree.BaseNode.Config} config The configuration for the tree.
* @constructor
* @extends {Blockly.tree.TreeNode}
*/

View File

@@ -1,4 +1,40 @@
/**
* @license
* Visual Blocks Editor
*
* Copyright 2019 Google Inc.
* https://developers.google.com/blockly/
*
* 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 Navigation tests.
* @author aschmiedt@google.com (Abby Schmiedt)
*/
'use strict';
suite('Navigation', function() {
function createNavigationWorkspace(enableKeyboardNav) {
var toolbox = document.getElementById('toolbox-categories');
var workspace = Blockly.inject('blocklyDiv', {toolbox: toolbox});
if (enableKeyboardNav) {
Blockly.navigation.enableKeyboardAccessibility();
Blockly.navigation.currentState_ = Blockly.navigation.STATE_WS;
}
return workspace;
}
// Test that toolbox key handlers call through to the right functions and
// transition correctly between toolbox, workspace, and flyout.
@@ -15,8 +51,7 @@ suite('Navigation', function() {
}
]
}]);
var toolbox = document.getElementById('toolbox-categories');
this.workspace = Blockly.inject('blocklyDiv', {toolbox: toolbox});
this.workspace = createNavigationWorkspace(true);
Blockly.navigation.focusToolbox_();
this.mockEvent = {
getModifierState: function() {
@@ -31,7 +66,6 @@ suite('Navigation', function() {
teardown(function() {
delete Blockly.Blocks['basic_block'];
this.workspace.dispose();
Blockly.navigation.currentCategory_ = null;
});
test('Next', function() {
@@ -39,43 +73,45 @@ suite('Navigation', function() {
chai.assert.isTrue(Blockly.navigation.onKeyPress(this.mockEvent));
chai.assert.equal(Blockly.navigation.currentState_,
Blockly.navigation.STATE_TOOLBOX);
chai.assert.equal(Blockly.navigation.currentCategory_,
chai.assert.equal(this.workspace.getToolbox().tree_.getSelectedItem(),
this.secondCategory_);
});
// Should be a no-op.
test('Next at end', function() {
Blockly.navigation.nextCategory_();
this.workspace.getToolbox().tree_.getSelectedItem().selectNext();
this.mockEvent.keyCode = Blockly.utils.KeyCodes.S;
var startCategory = Blockly.navigation.currentCategory_;
// Go forward one so that we can go back one.
Blockly.navigation.onKeyPress(this.mockEvent);
var startCategory = this.workspace.getToolbox().tree_.getSelectedItem();
chai.assert.isTrue(Blockly.navigation.onKeyPress(this.mockEvent));
chai.assert.equal(Blockly.navigation.currentState_,
Blockly.navigation.STATE_TOOLBOX);
chai.assert.equal(Blockly.navigation.currentCategory_,
chai.assert.equal(this.workspace.getToolbox().tree_.getSelectedItem(),
startCategory);
});
test('Previous', function() {
// Go forward one so that we can go back one:
Blockly.navigation.nextCategory_();
this.workspace.getToolbox().tree_.getSelectedItem().selectNext();
this.mockEvent.keyCode = Blockly.utils.KeyCodes.W;
chai.assert.equal(Blockly.navigation.currentCategory_,
chai.assert.equal(this.workspace.getToolbox().tree_.getSelectedItem(),
this.secondCategory_);
chai.assert.isTrue(Blockly.navigation.onKeyPress(this.mockEvent));
chai.assert.equal(Blockly.navigation.currentState_,
Blockly.navigation.STATE_TOOLBOX);
chai.assert.equal(Blockly.navigation.currentCategory_,
chai.assert.equal(this.workspace.getToolbox().tree_.getSelectedItem(),
this.firstCategory_);
});
// Should be a no-op.
test('Previous at start', function() {
var startCategory = Blockly.navigation.currentCategory_;
var startCategory = this.workspace.getToolbox().tree_.getSelectedItem();
this.mockEvent.keyCode = Blockly.utils.KeyCodes.W;
chai.assert.isTrue(Blockly.navigation.onKeyPress(this.mockEvent));
chai.assert.equal(Blockly.navigation.currentState_,
Blockly.navigation.STATE_TOOLBOX);
chai.assert.equal(Blockly.navigation.currentCategory_,
chai.assert.equal(this.workspace.getToolbox().tree_.getSelectedItem(),
startCategory);
});
@@ -132,8 +168,7 @@ suite('Navigation', function() {
}
]
}]);
var toolbox = document.getElementById('toolbox-categories');
this.workspace = Blockly.inject('blocklyDiv', {toolbox: toolbox});
this.workspace = createNavigationWorkspace(true);
Blockly.navigation.focusToolbox_();
Blockly.navigation.focusFlyout_();
this.mockEvent = {
@@ -146,7 +181,6 @@ suite('Navigation', function() {
teardown(function() {
delete Blockly.Blocks['basic_block'];
this.workspace.dispose();
Blockly.navigation.currentCategory_ = null;
});
// Should be a no-op
@@ -225,9 +259,7 @@ suite('Navigation', function() {
"previousStatement": null,
"nextStatement": null
}]);
var toolbox = document.getElementById('toolbox-categories');
this.workspace = Blockly.inject('blocklyDiv', {toolbox: toolbox});
Blockly.navigation.enableKeyboardAccessibility();
this.workspace = createNavigationWorkspace(true);
this.basicBlock = this.workspace.newBlock('basic_block');
this.firstCategory_ = this.workspace.getToolbox().tree_.firstChild_;
this.mockEvent = {
@@ -240,7 +272,6 @@ suite('Navigation', function() {
teardown(function() {
delete Blockly.Blocks['basic_block'];
this.workspace.dispose();
Blockly.navigation.currentCategory_ = null;
});
test('Previous', function() {
@@ -310,7 +341,7 @@ suite('Navigation', function() {
test('Toolbox', function() {
this.mockEvent.keyCode = Blockly.utils.KeyCodes.T;
chai.assert.isTrue(Blockly.navigation.onKeyPress(this.mockEvent));
chai.assert.equal(Blockly.navigation.currentCategory_, this.firstCategory_);
chai.assert.equal(this.workspace.getToolbox().tree_.getSelectedItem(), this.firstCategory_);
chai.assert.equal(Blockly.navigation.currentState_,
Blockly.navigation.STATE_TOOLBOX);
});
@@ -322,6 +353,7 @@ suite('Navigation', function() {
Blockly.user.keyMap.setKeyMap(Blockly.user.keyMap.createDefaultKeyMap());
Blockly.mainWorkspace = this.workspace;
Blockly.keyboardAccessibilityMode = true;
Blockly.navigation.currentState_ = Blockly.navigation.STATE_WS;
this.mockEvent = {
getModifierState: function() {
@@ -330,7 +362,9 @@ 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);
sinon.spy(field, 'onBlocklyAction');
this.workspace.getCursor().setCurNode(Blockly.ASTNode.createFieldNode(field));
@@ -343,7 +377,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);
sinon.stub(field, 'onBlocklyAction').callsFake(function(){
return true;
});
@@ -357,7 +393,9 @@ 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);
sinon.spy(field, 'onBlocklyAction');
this.workspace.getCursor().setCurNode(Blockly.ASTNode.createFieldNode(field));
@@ -424,8 +462,10 @@ suite('Navigation', function() {
this.workspace = new Blockly.Workspace({readOnly: true});
this.workspace.setCursor(new Blockly.Cursor());
Blockly.mainWorkspace = this.workspace;
this.fieldBlock1 = this.workspace.newBlock('field_block');
Blockly.keyboardAccessibilityMode = true;
Blockly.navigation.currentState_ = Blockly.navigation.STATE_WS;
this.fieldBlock1 = this.workspace.newBlock('field_block');
this.mockEvent = {
getModifierState: function() {
return false;
@@ -435,7 +475,6 @@ suite('Navigation', function() {
teardown(function() {
delete Blockly.Blocks['field_block'];
Blockly.mainWorkspace = null;
this.workspace.dispose();
});
@@ -472,8 +511,7 @@ suite('Navigation', function() {
"nextStatement": null,
}]);
var toolbox = document.getElementById('toolbox-categories');
this.workspace = Blockly.inject('blocklyDiv', {toolbox: toolbox});
this.workspace = createNavigationWorkspace(true);
var basicBlock = this.workspace.newBlock('basic_block');
var basicBlock2 = this.workspace.newBlock('basic_block');
@@ -485,7 +523,6 @@ suite('Navigation', function() {
teardown(function() {
delete Blockly.Blocks['basic_block'];
this.workspace.dispose();
Blockly.navigation.currentCategory_ = null;
});
test('Insert from flyout with a valid connection marked', function() {
@@ -562,8 +599,7 @@ suite('Navigation', function() {
"helpUrl": ""
}]);
var toolbox = document.getElementById('toolbox-categories');
this.workspace = Blockly.inject('blocklyDiv', {toolbox: toolbox});
this.workspace = createNavigationWorkspace(true);
var basicBlock = this.workspace.newBlock('basic_block');
var basicBlock2 = this.workspace.newBlock('basic_block');
@@ -592,7 +628,6 @@ suite('Navigation', function() {
teardown(function() {
delete Blockly.Blocks['basic_block'];
this.workspace.dispose();
Blockly.navigation.currentCategory_ = null;
});
test('Connect cursor on previous into stack', function() {
@@ -655,9 +690,7 @@ suite('Navigation', function() {
"previousStatement": null,
"nextStatement": null,
}]);
var toolbox = document.getElementById('toolbox-categories');
this.workspace = Blockly.inject('blocklyDiv', {toolbox: toolbox});
Blockly.navigation.enableKeyboardAccessibility();
this.workspace = createNavigationWorkspace(true);
this.basicBlockA = this.workspace.newBlock('basic_block');
this.basicBlockB = this.workspace.newBlock('basic_block');
});

View File

@@ -19,7 +19,7 @@
*/
goog.require('Blockly.Blocks.procedures');
goog.require('Blockly.Msg.en');
goog.require('Blockly.Msg');
suite('Procedures XML', function() {
suite('Deserialization', function() {