Fix tree focus issues.

This commit is contained in:
Sean Lip
2016-06-16 14:52:38 -07:00
parent 6c13b5c81b
commit 019082b795
4 changed files with 78 additions and 59 deletions

View File

@@ -63,10 +63,5 @@ blocklyApp.AppView = ng.core
blocklyApp.UtilsService]
})
.Class({
constructor: [blocklyApp.TreeService, function(_treeService) {
this.treeService = _treeService;
}],
ngAfterViewInit: function() {
this.treeService.initTreeRegistry();
}
constructor: [function() {}]
});

View File

@@ -27,8 +27,6 @@
blocklyApp.TreeService = ng.core
.Class({
constructor: function() {
// A list of all trees in the application.
this.treeRegistry = [];
// Keeping track of the last key pressed. If the user presses
// enter (to edit a text input or press a button), the keyboard
// focus shifts to that element. In the next keystroke, if the user
@@ -36,52 +34,66 @@ blocklyApp.TreeService = ng.core
// to shift focus back to the tree as a whole.
this.previousKey_ = null;
},
initTreeRegistry: function() {
this.treeRegistry = [];
this.treeRegistry.push(document.getElementById('blockly-toolbox-tree'));
// TODO(sll): Extend this to handle injected toolbar buttons.
this.treeRegistry.push(document.getElementById('clear-workspace'));
// Focus on the toolbox tree.
this.treeRegistry[0].focus();
getToolboxTreeNode_: function() {
return document.getElementById('blockly-toolbox-tree');
},
isTreeInRegistry: function(treeId) {
return this.treeRegistry.some(function(tree) {
getWorkspaceTreeNodes_: function() {
// Returns a list of all the top-level workspace tree nodes on the page.
return Array.from(document.querySelectorAll('ol.blocklyWorkspaceTree'));
},
getAllTreeNodes_: function() {
// Returns a list of all top-level tree nodes on the page.
var trees = [];
trees.push(document.getElementById('blockly-toolbox-tree'));
// TODO(sll): Extend this to handle injected toolbar buttons.
if (blocklyApp.workspace.topBlocks_.length > 0) {
trees.push(document.getElementById('clear-workspace'));
}
trees = trees.concat(this.getWorkspaceTreeNodes_());
return trees;
},
focusOnToolbox: function() {
this.getToolboxTreeNode_().focus();
},
isTopLevelWorkspaceTree: function(treeId) {
return this.getWorkspaceTreeNodes_().some(function(tree) {
return tree.id == treeId;
});
},
addTreeToRegistry: function(tree) {
this.treeRegistry.push(tree);
},
deleteTreeFromRegistry: function(treeId) {
// Shift focus to the next tree (if it exists), otherwise shift focus
// to the previous tree.
var movedToNextTree = this.goToNextTree(treeId);
if (!movedToNextTree) {
this.goToPreviousTree(treeId);
}
// Delete the tree from the tree registry.
for (var i = 0; i < this.treeRegistry.length; i++) {
if (this.treeRegistry[i].id == treeId) {
this.treeRegistry.splice(i, 1);
break;
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.
var workspaceTrees = this.getWorkspaceTreeNodes_();
for (var i = 0; i < workspaceTrees.length; i++) {
if (workspaceTrees[i].id == deletedTreeId) {
if (i + 1 < workspaceTrees.length) {
return workspaceTrees[i + 1];
} else if (i > 0) {
return workspaceTrees[i - 1];
}
}
}
return this.getToolboxTreeNode_();
},
goToNextTree: function(treeId) {
for (var i = 0; i < this.treeRegistry.length - 1; i++) {
if (this.treeRegistry[i].id == treeId) {
this.treeRegistry[i + 1].focus();
var trees = this.getAllTreeNodes_();
for (var i = 0; i < trees.length - 1; i++) {
if (trees[i].id == treeId) {
trees[i + 1].focus();
return true;
}
}
return false;
},
goToPreviousTree: function(treeId) {
for (var i = this.treeRegistry.length - 1; i > 0; i--) {
if (this.treeRegistry[i].id == treeId) {
this.treeRegistry[i - 1].focus();
var trees = this.getAllTreeNodes_();
for (var i = trees.length - 1; i > 0; i--) {
if (trees[i].id == treeId) {
trees[i - 1].focus();
return true;
}
}

View File

@@ -161,12 +161,12 @@ blocklyApp.WorkspaceTreeComponent = ng.core
this.idMap['parentList'] = this.utilsService.generateUniqueId();
},
ngAfterViewInit: function() {
// If this is a top-level tree in the workspace, add it to the tree
// registry and set its active descendant.
// If this is a top-level tree in the workspace, set its active
// descendant.
if (this.tree &&
(!this.tree.id || !this.treeService.isTreeInRegistry(this.tree.id))) {
(!this.tree.id ||
!this.treeService.isTopLevelWorkspaceTree(this.tree.id))) {
this.tree.id = this.utilsService.generateUniqueId();
this.treeService.addTreeToRegistry(this.tree);
this.treeService.setActiveDesc(
document.getElementById(this.idMap['parentList']),
this.tree);
@@ -183,18 +183,25 @@ blocklyApp.WorkspaceTreeComponent = ng.core
},
cutToClipboard: function(block) {
if (this.isTopLevelBlock(block)) {
this.treeService.deleteTreeFromRegistry(this.tree.id);
nextNodeToFocusOn = this.treeService.getNodeToFocusOnWhenTreeIsDeleted(
this.tree.id);
this.clipboardService.cut(block);
nextNodeToFocusOn.focus();
} else {
// TODO(sll): Change the active descendant of the tree.
this.clipboardService.cut(block);
}
this.clipboardService.cut(block);
},
deleteBlock: function(block, cutToClipboard) {
if (this.isTopLevelBlock(block)) {
this.treeService.deleteTreeFromRegistry(this.tree.id);
nextNodeToFocusOn = this.treeService.getNodeToFocusOnWhenTreeIsDeleted(
this.tree.id);
block.dispose(true);
nextNodeToFocusOn.focus();
} else {
// TODO(sll): Change the active descendant of the tree.
block.dispose(true);
}
// TODO(sll): Change the active descendant of the tree.
block.dispose(true);
},
generateAriaLabelledByAttr: function(mainLabel, secondLabel, isDisabled) {
return this.utilsService.generateAriaLabelledByAttr(
@@ -210,9 +217,14 @@ blocklyApp.WorkspaceTreeComponent = ng.core
this.clipboardService.pasteToMarkedConnection(block, false);
if (this.isTopLevelBlock(block)) {
this.treeService.deleteTreeFromRegistry(this.tree.id);
nextNodeToFocusOn = this.treeService.getNodeToFocusOnWhenTreeIsDeleted(
this.tree.id);
block.dispose(true);
nextNodeToFocusOn.focus();
} else {
// TODO(sll): Change the active descendant of the tree.
block.dispose(true);
}
block.dispose(true);
alert('Block moved to marked spot: ' + block.toString());
}

View File

@@ -45,7 +45,7 @@ blocklyApp.WorkspaceComponent = ng.core
<div *ngIf="workspace">
<ol #tree *ngFor="#block of workspace.topBlocks_; #i = index"
tabIndex="0" role="group" class="blocklyTree"
tabIndex="0" role="group" class="blocklyTree blocklyWorkspaceTree"
[attr.aria-labelledby]="workspaceTitle.id"
(keydown)="onKeypress($event, tree)">
<blockly-workspace-tree [level]=1 [block]="block" [tree]="tree">
@@ -71,14 +71,14 @@ blocklyApp.WorkspaceComponent = ng.core
}],
clearWorkspace: function() {
this.workspace.clear();
this.treeService.initTreeRegistry();
this.treeService.focusOnToolbox();
},
onWorkspaceToolbarKeypress: function(event) {
onWorkspaceToolbarKeypress: function(e) {
this.treeService.onWorkspaceToolbarKeypress(
event, document.activeElement.id);
e, document.activeElement.id);
},
onKeypress: function(event, tree){
this.treeService.onKeypress(event, tree);
onKeypress: function(e, tree) {
this.treeService.onKeypress(e, tree);
},
isWorkspaceEmpty: function() {
return !this.workspace.topBlocks_.length;