OLD | NEW |
---|---|
1 // Copyright 2015 The Chromium Authors. All rights reserved. | 1 // Copyright 2015 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 /** | |
6 * The different pages that can be shown at a time. | |
7 * Note: This must remain in sync with the order in manager.html! | |
8 * @enum {string} | |
9 */ | |
10 var Page = { | |
11 ITEM_LIST: '0', | |
12 DETAIL_VIEW: '1', | |
13 KEYBOARD_SHORTCUTS: '2', | |
14 ERROR_PAGE: '3', | |
15 }; | |
16 | |
17 cr.define('extensions', function() { | 5 cr.define('extensions', function() { |
18 'use strict'; | 6 'use strict'; |
19 | 7 |
20 /** | 8 /** |
21 * Compares two extensions to determine which should come first in the list. | 9 * Compares two extensions to determine which should come first in the list. |
22 * @param {chrome.developerPrivate.ExtensionInfo} a | 10 * @param {chrome.developerPrivate.ExtensionInfo} a |
23 * @param {chrome.developerPrivate.ExtensionInfo} b | 11 * @param {chrome.developerPrivate.ExtensionInfo} b |
24 * @return {number} | 12 * @return {number} |
25 */ | 13 */ |
26 var compareExtensions = function(a, b) { | 14 var compareExtensions = function(a, b) { |
(...skipping 49 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
76 */ | 64 */ |
77 errorPageItem_: Object, | 65 errorPageItem_: Object, |
78 | 66 |
79 /** | 67 /** |
80 * The item currently displayed in the details view subpage. See also | 68 * The item currently displayed in the details view subpage. See also |
81 * errorPageItem_. | 69 * errorPageItem_. |
82 * @private {!chrome.developerPrivate.ExtensionInfo|undefined} | 70 * @private {!chrome.developerPrivate.ExtensionInfo|undefined} |
83 */ | 71 */ |
84 detailViewItem_: Object, | 72 detailViewItem_: Object, |
85 | 73 |
74 /** | |
75 * The helper object to maintain page state. | |
76 * @private {!extensions.PageState} | |
77 */ | |
78 pageState_: Object, | |
79 | |
80 /** | |
81 * The current page being shown. | |
82 * @private {!PageEntry} | |
83 */ | |
84 currentPage_: Object, | |
85 | |
86 /** @type {!Array<!chrome.developerPrivate.ExtensionInfo>} */ | 86 /** @type {!Array<!chrome.developerPrivate.ExtensionInfo>} */ |
87 extensions: { | 87 extensions: { |
88 type: Array, | 88 type: Array, |
89 value: function() { return []; }, | 89 value: function() { return []; }, |
90 }, | 90 }, |
91 | 91 |
92 /** @type {!Array<!chrome.developerPrivate.ExtensionInfo>} */ | 92 /** @type {!Array<!chrome.developerPrivate.ExtensionInfo>} */ |
93 apps: { | 93 apps: { |
94 type: Array, | 94 type: Array, |
95 value: function() { return []; }, | 95 value: function() { return []; }, |
(...skipping 11 matching lines...) Expand all Loading... | |
107 | 107 |
108 ready: function() { | 108 ready: function() { |
109 /** @type {extensions.Sidebar} */ | 109 /** @type {extensions.Sidebar} */ |
110 this.sidebar = | 110 this.sidebar = |
111 /** @type {extensions.Sidebar} */(this.$$('extensions-sidebar')); | 111 /** @type {extensions.Sidebar} */(this.$$('extensions-sidebar')); |
112 this.toolbar = | 112 this.toolbar = |
113 /** @type {extensions.Toolbar} */(this.$$('extensions-toolbar')); | 113 /** @type {extensions.Toolbar} */(this.$$('extensions-toolbar')); |
114 this.listHelper_ = new ListHelper(this); | 114 this.listHelper_ = new ListHelper(this); |
115 this.sidebar.setListDelegate(this.listHelper_); | 115 this.sidebar.setListDelegate(this.listHelper_); |
116 this.readyPromiseResolver.resolve(); | 116 this.readyPromiseResolver.resolve(); |
117 this.currentPage_ = {page: Page.LIST}; | |
118 this.pageState_ = new extensions.PageState(function(newPage) { | |
119 this.changePage(newPage, true); | |
120 }.bind(this)); | |
121 this.optionsDialog.addEventListener('close', function() { | |
122 // We update the page when the options dialog closes, but only if we're | |
123 // still on the details page. We could be on a different page if the | |
124 // user hit back while the options dialog was visible; in that case, the | |
125 // new page is already correct. | |
126 if (this.currentPage_.page == Page.DETAILS) | |
127 this.changePage({page: Page.DETAILS, id: this.currentPage_.id}); | |
michaelpg
2017/04/14 20:23:53
this seems to contradict the comment: if we're on
Devlin
2017/04/17 23:29:24
Tried to clear it up with some comments.
michaelpg
2017/04/18 22:03:11
Thanks.
| |
128 }.bind(this)); | |
117 }, | 129 }, |
118 | 130 |
119 get keyboardShortcuts() { | 131 get keyboardShortcuts() { |
120 return this.$['keyboard-shortcuts']; | 132 return this.$['keyboard-shortcuts']; |
121 }, | 133 }, |
122 | 134 |
123 get packDialog() { | 135 get packDialog() { |
124 return this.$['pack-dialog']; | 136 return this.$['pack-dialog']; |
125 }, | 137 }, |
126 | 138 |
127 get loadError() { | 139 get loadError() { |
128 return this.$['load-error']; | 140 return this.$['load-error']; |
129 }, | 141 }, |
130 | 142 |
131 get optionsDialog() { | 143 get optionsDialog() { |
132 return this.$['options-dialog']; | 144 return this.$['options-dialog']; |
133 }, | 145 }, |
134 | 146 |
135 get errorPage() { | 147 get errorPage() { |
136 return this.$['error-page']; | 148 return this.$['error-page']; |
137 }, | 149 }, |
138 | 150 |
139 /** | 151 /** |
140 * Shows the details view for a given item. | 152 * Shows the details view for a given item. |
141 * @param {!chrome.developerPrivate.ExtensionInfo} data | 153 * @param {!chrome.developerPrivate.ExtensionInfo} data |
142 */ | 154 */ |
143 showItemDetails: function(data) { | 155 showItemDetails: function(data) { |
144 this.$['items-list'].willShowItemSubpage(data.id); | 156 this.changePage({page: Page.DETAILS, id: data.id}); |
145 this.detailViewItem_ = data; | |
146 this.changePage(Page.DETAIL_VIEW); | |
147 }, | 157 }, |
148 | 158 |
149 /** | 159 /** |
160 * Initializes the page to reflect what's specified in the url so that if | |
161 * the user visits chrome://extensions/?id=..., we land on the proper page. | |
162 */ | |
163 initPage: function() { | |
164 this.changePage(this.pageState_.getCurrentPage(), true); | |
165 }, | |
166 | |
167 /** | |
150 * @param {!CustomEvent} event | 168 * @param {!CustomEvent} event |
151 * @private | 169 * @private |
152 */ | 170 */ |
153 onFilterChanged_: function(event) { | 171 onFilterChanged_: function(event) { |
154 this.filter = /** @type {string} */ (event.detail); | 172 this.filter = /** @type {string} */ (event.detail); |
155 }, | 173 }, |
156 | 174 |
175 /** @private */ | |
157 onMenuButtonTap_: function() { | 176 onMenuButtonTap_: function() { |
158 this.$.drawer.toggle(); | 177 this.$.drawer.toggle(); |
159 }, | 178 }, |
160 | 179 |
161 /** | 180 /** |
162 * @param {chrome.developerPrivate.ExtensionType} type The type of item. | 181 * @param {chrome.developerPrivate.ExtensionType} type The type of item. |
163 * @return {string} The ID of the list that the item belongs in. | 182 * @return {string} The ID of the list that the item belongs in. |
164 * @private | 183 * @private |
165 */ | 184 */ |
166 getListId_: function(type) { | 185 getListId_: function(type) { |
(...skipping 24 matching lines...) Expand all Loading... | |
191 * @return {number} The index of the item in the list, or -1 if not found. | 210 * @return {number} The index of the item in the list, or -1 if not found. |
192 * @private | 211 * @private |
193 */ | 212 */ |
194 getIndexInList_: function(listId, itemId) { | 213 getIndexInList_: function(listId, itemId) { |
195 return this[listId].findIndex(function(item) { | 214 return this[listId].findIndex(function(item) { |
196 return item.id == itemId; | 215 return item.id == itemId; |
197 }); | 216 }); |
198 }, | 217 }, |
199 | 218 |
200 /** | 219 /** |
220 * @return {?chrome.developerPrivate.ExtensionInfo} | |
221 * @private | |
222 */ | |
223 getData_: function(id) { | |
224 return this.extensions[this.getIndexInList_('extensions', id)] || | |
225 this.apps[this.getIndexInList_('apps', id)]; | |
226 }, | |
227 | |
228 /** | |
201 * @return {boolean} Whether the list should be visible. | 229 * @return {boolean} Whether the list should be visible. |
202 * @private | 230 * @private |
203 */ | 231 */ |
204 computeListHidden_: function() { | 232 computeListHidden_: function() { |
205 return this.$['items-list'].items.length == 0; | 233 return this.$['items-list'].items.length == 0; |
206 }, | 234 }, |
207 | 235 |
208 /** | 236 /** |
209 * Creates and adds a new extensions-item element to the list, inserting it | 237 * Creates and adds a new extensions-item element to the list, inserting it |
210 * into its sorted position in the relevant section. | 238 * into its sorted position in the relevant section. |
(...skipping 22 matching lines...) Expand all Loading... | |
233 // We should never try and update a non-existent item. | 261 // We should never try and update a non-existent item. |
234 assert(index >= 0); | 262 assert(index >= 0); |
235 this.set([listId, index], item); | 263 this.set([listId, index], item); |
236 | 264 |
237 // Update the subpage if it is open and displaying the item. If it's not | 265 // Update the subpage if it is open and displaying the item. If it's not |
238 // open, we don't update the data even if it's displaying that item. We'll | 266 // open, we don't update the data even if it's displaying that item. We'll |
239 // set the item correctly before opening the page. It's a little weird | 267 // set the item correctly before opening the page. It's a little weird |
240 // that the DOM will have stale data, but there's no point in causing the | 268 // that the DOM will have stale data, but there's no point in causing the |
241 // extra work. | 269 // extra work. |
242 if (this.detailViewItem_ && this.detailViewItem_.id == item.id && | 270 if (this.detailViewItem_ && this.detailViewItem_.id == item.id && |
243 this.$.pages.selected == Page.DETAIL_VIEW) { | 271 this.$.pages.selected == Page.DETAILS) { |
244 this.detailViewItem_ = item; | 272 this.detailViewItem_ = item; |
245 } else if (this.errorPageItem_ && this.errorPageItem_.id == item.id && | 273 } else if (this.errorPageItem_ && this.errorPageItem_.id == item.id && |
246 this.$.pages.selected == Page.ERROR_PAGE) { | 274 this.$.pages.selected == Page.ERRORS) { |
247 this.errorPageItem_ = item; | 275 this.errorPageItem_ = item; |
248 } | 276 } |
249 }, | 277 }, |
250 | 278 |
251 /** | 279 /** |
252 * @param {!chrome.developerPrivate.ExtensionInfo} item The data for the | 280 * @param {!chrome.developerPrivate.ExtensionInfo} item The data for the |
253 * item to remove. | 281 * item to remove. |
254 */ | 282 */ |
255 removeItem: function(item) { | 283 removeItem: function(item) { |
256 var listId = this.getListId_(item.type); | 284 var listId = this.getListId_(item.type); |
257 var index = this.getIndexInList_(listId, item.id); | 285 var index = this.getIndexInList_(listId, item.id); |
258 // We should never try and remove a non-existent item. | 286 // We should never try and remove a non-existent item. |
259 assert(index >= 0); | 287 assert(index >= 0); |
260 this.splice(listId, index, 1); | 288 this.splice(listId, index, 1); |
261 }, | 289 }, |
262 | 290 |
263 /** | 291 /** |
264 * @param {Page} page | 292 * @param {Page} page |
265 * @return {!(extensions.KeyboardShortcuts | | 293 * @return {!(extensions.KeyboardShortcuts | |
266 * extensions.DetailView | | 294 * extensions.DetailView | |
267 * extensions.ItemList)} | 295 * extensions.ItemList)} |
268 * @private | 296 * @private |
269 */ | 297 */ |
270 getPage_: function(page) { | 298 getPage_: function(page) { |
271 switch (page) { | 299 switch (page) { |
272 case Page.ITEM_LIST: | 300 case Page.LIST: |
273 return this.$['items-list']; | 301 return this.$['items-list']; |
274 case Page.DETAIL_VIEW: | 302 case Page.DETAILS: |
275 return this.$['details-view']; | 303 return this.$['details-view']; |
276 case Page.KEYBOARD_SHORTCUTS: | 304 case Page.SHORTCUTS: |
277 return this.$['keyboard-shortcuts']; | 305 return this.$['keyboard-shortcuts']; |
278 case Page.ERROR_PAGE: | 306 case Page.ERRORS: |
279 return this.$['error-page']; | 307 return this.$['error-page']; |
280 } | 308 } |
281 assertNotReached(); | 309 assertNotReached(); |
282 }, | 310 }, |
283 | 311 |
284 /** | 312 /** |
285 * Changes the active page selection. | 313 * Changes the active page selection. |
286 * @param {Page} toPage | 314 * @param {PageEntry} newPage |
315 * @param {boolean=} isSilent | |
michaelpg
2017/04/14 20:23:53
document isSilent
Devlin
2017/04/17 23:29:24
Done.
| |
287 */ | 316 */ |
288 changePage: function(toPage) { | 317 changePage: function(newPage, isSilent) { |
318 if (this.currentPage_.page == newPage.page && | |
319 this.currentPage_.subpage == newPage.subpage && | |
320 this.currentPage_.id == newPage.id) { | |
321 return; | |
322 } | |
323 | |
289 this.$.drawer.closeDrawer(); | 324 this.$.drawer.closeDrawer(); |
325 if (this.optionsDialog.open) | |
326 this.optionsDialog.close(); | |
327 | |
290 var fromPage = this.$.pages.selected; | 328 var fromPage = this.$.pages.selected; |
291 if (fromPage == toPage) | 329 var toPage = newPage.page; |
292 return; | 330 var data; |
293 var entry; | 331 if (newPage.id) { |
294 var exit; | 332 data = this.getData_(newPage.id); |
295 if (fromPage == Page.ITEM_LIST && (toPage == Page.DETAIL_VIEW || | 333 assert(data, newPage.id); |
296 toPage == Page.ERROR_PAGE)) { | |
297 entry = [extensions.Animation.HERO]; | |
298 // The item grid can be larger than the detail view that we're | |
299 // hero'ing into, so we want to also fade out to avoid any jarring. | |
300 exit = [extensions.Animation.HERO, extensions.Animation.FADE_OUT]; | |
301 } else if (toPage == Page.ITEM_LIST) { | |
302 entry = [extensions.Animation.FADE_IN]; | |
303 exit = [extensions.Animation.SCALE_DOWN]; | |
304 } else { | |
305 assert(toPage == Page.DETAIL_VIEW || | |
306 toPage == Page.KEYBOARD_SHORTCUTS); | |
307 entry = [extensions.Animation.FADE_IN]; | |
308 exit = [extensions.Animation.FADE_OUT]; | |
309 } | 334 } |
310 this.getPage_(fromPage).animationHelper.setExitAnimations(exit); | 335 |
311 this.getPage_(toPage).animationHelper.setEntryAnimations(entry); | 336 if (toPage == Page.DETAILS) { |
312 this.$.pages.selected = toPage; | 337 assert(newPage.id); |
338 this.detailViewItem_ = data; | |
339 } else if (toPage == Page.ERRORS) { | |
340 assert(newPage.id); | |
341 this.errorPageItem_ = data; | |
342 } | |
343 | |
344 if (fromPage != toPage) { | |
345 var entry; | |
346 var exit; | |
347 if (fromPage == Page.LIST && (toPage == Page.DETAILS || | |
348 toPage == Page.ERRORS)) { | |
349 assert(newPage.id); | |
350 this.$['items-list'].willShowItemSubpage(data.id); | |
351 entry = [extensions.Animation.HERO]; | |
352 // The item grid can be larger than the detail view that we're | |
353 // hero'ing into, so we want to also fade out to avoid any jarring. | |
354 exit = [extensions.Animation.HERO, extensions.Animation.FADE_OUT]; | |
355 } else if (toPage == Page.LIST) { | |
356 entry = [extensions.Animation.FADE_IN]; | |
357 exit = [extensions.Animation.SCALE_DOWN]; | |
358 } else { | |
359 assert(toPage == Page.DETAILS || | |
360 toPage == Page.SHORTCUTS); | |
361 entry = [extensions.Animation.FADE_IN]; | |
362 exit = [extensions.Animation.FADE_OUT]; | |
363 } | |
364 | |
365 this.getPage_(fromPage).animationHelper.setExitAnimations(exit); | |
366 this.getPage_(toPage).animationHelper.setEntryAnimations(entry); | |
367 this.$.pages.selected = toPage; | |
368 } | |
369 | |
370 if (newPage.subpage) { | |
371 assert(newPage.subpage == Subpage.OPTIONS); | |
372 assert(newPage.id); | |
373 this.optionsDialog.show(data); | |
374 } | |
375 | |
376 this.currentPage_ = newPage; | |
377 | |
378 if (!isSilent) | |
379 this.pageState_.onPageChange(newPage); | |
313 }, | 380 }, |
314 | 381 |
315 /** | 382 /** |
316 * Handles the event for the user clicking on a details button. | 383 * Handles the event for the user clicking on a details button. |
317 * @param {!CustomEvent} e | 384 * @param {!CustomEvent} e |
318 * @private | 385 * @private |
319 */ | 386 */ |
320 onShouldShowItemDetails_: function(e) { | 387 onShouldShowItemDetails_: function(e) { |
321 this.showItemDetails(e.detail.data); | 388 this.showItemDetails(e.detail.data); |
322 }, | 389 }, |
323 | 390 |
324 /** | 391 /** |
325 * Handles the event for the user clicking on the errors button. | 392 * Handles the event for the user clicking on the errors button. |
326 * @param {!CustomEvent} e | 393 * @param {!CustomEvent} e |
327 * @private | 394 * @private |
328 */ | 395 */ |
329 onShouldShowItemErrors_: function(e) { | 396 onShouldShowItemErrors_: function(e) { |
330 var data = e.detail.data; | 397 this.changePage({page: Page.ERRORS, id: e.detail.data.id}); |
331 this.$['items-list'].willShowItemSubpage(data.id); | |
332 this.errorPageItem_ = data; | |
333 this.changePage(Page.ERROR_PAGE); | |
334 }, | 398 }, |
335 | 399 |
336 /** @private */ | 400 /** @private */ |
337 onDetailsViewClose_: function() { | 401 onDetailsViewClose_: function() { |
338 // Note: we don't reset detailViewItem_ here because doing so just causes | 402 // Note: we don't reset detailViewItem_ here because doing so just causes |
339 // extra work for the data-bound details view. | 403 // extra work for the data-bound details view. |
340 this.changePage(Page.ITEM_LIST); | 404 this.changePage({page: Page.LIST}); |
341 }, | 405 }, |
342 | 406 |
343 /** @private */ | 407 /** @private */ |
344 onErrorPageClose_: function() { | 408 onErrorPageClose_: function() { |
345 // Note: we don't reset errorPageItem_ here because doing so just causes | 409 // Note: we don't reset errorPageItem_ here because doing so just causes |
346 // extra work for the data-bound error page. | 410 // extra work for the data-bound error page. |
347 this.changePage(Page.ITEM_LIST); | 411 this.changePage({page: Page.LIST}); |
348 }, | 412 }, |
349 | 413 |
350 /** @private */ | 414 /** @private */ |
351 onPackTap_: function() { | 415 onPackTap_: function() { |
352 this.$['pack-dialog'].show(); | 416 this.$['pack-dialog'].show(); |
353 } | 417 } |
354 }); | 418 }); |
355 | 419 |
356 /** | 420 /** |
357 * @param {extensions.Manager} manager | 421 * @param {extensions.Manager} manager |
(...skipping 11 matching lines...) Expand all Loading... | |
369 switch (type) { | 433 switch (type) { |
370 case extensions.ShowingType.EXTENSIONS: | 434 case extensions.ShowingType.EXTENSIONS: |
371 items = this.manager_.extensions; | 435 items = this.manager_.extensions; |
372 break; | 436 break; |
373 case extensions.ShowingType.APPS: | 437 case extensions.ShowingType.APPS: |
374 items = this.manager_.apps; | 438 items = this.manager_.apps; |
375 break; | 439 break; |
376 } | 440 } |
377 | 441 |
378 this.manager_.$/* hack */ ['items-list'].set('items', assert(items)); | 442 this.manager_.$/* hack */ ['items-list'].set('items', assert(items)); |
379 this.manager_.changePage(Page.ITEM_LIST); | 443 this.manager_.changePage({page: Page.LIST}); |
380 }, | 444 }, |
381 | 445 |
382 /** @override */ | 446 /** @override */ |
383 showKeyboardShortcuts: function() { | 447 showKeyboardShortcuts: function() { |
384 this.manager_.changePage(Page.KEYBOARD_SHORTCUTS); | 448 this.manager_.changePage({page: Page.SHORTCUTS}); |
385 }, | 449 }, |
386 }; | 450 }; |
387 | 451 |
388 return {Manager: Manager}; | 452 return {Manager: Manager}; |
389 }); | 453 }); |
OLD | NEW |