From 602c1ba56e6fdf680f83a26e1cf823a9a0f44658 Mon Sep 17 00:00:00 2001 From: Sean Lip Date: Thu, 17 Nov 2016 17:45:12 -0800 Subject: [PATCH] Delete the on-screen toolbox. --- accessible/app.component.js | 7 +- accessible/media/accessible.css | 6 +- accessible/messages.js | 2 - accessible/toolbox-tree.component.js | 169 --------------------------- accessible/toolbox.component.js | 133 --------------------- accessible/tree.service.js | 116 ++++-------------- accessible/utils.service.js | 7 +- demos/accessible/index.html | 17 +-- 8 files changed, 35 insertions(+), 422 deletions(-) delete mode 100644 accessible/toolbox-tree.component.js delete mode 100644 accessible/toolbox.component.js diff --git a/accessible/app.component.js b/accessible/app.component.js index 9d8e7e494..9b453bfa4 100644 --- a/accessible/app.component.js +++ b/accessible/app.component.js @@ -36,20 +36,17 @@ blocklyApp.AppView = ng.core.Component({
-
- `, 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: ` -
  • - -
      -
    1. - -
    2. -
    3. - -
    4. -
    -
  • - `, - 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: ` -
    -

    {{'TOOLBOX'|translate}}

    -
      - - -
      - - -
      -
    -
    - `, - 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. +