Make aria-levels 1-indexed. Allow pressing Enter to go down a level, and pressing Escape to go up a level. Add a guard against incorrect status message when reaching the top of the outermost level.

This commit is contained in:
Sean Lip 2016-09-29 15:31:13 -07:00
parent 48f181e1e3
commit 966cda6088
3 changed files with 40 additions and 21 deletions

View file

@ -40,7 +40,7 @@ blocklyApp.ToolboxComponent = ng.core
[id]="idMap['Parent' + i]" role="treeitem"
[ngClass]="{blocklyHasChildren: true, blocklyActiveDescendant: tree.getAttribute('aria-activedescendant') == idMap['Parent' + i]}"
*ngFor="#category of toolboxCategories; #i=index"
aria-level="1"
aria-level="0"
[attr.aria-label]="getCategoryAriaLabel(category)">
<div *ngIf="category && category.attributes">
<label [id]="idMap['Label' + i]" #name>
@ -48,7 +48,7 @@ blocklyApp.ToolboxComponent = ng.core
</label>
<ol role="group" *ngIf="getToolboxWorkspace(category).topBlocks_.length > 0">
<blockly-toolbox-tree *ngFor="#block of getToolboxWorkspace(category).topBlocks_"
[level]="2" [block]="block"
[level]="1" [block]="block"
[displayBlockMenu]="true"
[tree]="tree">
</blockly-toolbox-tree>
@ -59,7 +59,7 @@ blocklyApp.ToolboxComponent = ng.core
<div *ngIf="!xmlHasCategories">
<blockly-toolbox-tree *ngFor="#block of getToolboxWorkspace(toolboxCategories[0]).topBlocks_; #i=index"
role="treeitem" [level]="1" [block]="block"
role="treeitem" [level]="0" [block]="block"
[tree]="tree" [displayBlockMenu]="true"
[isFirstToolboxTree]="i === 0">
</blockly-toolbox-tree>

View file

@ -440,23 +440,26 @@ blocklyApp.TreeService = ng.core
// Outside an input field, Enter, Tab and navigation keys are all
// recognized.
if (e.keyCode == 13) {
// Enter key. The user wants to interact with a button or an input
// field.
// Enter key. The user wants to interact with a button, interact with
// an input field, or move down one level.
// Algorithm to find the field: do a DFS through the children until
// we find an INPUT or BUTTON element (in which case we use it).
// Truncate the search at child LI elements.
var found = false;
var dfsStack = Array.from(activeDesc.children);
while (dfsStack.length) {
var currentNode = dfsStack.shift();
if (currentNode.tagName == 'BUTTON') {
this.moveActiveDescToParent(treeId);
this.moveUpOneLevel_(treeId);
currentNode.click();
found = true;
break;
} else if (currentNode.tagName == 'INPUT') {
currentNode.focus();
currentNode.select();
this.notificationsService.setStatusMessage(
'Type a value, then press Escape to exit');
found = true;
break;
} else if (currentNode.tagName == 'LI') {
continue;
@ -469,6 +472,12 @@ blocklyApp.TreeService = ng.core
});
}
}
// If we cannot find a field to interact with, we try moving down a
// level instead.
if (!found) {
this.moveDownOneLevel_(treeId);
}
} else if (e.keyCode == 9) {
// Tab key. Note that allowing the event to propagate through is
// intentional.
@ -478,6 +487,8 @@ blocklyApp.TreeService = ng.core
if (destinationTreeId) {
this.notifyUserAboutCurrentTree_(destinationTreeId);
}
} else if (e.keyCode == 27) {
this.moveUpOneLevel_(treeId);
} else if (e.keyCode >= 35 && e.keyCode <= 40) {
// End, home, and arrow keys.
if (e.keyCode == 35) {
@ -494,22 +505,22 @@ blocklyApp.TreeService = ng.core
}
} else if (e.keyCode == 37) {
// Left arrow key. Go up a level, if possible.
this.moveActiveDescToParent(treeId);
this.moveUpOneLevel_(treeId);
} else if (e.keyCode == 38) {
// Up arrow key. Go to the previous sibling, if possible.
var prevSibling = this.getPreviousSibling(activeDesc);
if (prevSibling) {
this.setActiveDesc(prevSibling.id, treeId);
} else {
this.notificationsService.setStatusMessage(
'Reached top of list. Press left to go to parent list.');
var statusMessage = 'Reached top of list.';
if (this.getParentListElement_(activeDesc)) {
statusMessage += ' Press left to go to parent list.';
}
this.notificationsService.setStatusMessage(statusMessage);
}
} else if (e.keyCode == 39) {
// Right arrow key. Go down a level, if possible.
var firstChild = this.getFirstChild(activeDesc);
if (firstChild) {
this.setActiveDesc(firstChild.id, treeId);
}
this.moveDownOneLevel_(treeId);
} else if (e.keyCode == 40) {
// Down arrow key. Go to the next sibling, if possible.
var nextSibling = this.getNextSibling(activeDesc);
@ -526,19 +537,27 @@ blocklyApp.TreeService = ng.core
}
}
},
moveActiveDescToParent: function(treeId) {
moveDownOneLevel_: function(treeId) {
var activeDesc = document.getElementById(this.getActiveDescId(treeId));
var nextNode = activeDesc.parentNode;
if (this.isButtonOrFieldNode_(activeDesc)) {
nextNode = nextNode.parentNode;
}
while (nextNode && nextNode.tagName != 'LI') {
nextNode = nextNode.parentNode;
var firstChild = this.getFirstChild(activeDesc);
if (firstChild) {
this.setActiveDesc(firstChild.id, treeId);
}
},
moveUpOneLevel_: function(treeId) {
var activeDesc = document.getElementById(this.getActiveDescId(treeId));
var nextNode = this.getParentListElement_(activeDesc);
if (nextNode) {
this.setActiveDesc(nextNode.id, treeId);
}
},
getParentListElement_: function(element) {
var nextNode = element.parentNode;
while (nextNode && nextNode.tagName != 'LI') {
nextNode = nextNode.parentNode;
}
return nextNode;
},
getFirstChild: function(element) {
if (!element) {
return element;

View file

@ -36,7 +36,7 @@ blocklyApp.WorkspaceComponent = ng.core
[attr.aria-activedescendant]="getActiveDescId(tree.id)"
[attr.aria-labelledby]="workspaceTitle.id"
(keydown)="onKeypress($event, tree)">
<blockly-workspace-tree [level]=1 [block]="block" [tree]="tree" [isTopLevel]="true">
<blockly-workspace-tree [level]="0" [block]="block" [tree]="tree" [isTopLevel]="true">
</blockly-workspace-tree>
</ol>
</div>