Chromium Code Reviews| OLD | NEW |
|---|---|
| 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 Polymer.IronA11yKeysBehavior, | |
| 10 ], | 11 ], |
| 11 | 12 |
| 12 properties: { | 13 properties: { |
| 13 itemId: { | 14 itemId: { |
| 14 type: String, | 15 type: String, |
| 15 observer: 'updateFromStore', | 16 observer: 'updateFromStore', |
| 16 }, | 17 }, |
| 17 | 18 |
| 18 depth: { | 19 depth: { |
| 19 type: Number, | 20 type: Number, |
| 20 observer: 'depthChanged_', | 21 observer: 'depthChanged_', |
| 21 }, | 22 }, |
| 22 | 23 |
| 24 focusable: { | |
| 25 type: Boolean, | |
| 26 value: false, | |
| 27 }, | |
| 28 | |
| 23 /** @type {BookmarkNode} */ | 29 /** @type {BookmarkNode} */ |
| 24 item_: Object, | 30 item_: Object, |
| 25 | 31 |
| 26 /** @private */ | 32 /** @private */ |
| 27 isClosed_: Boolean, | 33 isClosed_: Boolean, |
| 28 | 34 |
| 29 /** @private */ | 35 /** @private */ |
| 30 selectedFolder_: String, | 36 selectedFolder_: String, |
| 31 | 37 |
| 32 /** @private */ | 38 /** @private */ |
| 33 searchActive_: Boolean, | 39 searchActive_: Boolean, |
| 34 | 40 |
| 35 /** @private */ | 41 /** @private */ |
| 36 isSelectedFolder_: { | 42 isSelectedFolder_: { |
| 37 type: Boolean, | 43 type: Boolean, |
| 38 value: false, | 44 value: false, |
| 39 reflectToAttribute: true, | 45 reflectToAttribute: true, |
| 40 computed: 'computeIsSelected_(itemId, selectedFolder_, searchActive_)' | 46 computed: 'computeIsSelected_(itemId, selectedFolder_, searchActive_)' |
| 41 }, | 47 }, |
| 42 }, | 48 }, |
| 43 | 49 |
| 50 listeners: { | |
| 51 'keydown': 'onKeydown_', | |
| 52 }, | |
| 53 | |
| 44 /** @override */ | 54 /** @override */ |
| 45 attached: function() { | 55 attached: function() { |
| 46 this.watch('item_', function(state) { | 56 this.watch('item_', function(state) { |
| 47 return state.nodes[this.itemId]; | 57 return state.nodes[this.itemId]; |
| 48 }.bind(this)); | 58 }.bind(this)); |
| 49 this.watch('isClosed_', function(state) { | 59 this.watch('isClosed_', function(state) { |
| 50 return state.closedFolders.has(this.itemId); | 60 return state.closedFolders.has(this.itemId); |
| 51 }.bind(this)); | 61 }.bind(this)); |
| 52 this.watch('selectedFolder_', function(state) { | 62 this.watch('selectedFolder_', function(state) { |
| 53 return state.selectedFolder; | 63 return state.selectedFolder; |
| 54 }); | 64 }); |
| 55 this.watch('searchActive_', function(state) { | 65 this.watch('searchActive_', function(state) { |
| 56 return bookmarks.util.isShowingSearch(state); | 66 return bookmarks.util.isShowingSearch(state); |
| 57 }); | 67 }); |
| 58 | 68 |
| 59 this.updateFromStore(); | 69 this.updateFromStore(); |
| 70 | |
| 71 if (this.selectedFolder_ == this.itemId) | |
| 72 this.fire('folder-node-focus-changed', this); | |
| 60 }, | 73 }, |
| 61 | 74 |
| 62 /** @return {HTMLElement} */ | 75 /** @return {HTMLElement} */ |
| 76 getFocusTarget: function() { | |
| 77 return this.$.container; | |
| 78 }, | |
| 79 | |
| 80 /** @return {HTMLElement} */ | |
| 63 getDropTarget: function() { | 81 getDropTarget: function() { |
| 64 return this.$.container; | 82 return this.$.container; |
| 65 }, | 83 }, |
| 66 | 84 |
| 67 /** @return {boolean} */ | 85 /** @return {boolean} */ |
| 68 isPositiveDepth_: function() { | 86 isPositiveDepth_: function(depth) { |
| 69 return this.depth >= 0; | 87 return depth >= 0; |
| 70 }, | 88 }, |
| 71 | 89 |
| 72 /** | 90 /** |
| 91 * @private | |
| 92 * @param {!Event} e | |
| 93 */ | |
| 94 onKeydown_: function(e) { | |
| 95 var direction = 0; | |
| 96 var handled = true; | |
| 97 if (this.keyboardEventMatchesKeys(e, 'up')) { | |
|
tsergeant
2017/04/19 01:42:16
Seems like overkill to use IronA11yKeysBehavior ju
calamity
2017/04/19 04:51:02
Done.
| |
| 98 direction = -1; | |
| 99 } else if (this.keyboardEventMatchesKeys(e, 'down')) { | |
| 100 direction = 1; | |
| 101 } else { | |
| 102 handled = false; | |
| 103 } | |
| 104 | |
|
tsergeant
2017/04/19 01:42:16
Is left/right going to be handled here too? Maybe
calamity
2017/04/19 04:51:02
Yeah. It's in a follow-up.
| |
| 105 if (direction) { | |
| 106 handled = | |
| 107 this.changeKeyboardSelection_(direction, this.root.activeElement); | |
| 108 } | |
| 109 | |
| 110 if (!handled) | |
| 111 return; | |
| 112 | |
| 113 e.preventDefault(); | |
| 114 e.stopPropagation(); | |
| 115 }, | |
| 116 | |
| 117 /** | |
| 118 * @private | |
| 119 * @param {number} direction | |
| 120 * @return {boolean} Whether the event should be treated as handled. | |
| 121 */ | |
| 122 changeKeyboardSelection_: function(direction, currentFocus) { | |
| 123 var isCurrentlyFocused = currentFocus == this.$.container; | |
| 124 | |
| 125 // Get the next folder node. If there is no next element, the event will | |
| 126 // bubble to the parent node which will handle it. | |
| 127 var newFocusFolderNode = this.getNextVisibleFolderNode_( | |
| 128 direction == -1, isCurrentlyFocused ? this : currentFocus); | |
| 129 | |
| 130 if (!newFocusFolderNode || newFocusFolderNode.itemId != ROOT_NODE_ID) { | |
|
tsergeant
2017/04/19 01:42:16
This can be simplified a little bit:
if (!newFocu
calamity
2017/04/19 04:51:02
Done.
| |
| 131 if (newFocusFolderNode) { | |
| 132 this.fire('folder-node-focus-changed', newFocusFolderNode); | |
| 133 newFocusFolderNode.getFocusTarget().focus(); | |
| 134 } else { | |
| 135 // If there is no newly focused node, allow the event to bubble. | |
| 136 return false; | |
| 137 } | |
| 138 } | |
| 139 return true; | |
| 140 }, | |
| 141 | |
| 142 /** | |
| 143 * Returns the next or previous visible bookmark node relative to |current|. | |
| 144 * @private | |
| 145 * @param {boolean} reverse | |
| 146 * @param {BookmarksFolderNodeElement} current Either this node, or an | |
| 147 * immediate child. | |
| 148 * @return {HTMLElement|null} Returns null | |
|
tsergeant
2017/04/19 01:42:16
Returns null...when?
calamity
2017/04/19 04:51:02
Done.
| |
| 149 */ | |
| 150 getNextVisibleFolderNode_: function(reverse, current) { | |
| 151 var newFocus = null; | |
| 152 var children = | |
| 153 Array.from(this.root.querySelectorAll('bookmarks-folder-node')); | |
| 154 | |
| 155 // The current node's successor can only be its first child. | |
| 156 if (this == current) { | |
| 157 if (!reverse && children.length && !this.isClosed_) | |
| 158 newFocus = children[0]; | |
| 159 | |
| 160 return newFocus; | |
| 161 } | |
| 162 | |
| 163 var index = children.indexOf(current); | |
| 164 assert(index != -1); | |
| 165 if (reverse) { | |
| 166 // A child node's predecessor is either the previous child's last visible | |
| 167 // descendant, or this node, which is its immediate parent. | |
| 168 newFocus = | |
| 169 index == 0 ? this : children[index - 1].getLastVisibleDescendant_(); | |
| 170 } else if (index < children.length - 1) { | |
| 171 // A successor to a child is the next child. | |
| 172 newFocus = children[index + 1]; | |
| 173 } | |
| 174 | |
| 175 return newFocus; | |
| 176 }, | |
| 177 | |
| 178 /** | |
| 179 * @private | |
| 180 * @return {BookmarksFolderNodeElement} | |
| 181 */ | |
| 182 getLastVisibleDescendant_: function() { | |
| 183 var children = | |
| 184 Array.from(this.root.querySelectorAll('bookmarks-folder-node')); | |
| 185 | |
| 186 if (this.isClosed_ || children.length == 0) | |
| 187 return this; | |
| 188 | |
| 189 return children.pop().getLastVisibleDescendant_(); | |
| 190 }, | |
| 191 | |
| 192 /** | |
| 73 * @private | 193 * @private |
| 74 * @return {string} | 194 * @return {string} |
| 75 */ | 195 */ |
| 76 getFolderIcon_: function() { | 196 getFolderIcon_: function() { |
| 77 return this.isSelectedFolder_ ? 'bookmarks:folder-open' : 'cr:folder'; | 197 return this.isSelectedFolder_ ? 'bookmarks:folder-open' : 'cr:folder'; |
| 78 }, | 198 }, |
| 79 | 199 |
| 80 /** @private */ | 200 /** @private */ |
| 81 selectFolder_: function() { | 201 selectFolder_: function() { |
| 82 this.dispatch(bookmarks.actions.selectFolder(this.item_.id)); | 202 this.dispatch(bookmarks.actions.selectFolder(this.item_.id)); |
| (...skipping 50 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 133 return !this.getState().nodes[itemId].url; | 253 return !this.getState().nodes[itemId].url; |
| 134 }, | 254 }, |
| 135 | 255 |
| 136 /** | 256 /** |
| 137 * @private | 257 * @private |
| 138 * @return {boolean} | 258 * @return {boolean} |
| 139 */ | 259 */ |
| 140 isRootFolder_: function() { | 260 isRootFolder_: function() { |
| 141 return this.depth == 0; | 261 return this.depth == 0; |
| 142 }, | 262 }, |
| 263 | |
| 264 getTabIndex_: function(focusable) { | |
| 265 return focusable ? 0 : -1; | |
| 266 }, | |
| 143 }); | 267 }); |
| OLD | NEW |