[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}
diff --git a/chrome/browser/resources/md_bookmarks/folder_node.html b/chrome/browser/resources/md_bookmarks/folder_node.html
index 9f87024..cf1629a 100644
--- a/chrome/browser/resources/md_bookmarks/folder_node.html
+++ b/chrome/browser/resources/md_bookmarks/folder_node.html
@@ -57,15 +57,18 @@
#arrow {
color: var(--secondary-text-color);
margin: 0 8px;
+ }
+
+ #arrow iron-icon {
transform: rotate(-90deg);
transition: transform 150ms;
}
- :host-context([dir='rtl']) #arrow {
+ :host-context([dir='rtl']) #arrow iron-icon {
transform: rotate(90deg);
}
- #arrow[is-open] {
+ #arrow iron-icon[is-open] {
transform: initial;
}
@@ -80,9 +83,9 @@
hidden="[[isRootFolder_(depth)]]">
<template is="dom-if" if="[[hasChildFolder_(item_.children)]]">
<button is="paper-icon-button-light" id="arrow"
- is-open$="[[!isClosed_]]" on-tap="toggleFolder_"
- on-mousedown="preventDefault_" tabindex="-1">
- <iron-icon icon="cr:arrow-drop-down"></iron-icon>
+ on-tap="toggleFolder_" on-mousedown="preventDefault_" tabindex="-1">
+ <iron-icon icon="cr:arrow-drop-down" is-open$="[[!isClosed_]]">
+ </iron-icon>
</button>
</template>
<div id="folder-label" class="v-centered">
diff --git a/chrome/browser/resources/md_bookmarks/folder_node.js b/chrome/browser/resources/md_bookmarks/folder_node.js
index 4e25e715..12654b4 100644
--- a/chrome/browser/resources/md_bookmarks/folder_node.js
+++ b/chrome/browser/resources/md_bookmarks/folder_node.js
@@ -83,19 +83,26 @@
* @param {!Event} e
*/
onKeydown_: function(e) {
- var direction = 0;
+ var yDirection = 0;
+ var xDirection = 0;
var handled = true;
- // TODO(calamity): Handle left/right arrow keys.
if (e.key == 'ArrowUp') {
- direction = -1;
+ yDirection = -1;
} else if (e.key == 'ArrowDown') {
- direction = 1;
+ yDirection = 1;
+ } else if (e.key == 'ArrowLeft') {
+ xDirection = -1;
+ } else if (e.key == 'ArrowRight') {
+ xDirection = 1;
} else {
handled = false;
}
- if (direction)
- this.changeKeyboardSelection_(direction, this.root.activeElement);
+ if (this.getComputedStyleValue('direction') == 'rtl')
+ xDirection *= -1;
+
+ this.changeKeyboardSelection_(
+ xDirection, yDirection, this.root.activeElement);
if (!handled)
return;
@@ -106,17 +113,45 @@
/**
* @private
- * @param {number} direction
+ * @param {number} xDirection
+ * @param {number} yDirection
* @param {!HTMLElement} currentFocus
*/
- changeKeyboardSelection_: function(direction, currentFocus) {
+ changeKeyboardSelection_: function(xDirection, yDirection, currentFocus) {
var newFocusFolderNode = null;
var isChildFolderNodeFocused =
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.
- if (!isChildFolderNodeFocused && !reverse && !this.isClosed_) {
+ if (!isChildFolderNodeFocused && yDirection == 1 && !this.isClosed_) {
var children = this.getChildFolderNodes_();
if (children.length)
newFocusFolderNode = children[0];
@@ -126,19 +161,20 @@
// Get the next child folder node if a child is focused.
if (!newFocusFolderNode) {
newFocusFolderNode = this.getNextChild_(
- reverse,
+ yDirection == -1,
/** @type {!BookmarksFolderNodeElement} */ (currentFocus));
}
// The first child's predecessor is this node.
- if (!newFocusFolderNode && reverse)
+ if (!newFocusFolderNode && yDirection == -1)
newFocusFolderNode = this;
}
// If there is no newly focused node, allow the parent to handle the change.
if (!newFocusFolderNode) {
if (this.itemId != ROOT_NODE_ID)
- this.getParentFolderNode_().changeKeyboardSelection_(direction, this);
+ this.getParentFolderNode_().changeKeyboardSelection_(
+ 0, yDirection, this);
return;
}
diff --git a/chrome/test/data/webui/md_bookmarks/md_bookmarks_focus_test.js b/chrome/test/data/webui/md_bookmarks/md_bookmarks_focus_test.js
index e70c156..e1ca42b 100644
--- a/chrome/test/data/webui/md_bookmarks/md_bookmarks_focus_test.js
+++ b/chrome/test/data/webui/md_bookmarks/md_bookmarks_focus_test.js
@@ -97,6 +97,12 @@
keydown('1', 'ArrowDown');
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');
// Move down past closed folders.
@@ -124,6 +130,54 @@
keydown('1', 'ArrowUp');
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();