Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(403)

Side by Side Diff: chrome/browser/resources/md_bookmarks/folder_node.js

Issue 2820153003: [MD Bookmarks] Add keyboard navigation to sidebar. (Closed)
Patch Set: select_on_move Created 3 years, 8 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
1 // Copyright 2016 The Chromium Authors. All rights reserved. 1 // Copyright 2016 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 Polymer({ 5 Polymer({
6 is: 'bookmarks-folder-node', 6 is: 'bookmarks-folder-node',
7 7
8 behaviors: [ 8 behaviors: [
9 bookmarks.StoreClient, 9 bookmarks.StoreClient,
10 ], 10 ],
(...skipping 23 matching lines...) Expand all
34 34
35 /** @private */ 35 /** @private */
36 isSelectedFolder_: { 36 isSelectedFolder_: {
37 type: Boolean, 37 type: Boolean,
38 value: false, 38 value: false,
39 reflectToAttribute: true, 39 reflectToAttribute: true,
40 computed: 'computeIsSelected_(itemId, selectedFolder_, searchActive_)' 40 computed: 'computeIsSelected_(itemId, selectedFolder_, searchActive_)'
41 }, 41 },
42 }, 42 },
43 43
44 listeners: {
45 'keydown': 'onKeydown_',
46 },
47
44 /** @override */ 48 /** @override */
45 attached: function() { 49 attached: function() {
46 this.watch('item_', function(state) { 50 this.watch('item_', function(state) {
47 return state.nodes[this.itemId]; 51 return state.nodes[this.itemId];
48 }.bind(this)); 52 }.bind(this));
49 this.watch('isClosed_', function(state) { 53 this.watch('isClosed_', function(state) {
50 return state.closedFolders.has(this.itemId); 54 return state.closedFolders.has(this.itemId);
51 }.bind(this)); 55 }.bind(this));
52 this.watch('selectedFolder_', function(state) { 56 this.watch('selectedFolder_', function(state) {
53 return state.selectedFolder; 57 return state.selectedFolder;
54 }); 58 });
55 this.watch('searchActive_', function(state) { 59 this.watch('searchActive_', function(state) {
56 return bookmarks.util.isShowingSearch(state); 60 return bookmarks.util.isShowingSearch(state);
57 }); 61 });
58 62
59 this.updateFromStore(); 63 this.updateFromStore();
60 }, 64 },
61 65
62 /** @return {HTMLElement} */ 66 /** @return {HTMLElement} */
67 getFocusTarget: function() {
68 return this.$.container;
69 },
70
71 /** @return {HTMLElement} */
63 getDropTarget: function() { 72 getDropTarget: function() {
64 return this.$.container; 73 return this.$.container;
65 }, 74 },
66 75
67 /** @return {boolean} */ 76 /** @return {boolean} */
68 isPositiveDepth_: function() { 77 isPositiveDepth_: function() {
69 return this.depth >= 0; 78 return this.depth >= 0;
70 }, 79 },
71 80
72 /** 81 /**
73 * @private 82 * @private
83 * @param {!Event} e
84 */
85 onKeydown_: function(e) {
86 var direction = 0;
87 var handled = true;
88 // TODO(calamity): Handle left/right arrow keys.
89 if (e.key == 'ArrowUp') {
90 direction = -1;
91 } else if (e.key == 'ArrowDown') {
92 direction = 1;
93 } else {
94 handled = false;
95 }
96
97 if (direction) {
98 handled =
99 this.changeKeyboardSelection_(direction, this.root.activeElement);
100 }
101
102 if (!handled)
103 return;
104
105 e.preventDefault();
106 e.stopPropagation();
107 },
108
109 /**
110 * @private
111 * @param {number} direction
112 * @param {HTMLElement} currentFocus
113 * @return {boolean} Whether the event should be treated as handled.
114 */
115 changeKeyboardSelection_: function(direction, currentFocus) {
116 var isChildFolderNodeFocused =
117 currentFocus.tagName == 'BOOKMARKS-FOLDER-NODE';
118
119 // Get the next folder node. If there is no next element, the event will
120 // bubble to the parent node which will handle it.
121 var newFocusFolderNode = this.getNextVisibleFolderNode_(
122 direction == -1,
123 isChildFolderNodeFocused ?
124 /** @type {BookmarksFolderNodeElement} */ (currentFocus) :
125 this);
126
127 // If there is no newly focused node, allow the event to bubble.
128 if (!newFocusFolderNode)
129 return false;
130
131 if (newFocusFolderNode.itemId != ROOT_NODE_ID) {
132 newFocusFolderNode.selectFolder_();
133 newFocusFolderNode.getFocusTarget().focus();
134 }
135
136 return true;
137 },
138
139 /**
140 * Returns the next or previous visible bookmark node relative to |current|.
141 * @private
142 * @param {boolean} reverse
143 * @param {BookmarksFolderNodeElement} current Either this node, or an
144 * immediate child.
145 * @return {HTMLElement|null} Returns null if the next node is not within this
146 * folder node.
147 */
148 getNextVisibleFolderNode_: function(reverse, current) {
149 var newFocus = null;
150 var children =
151 Array.from(this.root.querySelectorAll('bookmarks-folder-node'));
tsergeant 2017/04/19 07:32:18 Pull this out into a helper getter, since it's use
calamity 2017/04/28 06:15:47 Done.
152
153 // The current node's successor can only be its first child.
154 if (this == current) {
tsergeant 2017/04/19 07:32:18 I find it confusing that this is packaged into thi
calamity 2017/04/28 06:15:47 Hmm, ok. I've changed things here a little bit. WD
tsergeant 2017/05/01 01:35:57 Yeah, I think this is a bit better. It's still a c
155 if (!reverse && children.length && !this.isClosed_)
156 newFocus = children[0];
157
158 return newFocus;
159 }
160
161 var index = children.indexOf(current);
162 assert(index != -1);
163 if (reverse) {
164 // A child node's predecessor is either the previous child's last visible
165 // descendant, or this node, which is its immediate parent.
166 newFocus =
167 index == 0 ? this : children[index - 1].getLastVisibleDescendant_();
168 } else if (index < children.length - 1) {
169 // A successor to a child is the next child.
170 newFocus = children[index + 1];
171 }
172
173 return newFocus;
174 },
175
176 /**
177 * @private
178 * @return {BookmarksFolderNodeElement}
179 */
180 getLastVisibleDescendant_: function() {
181 var children =
182 Array.from(this.root.querySelectorAll('bookmarks-folder-node'));
183
184 if (this.isClosed_ || children.length == 0)
185 return this;
186
187 return children.pop().getLastVisibleDescendant_();
188 },
189
190 /**
191 * @private
74 * @return {string} 192 * @return {string}
75 */ 193 */
76 getFolderIcon_: function() { 194 getFolderIcon_: function() {
77 return this.isSelectedFolder_ ? 'bookmarks:folder-open' : 'cr:folder'; 195 return this.isSelectedFolder_ ? 'bookmarks:folder-open' : 'cr:folder';
78 }, 196 },
79 197
80 /** @private */ 198 /** @private */
81 selectFolder_: function() { 199 selectFolder_: function() {
82 this.dispatch(bookmarks.actions.selectFolder(this.item_.id)); 200 this.dispatch(bookmarks.actions.selectFolder(this.item_.id));
83 }, 201 },
(...skipping 49 matching lines...) Expand 10 before | Expand all | Expand 10 after
133 return !this.getState().nodes[itemId].url; 251 return !this.getState().nodes[itemId].url;
134 }, 252 },
135 253
136 /** 254 /**
137 * @private 255 * @private
138 * @return {boolean} 256 * @return {boolean}
139 */ 257 */
140 isRootFolder_: function() { 258 isRootFolder_: function() {
141 return this.depth == 0; 259 return this.depth == 0;
142 }, 260 },
261
262 /**
263 * @private
264 * @return {string}
265 */
266 getTabIndex_: function() {
267 return this.isSelectedFolder_ ? '0' : '';
268 },
143 }); 269 });
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698