Commit 872e2db0 authored by calamity's avatar calamity Committed by Commit bot

[MD Bookmarks] Allow left/right keys to close/open folders in sidebar.

This CL makes the left and right arrows close and open folders in the
sidebar respectively. A closed folder will transfer selection to the
parent when left is pressed and an open folder will transfer selection
to its first child.

BUG=692844
CQ_INCLUDE_TRYBOTS=master.tryserver.chromium.linux:closure_compilation

Review-Url: https://codereview.chromium.org/2857893002
Cr-Commit-Position: refs/heads/master@{#471199}
parent 25aed983
...@@ -57,15 +57,18 @@ ...@@ -57,15 +57,18 @@
#arrow { #arrow {
color: var(--secondary-text-color); color: var(--secondary-text-color);
margin: 0 8px; margin: 0 8px;
}
#arrow iron-icon {
transform: rotate(-90deg); transform: rotate(-90deg);
transition: transform 150ms; transition: transform 150ms;
} }
:host-context([dir='rtl']) #arrow { :host-context([dir='rtl']) #arrow iron-icon {
transform: rotate(90deg); transform: rotate(90deg);
} }
#arrow[is-open] { #arrow iron-icon[is-open] {
transform: initial; transform: initial;
} }
...@@ -80,9 +83,9 @@ ...@@ -80,9 +83,9 @@
hidden="[[isRootFolder_(depth)]]"> hidden="[[isRootFolder_(depth)]]">
<template is="dom-if" if="[[hasChildFolder_(item_.children)]]"> <template is="dom-if" if="[[hasChildFolder_(item_.children)]]">
<button is="paper-icon-button-light" id="arrow" <button is="paper-icon-button-light" id="arrow"
is-open$="[[!isClosed_]]" on-tap="toggleFolder_" on-tap="toggleFolder_" on-mousedown="preventDefault_" tabindex="-1">
on-mousedown="preventDefault_" tabindex="-1"> <iron-icon icon="cr:arrow-drop-down" is-open$="[[!isClosed_]]">
<iron-icon icon="cr:arrow-drop-down"></iron-icon> </iron-icon>
</button> </button>
</template> </template>
<div id="folder-label" class="v-centered"> <div id="folder-label" class="v-centered">
......
...@@ -83,19 +83,26 @@ Polymer({ ...@@ -83,19 +83,26 @@ Polymer({
* @param {!Event} e * @param {!Event} e
*/ */
onKeydown_: function(e) { onKeydown_: function(e) {
var direction = 0; var yDirection = 0;
var xDirection = 0;
var handled = true; var handled = true;
// TODO(calamity): Handle left/right arrow keys.
if (e.key == 'ArrowUp') { if (e.key == 'ArrowUp') {
direction = -1; yDirection = -1;
} else if (e.key == 'ArrowDown') { } else if (e.key == 'ArrowDown') {
direction = 1; yDirection = 1;
} else if (e.key == 'ArrowLeft') {
xDirection = -1;
} else if (e.key == 'ArrowRight') {
xDirection = 1;
} else { } else {
handled = false; handled = false;
} }
if (direction) if (this.getComputedStyleValue('direction') == 'rtl')
this.changeKeyboardSelection_(direction, this.root.activeElement); xDirection *= -1;
this.changeKeyboardSelection_(
xDirection, yDirection, this.root.activeElement);
if (!handled) if (!handled)
return; return;
...@@ -106,17 +113,45 @@ Polymer({ ...@@ -106,17 +113,45 @@ Polymer({
/** /**
* @private * @private
* @param {number} direction * @param {number} xDirection
* @param {number} yDirection
* @param {!HTMLElement} currentFocus * @param {!HTMLElement} currentFocus
*/ */
changeKeyboardSelection_: function(direction, currentFocus) { changeKeyboardSelection_: function(xDirection, yDirection, currentFocus) {
var newFocusFolderNode = null; var newFocusFolderNode = null;
var isChildFolderNodeFocused = var isChildFolderNodeFocused =
currentFocus.tagName == 'BOOKMARKS-FOLDER-NODE'; currentFocus.tagName == 'BOOKMARKS-FOLDER-NODE';
var reverse = direction == -1;
if (xDirection == 1) {
// The right arrow opens a folder if closed and goes to the first child
// otherwise.
if (this.hasChildFolder_()) {
if (this.isClosed_) {
this.dispatch(
bookmarks.actions.changeFolderOpen(this.item_.id, true));
} else {
yDirection = 1;
}
}
} else if (xDirection == -1) {
// The left arrow closes a folder if open and goes to the parent
// otherwise.
if (this.hasChildFolder_() && !this.isClosed_) {
this.dispatch(bookmarks.actions.changeFolderOpen(this.item_.id, false));
} else {
var parentFolderNode = this.getParentFolderNode_();
if (parentFolderNode.itemId != ROOT_NODE_ID) {
parentFolderNode.selectFolder_();
parentFolderNode.getFocusTarget().focus();
}
}
}
if (!yDirection)
return;
// The current node's successor is its first child when open. // The current node's successor is its first child when open.
if (!isChildFolderNodeFocused && !reverse && !this.isClosed_) { if (!isChildFolderNodeFocused && yDirection == 1 && !this.isClosed_) {
var children = this.getChildFolderNodes_(); var children = this.getChildFolderNodes_();
if (children.length) if (children.length)
newFocusFolderNode = children[0]; newFocusFolderNode = children[0];
...@@ -126,19 +161,20 @@ Polymer({ ...@@ -126,19 +161,20 @@ Polymer({
// Get the next child folder node if a child is focused. // Get the next child folder node if a child is focused.
if (!newFocusFolderNode) { if (!newFocusFolderNode) {
newFocusFolderNode = this.getNextChild_( newFocusFolderNode = this.getNextChild_(
reverse, yDirection == -1,
/** @type {!BookmarksFolderNodeElement} */ (currentFocus)); /** @type {!BookmarksFolderNodeElement} */ (currentFocus));
} }
// The first child's predecessor is this node. // The first child's predecessor is this node.
if (!newFocusFolderNode && reverse) if (!newFocusFolderNode && yDirection == -1)
newFocusFolderNode = this; newFocusFolderNode = this;
} }
// If there is no newly focused node, allow the parent to handle the change. // If there is no newly focused node, allow the parent to handle the change.
if (!newFocusFolderNode) { if (!newFocusFolderNode) {
if (this.itemId != ROOT_NODE_ID) if (this.itemId != ROOT_NODE_ID)
this.getParentFolderNode_().changeKeyboardSelection_(direction, this); this.getParentFolderNode_().changeKeyboardSelection_(
0, yDirection, this);
return; return;
} }
......
...@@ -97,6 +97,12 @@ TEST_F('MaterialBookmarksFocusTest', 'All', function() { ...@@ -97,6 +97,12 @@ TEST_F('MaterialBookmarksFocusTest', 'All', function() {
keydown('1', 'ArrowDown'); keydown('1', 'ArrowDown');
assertDeepEquals(bookmarks.actions.selectFolder('2'), store.lastAction); assertDeepEquals(bookmarks.actions.selectFolder('2'), store.lastAction);
store.data.selectedFolder = '2';
store.notifyObservers();
assertEquals('', getFolderNode('1').$.container.getAttribute('tabindex'));
assertEquals(
'0', getFolderNode('2').$.container.getAttribute('tabindex'));
assertFocused('1', '2'); assertFocused('1', '2');
// Move down past closed folders. // Move down past closed folders.
...@@ -124,6 +130,54 @@ TEST_F('MaterialBookmarksFocusTest', 'All', function() { ...@@ -124,6 +130,54 @@ TEST_F('MaterialBookmarksFocusTest', 'All', function() {
keydown('1', 'ArrowUp'); keydown('1', 'ArrowUp');
assertDeepEquals(null, store.lastAction); assertDeepEquals(null, store.lastAction);
}); });
test('keyboard left/right', function() {
store.data.closedFolders = new Set('2');
store.notifyObservers();
// Give keyboard focus to the first item.
getFolderNode('1').$.container.focus();
// Pressing right descends into first child.
keydown('1', 'ArrowRight');
assertDeepEquals(bookmarks.actions.selectFolder('2'), store.lastAction);
// Pressing right on a closed folder opens that folder
keydown('2', 'ArrowRight');
assertDeepEquals(
bookmarks.actions.changeFolderOpen('2', true), store.lastAction);
// Pressing right again descends into first child.
keydown('2', 'ArrowRight');
assertDeepEquals(bookmarks.actions.selectFolder('3'), store.lastAction);
// Pressing right on a folder with no children does nothing.
store.resetLastAction();
keydown('3', 'ArrowRight');
assertDeepEquals(null, store.lastAction);
// Pressing left on a folder with no children ascends to parent.
keydown('3', 'ArrowDown');
keydown('4', 'ArrowLeft');
assertDeepEquals(bookmarks.actions.selectFolder('2'), store.lastAction);
// Pressing left again closes the parent.
keydown('2', 'ArrowLeft');
assertDeepEquals(
bookmarks.actions.changeFolderOpen('2', false), store.lastAction);
// RTL flips left and right.
document.body.style.direction = 'rtl';
keydown('2', 'ArrowLeft');
assertDeepEquals(
bookmarks.actions.changeFolderOpen('2', true), store.lastAction);
keydown('2', 'ArrowRight');
assertDeepEquals(
bookmarks.actions.changeFolderOpen('2', false), store.lastAction);
document.body.style.direction = 'ltr';
});
}); });
mocha.run(); mocha.run();
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment