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

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

Issue 2977523002: MD Bookmarks: Scroll and select items that are added to the main list (Closed)
Patch Set: Reformat json schema Created 3 years, 4 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-list', 6 is: 'bookmarks-list',
7 7
8 behaviors: [ 8 behaviors: [
9 bookmarks.StoreClient, 9 bookmarks.StoreClient,
10 ], 10 ],
11 11
12 properties: { 12 properties: {
13 /** 13 /**
14 * A list of item ids wrapped in an Object. This is necessary because 14 * A list of item ids wrapped in an Object. This is necessary because
15 * iron-list is unable to distinguish focusing index 6 from focusing id '6' 15 * iron-list is unable to distinguish focusing index 6 from focusing id '6'
16 * so the item we supply to iron-list needs to be non-index-like. 16 * so the item we supply to iron-list needs to be non-index-like.
17 * @private {Array<{id: string}>} 17 * @private {Array<{id: string}>}
18 */ 18 */
19 displayedList_: { 19 displayedList_: {
20 type: Array, 20 type: Array,
21 value: function() { 21 value: function() {
22 // Use an empty list during initialization so that the databinding to 22 // Use an empty list during initialization so that the databinding to
23 // hide #bookmarksCard takes effect. 23 // hide #list takes effect.
24 return []; 24 return [];
25 }, 25 },
26 }, 26 },
27 27
28 /** @private {Array<string>} */ 28 /** @private {Array<string>} */
29 displayedIds_: { 29 displayedIds_: {
30 type: Array, 30 type: Array,
31 observer: 'onDisplayedIdsChanged_', 31 observer: 'onDisplayedIdsChanged_',
32 }, 32 },
33 33
34 /** @private */ 34 /** @private */
35 searchTerm_: { 35 searchTerm_: {
36 type: String, 36 type: String,
37 observer: 'onDisplayedListSourceChange_', 37 observer: 'onDisplayedListSourceChange_',
38 }, 38 },
39 39
40 /** @private */ 40 /** @private */
41 selectedFolder_: { 41 selectedFolder_: {
42 type: String, 42 type: String,
43 observer: 'onDisplayedListSourceChange_', 43 observer: 'onDisplayedListSourceChange_',
44 }, 44 },
45 }, 45 },
46 46
47 listeners: { 47 listeners: {
48 'click': 'deselectItems_', 48 'click': 'deselectItems_',
49 'open-item-menu': 'onOpenItemMenu_', 49 'open-item-menu': 'onOpenItemMenu_',
50 }, 50 },
51 51
52 attached: function() { 52 attached: function() {
53 var list = /** @type {IronListElement} */ (this.$.bookmarksCard); 53 var list = /** @type {IronListElement} */ (this.$.list);
54 list.scrollTarget = this; 54 list.scrollTarget = this;
55 55
56 this.watch('displayedIds_', function(state) { 56 this.watch('displayedIds_', function(state) {
57 return bookmarks.util.getDisplayedList(state); 57 return bookmarks.util.getDisplayedList(state);
58 }); 58 });
59 this.watch('searchTerm_', function(state) { 59 this.watch('searchTerm_', function(state) {
60 return state.search.term; 60 return state.search.term;
61 }); 61 });
62 this.watch('selectedFolder_', function(state) { 62 this.watch('selectedFolder_', function(state) {
63 return state.selectedFolder; 63 return state.selectedFolder;
64 }); 64 });
65 this.updateFromStore(); 65 this.updateFromStore();
66 66
67 this.$.bookmarksCard.addEventListener( 67 this.$.list.addEventListener(
68 'keydown', this.onItemKeydown_.bind(this), true); 68 'keydown', this.onItemKeydown_.bind(this), true);
69
70 /** @private {function(!Event)} */
71 this.boundOnHighlightItems_ = this.onHighlightItems_.bind(this);
72 document.addEventListener('highlight-items', this.boundOnHighlightItems_);
73 },
74
75 detached: function() {
76 document.removeEventListener(
77 'highlight-items', this.boundOnHighlightItems_);
69 }, 78 },
70 79
71 /** @return {HTMLElement} */ 80 /** @return {HTMLElement} */
72 getDropTarget: function() { 81 getDropTarget: function() {
73 return this.$.message; 82 return this.$.message;
74 }, 83 },
75 84
76 /** 85 /**
77 * Updates `displayedList_` using splices to be equivalent to `newValue`. This 86 * Updates `displayedList_` using splices to be equivalent to `newValue`. This
78 * allows the iron-list to delete sublists of items which preserves scroll and 87 * allows the iron-list to delete sublists of items which preserves scroll and
(...skipping 22 matching lines...) Expand all
101 ].concat(additions)); 110 ].concat(additions));
102 }.bind(this)); 111 }.bind(this));
103 } 112 }
104 }, 113 },
105 114
106 /** @private */ 115 /** @private */
107 onDisplayedListSourceChange_: function() { 116 onDisplayedListSourceChange_: function() {
108 this.scrollTop = 0; 117 this.scrollTop = 0;
109 }, 118 },
110 119
120 /**
121 * Scroll the list so that |itemId| is visible, if it is not already.
122 * @param {string} itemId
123 * @private
124 */
125 scrollToId_: function(itemId) {
126 var index = this.displayedIds_.indexOf(itemId);
127 var list = this.$.list;
128 if (index >= 0 && index < list.firstVisibleIndex ||
129 index > list.lastVisibleIndex) {
130 list.scrollToIndex(index);
131 }
132 },
133
111 /** @private */ 134 /** @private */
112 emptyListMessage_: function() { 135 emptyListMessage_: function() {
113 var emptyListMessage = this.searchTerm_ ? 'noSearchResults' : 'emptyList'; 136 var emptyListMessage = this.searchTerm_ ? 'noSearchResults' : 'emptyList';
114 return loadTimeData.getString(emptyListMessage); 137 return loadTimeData.getString(emptyListMessage);
115 }, 138 },
116 139
117 /** @private */ 140 /** @private */
118 isEmptyList_: function() { 141 isEmptyList_: function() {
119 return this.displayedList_.length == 0; 142 return this.displayedList_.length == 0;
120 }, 143 },
121 144
122 /** @private */ 145 /** @private */
123 deselectItems_: function() { 146 deselectItems_: function() {
124 this.dispatch(bookmarks.actions.deselectItems()); 147 this.dispatch(bookmarks.actions.deselectItems());
125 }, 148 },
126 149
127 /** 150 /**
128 * @param{HTMLElement} el 151 * @param{HTMLElement} el
129 * @private 152 * @private
130 */ 153 */
131 getIndexForItemElement_: function(el) { 154 getIndexForItemElement_: function(el) {
132 return this.$.bookmarksCard.modelForElement(el).index; 155 return this.$.list.modelForElement(el).index;
133 }, 156 },
134 157
135 /** 158 /**
136 * @param {Event} e 159 * @param {Event} e
137 * @private 160 * @private
138 */ 161 */
139 onOpenItemMenu_: function(e) { 162 onOpenItemMenu_: function(e) {
140 var index = this.displayedIds_.indexOf(
141 /** @type {BookmarksItemElement} */ (e.path[0]).itemId);
142 var list = this.$.bookmarksCard;
143 // If the item is not visible, scroll to it before rendering the menu. 163 // If the item is not visible, scroll to it before rendering the menu.
144 if (index < list.firstVisibleIndex || index > list.lastVisibleIndex) 164 this.scrollToId_(/** @type {BookmarksItemElement} */ (e.path[0]).itemId);
145 list.scrollToIndex(index);
146 }, 165 },
147 166
148 /** 167 /**
168 * Highlight a list of items by selecting them, scrolling them into view and
169 * focusing the first item.
170 * @param {Event} e
171 * @private
172 */
173 onHighlightItems_: function(e) {
174 // Ensure that we only select items which are actually being displayed.
175 // This should only matter if an unrelated update to the bookmark model
176 // happens with the perfect timing to end up in a tracked batch update.
177 var toHighlight = /** @type {!Array<string>} */
178 (e.detail.filter((item) => this.displayedIds_.indexOf(item) != -1));
179
180 assert(toHighlight.length > 0);
181 var leadId = toHighlight[0];
182 this.dispatch(
183 bookmarks.actions.selectAll(toHighlight, this.getState(), leadId));
184
185 // Allow iron-list time to render additions to the list.
186 this.async(function() {
187 this.scrollToId_(leadId);
188 var leadIndex = this.displayedIds_.indexOf(leadId);
189 assert(leadIndex != -1);
190 this.$.list.focusItem(leadIndex);
191 });
192 },
193
194 /**
149 * @param {KeyboardEvent} e 195 * @param {KeyboardEvent} e
150 * @private 196 * @private
151 */ 197 */
152 onItemKeydown_: function(e) { 198 onItemKeydown_: function(e) {
153 var handled = true; 199 var handled = true;
154 var list = this.$.bookmarksCard; 200 var list = this.$.list;
155 var focusMoved = false; 201 var focusMoved = false;
156 var focusedIndex = 202 var focusedIndex =
157 this.getIndexForItemElement_(/** @type {HTMLElement} */ (e.target)); 203 this.getIndexForItemElement_(/** @type {HTMLElement} */ (e.target));
158 var oldFocusedIndex = focusedIndex; 204 var oldFocusedIndex = focusedIndex;
159 var cursorModifier = cr.isMac ? e.metaKey : e.ctrlKey; 205 var cursorModifier = cr.isMac ? e.metaKey : e.ctrlKey;
160 if (e.key == 'ArrowUp') { 206 if (e.key == 'ArrowUp') {
161 focusedIndex--; 207 focusedIndex--;
162 focusMoved = true; 208 focusMoved = true;
163 } else if (e.key == 'ArrowDown') { 209 } else if (e.key == 'ArrowDown') {
164 focusedIndex++; 210 focusedIndex++;
(...skipping 49 matching lines...) Expand 10 before | Expand all | Expand 10 after
214 260
215 if (!handled) { 261 if (!handled) {
216 handled = bookmarks.CommandManager.getInstance().handleKeyEvent( 262 handled = bookmarks.CommandManager.getInstance().handleKeyEvent(
217 e, this.getState().selection.items); 263 e, this.getState().selection.items);
218 } 264 }
219 265
220 if (handled) 266 if (handled)
221 e.stopPropagation(); 267 e.stopPropagation();
222 }, 268 },
223 }); 269 });
OLDNEW
« no previous file with comments | « chrome/browser/resources/md_bookmarks/list.html ('k') | chrome/browser/resources/md_bookmarks/store_client.js » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698