-
`,
directives: [
- blocklyApp.ToolboxComponent, blocklyApp.WorkspaceComponent,
- blocklyApp.BlockOptionsModalComponent, blocklyApp.SidebarComponent,
- blocklyApp.ToolboxModalComponent],
+ blocklyApp.WorkspaceComponent, blocklyApp.BlockOptionsModalComponent,
+ blocklyApp.SidebarComponent, blocklyApp.ToolboxModalComponent],
pipes: [blocklyApp.TranslatePipe],
// All services are declared here, so that all components in the
// application use the same instance of the service.
diff --git a/accessible/media/accessible.css b/accessible/media/accessible.css
index d068253bf..70c88815a 100644
--- a/accessible/media/accessible.css
+++ b/accessible/media/accessible.css
@@ -1,10 +1,6 @@
-.blocklyToolboxColumn {
- float: left;
- width: 350px;
-}
.blocklyWorkspaceColumn {
float: left;
- width: 350px;
+ width: 700px;
}
.blocklySidebarColumn {
float: left;
diff --git a/accessible/messages.js b/accessible/messages.js
index aae6d34c4..4fe8e6b8a 100644
--- a/accessible/messages.js
+++ b/accessible/messages.js
@@ -24,9 +24,7 @@
*/
'use strict';
-Blockly.Msg.TOOLBOX = 'Toolbox';
Blockly.Msg.WORKSPACE = 'Workspace';
-Blockly.Msg.TOOLBOX_BLOCK = 'toolbox block. Move right to view submenu.';
Blockly.Msg.WORKSPACE_BLOCK =
'workspace block. Move right to edit. Press Enter for more options.';
diff --git a/accessible/toolbox-tree.component.js b/accessible/toolbox-tree.component.js
deleted file mode 100644
index 682695811..000000000
--- a/accessible/toolbox-tree.component.js
+++ /dev/null
@@ -1,169 +0,0 @@
-/**
- * AccessibleBlockly
- *
- * Copyright 2016 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 Angular2 Component that details how blocks are
- * rendered in the toolbox in AccessibleBlockly. Also handles any interactions
- * with the blocks.
- * @author madeeha@google.com (Madeeha Ghori)
- */
-
-blocklyApp.ToolboxTreeComponent = ng.core.Component({
- selector: 'blockly-toolbox-tree',
- template: `
-
-
-
-
-
-
-
-
-
-
-
- `,
- directives: [ng.core.forwardRef(function() {
- return blocklyApp.ToolboxTreeComponent;
- })],
- inputs: [
- 'block', 'displayBlockMenu', 'level', 'tree', 'isFirstToolboxTree'],
- pipes: [blocklyApp.TranslatePipe]
-})
-.Class({
- constructor: [
- blocklyApp.ClipboardService, blocklyApp.NotificationsService,
- blocklyApp.TreeService, blocklyApp.UtilsService,
- function(
- _clipboardService, _notificationsService,
- _treeService, _utilsService) {
- this.clipboardService = _clipboardService;
- this.notificationsService = _notificationsService;
- this.treeService = _treeService;
- this.utilsService = _utilsService;
- }],
- ngOnInit: function() {
- var idKeys = ['toolboxBlockRoot', 'toolboxBlockSummary'];
- if (this.displayBlockMenu) {
- idKeys = idKeys.concat([
- 'workspaceCopy', 'workspaceCopyButton', 'sendToSelected',
- 'sendToSelectedButton', 'blockCopy', 'blockCopyButton']);
- }
-
- this.idMap = {};
- for (var i = 0; i < idKeys.length; i++) {
- this.idMap[idKeys[i]] = this.block.id + idKeys[i];
- }
- },
- ngAfterViewInit: function() {
- // If this is the first tree in the category-less toolbox, set its active
- // descendant after the ids have been computed.
- // Note that a timeout is needed here in order to trigger Angular
- // change detection.
- if (this.isFirstToolboxTree) {
- var that = this;
- setTimeout(function() {
- that.treeService.setActiveDesc(
- that.idMap['toolboxBlockRoot'], 'blockly-toolbox-tree');
- });
- }
- },
- getAriaLabelForCopyToMarkedSpotButton: function() {
- // TODO(sll): Find a way to make this more like the other buttons.
- var ariaLabel = 'Attach to link button';
- if (!this.clipboardService.isAnyConnectionMarked()) {
- ariaLabel += ', unavailable. Add a link in the workspace first.';
- }
- return ariaLabel;
- },
- isWorkspaceEmpty: function() {
- return this.utilsService.isWorkspaceEmpty();
- },
- getBlockDescription: function() {
- return this.utilsService.getBlockDescription(this.block);
- },
- generateAriaLabelledByAttr: function(mainLabel, secondLabel) {
- return this.utilsService.generateAriaLabelledByAttr(
- mainLabel, secondLabel);
- },
- canBeCopiedToMarkedConnection: function() {
- return this.clipboardService.canBeCopiedToMarkedConnection(this.block);
- },
- copyToClipboard: function() {
- this.clipboardService.copy(this.block);
- this.notificationsService.setStatusMessage(
- this.getBlockDescription() + ' ' + Blockly.Msg.COPIED_BLOCK_MSG);
- },
- copyToWorkspace: function() {
- var blockDescription = this.getBlockDescription();
- var xml = Blockly.Xml.blockToDom(this.block);
- var newBlockId = Blockly.Xml.domToBlock(blocklyApp.workspace, xml).id;
-
- var that = this;
- setTimeout(function() {
- that.treeService.focusOnBlock(newBlockId);
- that.notificationsService.setStatusMessage(
- blockDescription + ' added to workspace. ' +
- 'Now on added block in workspace.');
- });
- },
- copyToMarkedSpot: function() {
- var blockDescription = this.getBlockDescription();
- // Clean up the active desc for the destination tree.
- var oldDestinationTreeId = this.treeService.getTreeIdForBlock(
- this.clipboardService.getMarkedConnectionBlock().id);
- this.treeService.clearActiveDesc(oldDestinationTreeId);
-
- var newBlockId = this.clipboardService.pasteToMarkedConnection(
- this.block);
-
- // Invoke a digest cycle, so that the DOM settles.
- var that = this;
- setTimeout(function() {
- that.treeService.focusOnBlock(newBlockId);
-
- var newDestinationTreeId = that.treeService.getTreeIdForBlock(
- newBlockId);
- if (newDestinationTreeId != oldDestinationTreeId) {
- // It is possible for the tree ID for the pasted block to change
- // after the paste operation, e.g. when inserting a block between two
- // existing blocks that are joined together. In this case, we need to
- // also reset the active desc for the old destination tree.
- that.treeService.initActiveDesc(oldDestinationTreeId);
- }
-
- that.notificationsService.setStatusMessage(
- blockDescription + ' connected. ' +
- 'Now on copied block in workspace.');
- });
- }
-});
diff --git a/accessible/toolbox.component.js b/accessible/toolbox.component.js
deleted file mode 100644
index 0a72cb99e..000000000
--- a/accessible/toolbox.component.js
+++ /dev/null
@@ -1,133 +0,0 @@
-/**
- * AccessibleBlockly
- *
- * Copyright 2016 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 Angular2 Component that details how a toolbox is rendered
- * in AccessibleBlockly. Also handles any interactions with the toolbox.
- *
- * @author madeeha@google.com (Madeeha Ghori)
- */
-
-blocklyApp.ToolboxComponent = ng.core.Component({
- selector: 'blockly-toolbox',
- template: `
-
- `,
- directives: [blocklyApp.ToolboxTreeComponent],
- pipes: [blocklyApp.TranslatePipe]
-})
-.Class({
- constructor: [
- blocklyApp.TreeService, blocklyApp.UtilsService,
- function(_treeService, _utilsService) {
- this.toolboxCategories = [];
- this.treeService = _treeService;
- this.utilsService = _utilsService;
-
- this.xmlHasCategories = false;
- }
- ],
- ngOnInit: function() {
- // Note that sometimes the toolbox may not have categories; it may
- // display individual blocks directly (which is often the case in,
- // e.g., Blockly Games).
- var xmlToolboxElt = document.getElementById('blockly-toolbox-xml');
- var xmlCategoryElts = xmlToolboxElt.getElementsByTagName('category');
- if (xmlCategoryElts.length) {
- this.xmlHasCategories = true;
- this.toolboxCategories = Array.from(xmlCategoryElts);
-
- var elementsNeedingIds = [];
- for (var i = 0; i < this.toolboxCategories.length; i++) {
- elementsNeedingIds.push('Parent' + i, 'Label' + i);
- }
- this.idMap = this.utilsService.generateIds(elementsNeedingIds);
- for (var i = 0; i < this.toolboxCategories.length; i++) {
- this.idMap['Parent' + i] = 'blockly-toolbox-tree-node' + i;
- }
- } else {
- // Create a single category with all the top-level blocks.
- this.xmlHasCategories = false;
- this.toolboxCategories = [Array.from(xmlToolboxElt.children)];
- }
- },
- ngAfterViewInit: function() {
- // If this is a top-level tree in the toolbox, set its active
- // descendant after the ids have been computed.
- // Note that a timeout is needed here in order to trigger Angular
- // change detection.
- if (this.xmlHasCategories) {
- var that = this;
- setTimeout(function() {
- that.treeService.setActiveDesc(
- 'blockly-toolbox-tree-node0', 'blockly-toolbox-tree');
- });
- }
- },
- getActiveDescId: function() {
- return this.treeService.getActiveDescId('blockly-toolbox-tree');
- },
- getCategoryAriaLabel: function(category) {
- var numBlocks = this.getToolboxWorkspace(category).topBlocks_.length;
- return category.attributes.name.value + ' category. ' +
- 'Move right to access ' + numBlocks + ' blocks in this category.';
- },
- getToolboxWorkspace: function(categoryNode) {
- return this.treeService.getToolboxWorkspace(categoryNode);
- }
-});
diff --git a/accessible/tree.service.js b/accessible/tree.service.js
index 39df6948a..357a1711b 100644
--- a/accessible/tree.service.js
+++ b/accessible/tree.service.js
@@ -39,12 +39,8 @@ blocklyApp.TreeService = ng.core.Class({
this.clipboardService = _clipboardService;
this.blockOptionsModalService = _blockOptionsModalService;
this.audioService = _audioService;
- this.toolboxWorkspaces = {};
}
],
- getToolboxTreeNode_: function() {
- return document.getElementById('blockly-toolbox-tree');
- },
// Returns a list of all top-level workspace tree nodes on the page.
getWorkspaceTreeNodes_: function() {
return Array.from(document.querySelectorAll('ol.blocklyWorkspaceTree'));
@@ -52,45 +48,10 @@ blocklyApp.TreeService = ng.core.Class({
getSidebarButtonNodes_: function() {
return Array.from(document.querySelectorAll('button.blocklySidebarButton'));
},
- getToolboxWorkspace: function(categoryNode) {
- if (categoryNode.attributes && categoryNode.attributes.name) {
- var categoryName = categoryNode.attributes.name.value;
- } else {
- var categoryName = 'no-category';
- }
-
- if (this.toolboxWorkspaces.hasOwnProperty(categoryName)) {
- return this.toolboxWorkspaces[categoryName];
- } else {
- var categoryWorkspace = new Blockly.Workspace();
- if (categoryName == 'no-category') {
- for (var i = 0; i < categoryNode.length; i++) {
- Blockly.Xml.domToBlock(categoryWorkspace, categoryNode[i]);
- }
- } else {
- Blockly.Xml.domToWorkspace(categoryNode, categoryWorkspace);
- }
-
- this.toolboxWorkspaces[categoryName] = categoryWorkspace;
- return this.toolboxWorkspaces[categoryName];
- }
- },
- getToolboxBlockById: function(blockId) {
- for (var categoryName in this.toolboxWorkspaces) {
- var putativeBlock = this.utilsService.getBlockByIdFromWorkspace(
- blockId, this.toolboxWorkspaces[categoryName]);
- if (putativeBlock) {
- return putativeBlock;
- }
- }
- return null;
- },
// Returns a list of all top-level tree nodes on the page.
getAllTreeNodes_: function() {
- var treeNodes = [this.getToolboxTreeNode_()];
- treeNodes = treeNodes.concat(this.getWorkspaceTreeNodes_());
- treeNodes = treeNodes.concat(this.getSidebarButtonNodes_());
- return treeNodes;
+ return this.getWorkspaceTreeNodes_().concat(
+ this.getSidebarButtonNodes_());
},
isTopLevelWorkspaceTree: function(treeId) {
return this.getWorkspaceTreeNodes_().some(function(tree) {
@@ -99,20 +60,15 @@ blocklyApp.TreeService = ng.core.Class({
},
getNodeToFocusOnWhenTreeIsDeleted: function(deletedTreeId) {
// This returns the node to focus on after the deletion happens.
- // We shift focus to the next tree (if it exists), otherwise we shift
- // focus to the previous tree.
+ // We shift focus to the next tree (which may be a button in the sidebar).
var trees = this.getAllTreeNodes_();
for (var i = 0; i < trees.length; i++) {
if (trees[i].id == deletedTreeId) {
if (i + 1 < trees.length) {
return trees[i + 1];
- } else if (i > 0) {
- return trees[i - 1];
}
}
}
-
- return this.getToolboxTreeNode_();
},
focusOnCurrentTree_: function(treeId) {
var trees = this.getAllTreeNodes_();
@@ -268,16 +224,12 @@ blocklyApp.TreeService = ng.core.Class({
console.error('Could not handle deletion of block.' + blockRootNode);
},
notifyUserAboutCurrentTree_: function(treeId) {
- if (this.getToolboxTreeNode_().id == treeId) {
- this.notificationsService.setStatusMessage('Now in toolbox.');
- } else {
- var workspaceTreeNodes = this.getWorkspaceTreeNodes_();
- for (var i = 0; i < workspaceTreeNodes.length; i++) {
- if (workspaceTreeNodes[i].id == treeId) {
- this.notificationsService.setStatusMessage(
- 'Now in workspace group ' + (i + 1) + ' of ' +
- workspaceTreeNodes.length);
- }
+ var workspaceTreeNodes = this.getWorkspaceTreeNodes_();
+ for (var i = 0; i < workspaceTreeNodes.length; i++) {
+ if (workspaceTreeNodes[i].id == treeId) {
+ this.notificationsService.setStatusMessage(
+ 'Now in workspace group ' + (i + 1) + ' of ' +
+ workspaceTreeNodes.length);
}
}
},
@@ -444,26 +396,24 @@ blocklyApp.TreeService = ng.core.Class({
that.focusOnBlock(block.id);
});
},
- getBlockRootSuffix_: function(inToolbox) {
- return inToolbox ? 'toolboxBlockRoot' : 'blockRoot';
+ getBlockRootSuffix_: function() {
+ return 'blockRoot';
},
- getCurrentBlockRootNode_: function(inToolbox, activeDesc) {
+ getCurrentBlockRootNode_: function(activeDesc) {
// Starting from the activeDesc, walk up the tree until we find the
// root of the current block.
- var blockRootSuffix = this.getBlockRootSuffix_(inToolbox);
+ var blockRootSuffix = this.getBlockRootSuffix_();
var putativeBlockRootNode = activeDesc;
while (putativeBlockRootNode.id.indexOf(blockRootSuffix) === -1) {
putativeBlockRootNode = putativeBlockRootNode.parentNode;
}
return putativeBlockRootNode;
},
- getBlockFromRootNode_: function(inToolbox, blockRootNode) {
- var blockRootSuffix = this.getBlockRootSuffix_(inToolbox);
+ getBlockFromRootNode_: function(blockRootNode) {
+ var blockRootSuffix = this.getBlockRootSuffix_();
var blockId = blockRootNode.id.substring(
0, blockRootNode.id.length - blockRootSuffix.length);
- return inToolbox ?
- this.getToolboxBlockById(blockId) :
- this.utilsService.getBlockById(blockId);
+ return this.utilsService.getBlockById(blockId);
},
onKeypress: function(e, tree) {
// TODO(sll): Instead of this, have a common ActiveContextService which
@@ -485,36 +435,15 @@ blocklyApp.TreeService = ng.core.Class({
return;
}
- // Scout up the tree to see whether we're in the toolbox or workspace.
- var scoutNode = activeDesc;
- var TARGET_TAG_NAMES = ['BLOCKLY-TOOLBOX', 'BLOCKLY-WORKSPACE'];
- while (TARGET_TAG_NAMES.indexOf(scoutNode.tagName) === -1) {
- scoutNode = scoutNode.parentNode;
- }
- var inToolbox = (scoutNode.tagName == 'BLOCKLY-TOOLBOX');
-
if (e.ctrlKey) {
- // Disallow cutting and pasting in the toolbox.
- if (inToolbox && e.keyCode != 67) {
- if (e.keyCode == 86) {
- this.notificationsService.setStatusMessage(
- 'Cannot paste block in toolbox.');
- } else if (e.keyCode == 88) {
- this.notificationsService.setStatusMessage(
- 'Cannot cut block in toolbox. Try copying instead.');
- }
- }
-
- var blockRootNode = this.getCurrentBlockRootNode_(
- inToolbox, activeDesc);
- var block = this.getBlockFromRootNode_(inToolbox, blockRootNode);
+ var blockRootNode = this.getCurrentBlockRootNode_(activeDesc);
+ var block = this.getBlockFromRootNode_(blockRootNode);
if (e.keyCode == 88) {
// Cut block.
this.cutBlock_(block, blockRootNode);
} else if (e.keyCode == 67) {
- // Copy block. Note that, in this case, we might be in the workspace
- // or toolbox.
+ // Copy block.
this.copyBlock_(block);
} else if (e.keyCode == 86) {
// Paste block, if possible.
@@ -582,10 +511,9 @@ blocklyApp.TreeService = ng.core.Class({
// If we cannot find a field to interact with, we open the modal for
// the current block instead.
- if (!found && !inToolbox) {
- var blockRootNode = this.getCurrentBlockRootNode_(
- false, activeDesc);
- var block = this.getBlockFromRootNode_(false, blockRootNode);
+ if (!found) {
+ var blockRootNode = this.getCurrentBlockRootNode_(activeDesc);
+ var block = this.getBlockFromRootNode_(blockRootNode);
e.stopPropagation();
this.showBlockOptionsModal(block, blockRootNode);
diff --git a/accessible/utils.service.js b/accessible/utils.service.js
index fec1ffa9f..e6311cc10 100644
--- a/accessible/utils.service.js
+++ b/accessible/utils.service.js
@@ -67,11 +67,6 @@ blocklyApp.UtilsService = ng.core.Class({
return !blocklyApp.workspace.topBlocks_.length;
},
getBlockById: function(blockId) {
- return this.getBlockByIdFromWorkspace(blockId, blocklyApp.workspace);
- },
- getBlockByIdFromWorkspace: function(blockId, workspace) {
- // This is used for non-default workspaces, such as those comprising the
- // toolbox.
- return workspace.getBlockById(blockId);
+ return blocklyApp.workspace.getBlockById(blockId);
}
});
diff --git a/demos/accessible/index.html b/demos/accessible/index.html
index ae0d20cd5..4e7205fda 100644
--- a/demos/accessible/index.html
+++ b/demos/accessible/index.html
@@ -31,8 +31,6 @@
-
-
@@ -60,13 +58,16 @@
Demos > Accessible Blockly
-
This is a simple demo of a version of Blockly designed for screen readers.
-
- In Blockly, you can move blocks from the toolbox to the workspace and join
- them to create programs. To navigate between components, use Tab or
- Shift-Tab. When you're on a block, move right to access its submenus, and
- move up or down to go to the next or previous block in the sequence.
+ This is a demo of a version of Blockly designed for screen readers. It
+ allows users to create programs in a workspace by manipulating groups of
+ blocks.
+
+
To explore a group of blocks, use the arrow keys.
+
To navigate between groups, use Tab or Shift-Tab.
+
To add new blocks, use the buttons in the menu on the right.
+
To delete or add links to existing blocks, press Enter while you're on that block.