Chromium Code Reviews| 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.NavigationHelper} | |
| 77 */ | |
| 78 navigationHelper_: Object, | |
| 79 | |
| 80 /** | |
| 81 * The current page being shown. | |
| 82 * @private {!PageState} | |
| 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.navigationHelper_ = | |
| 119 new extensions.NavigationHelper(function(newPage) { | |
| 120 this.changePage(newPage, true); | |
| 121 }.bind(this)); | |
| 122 this.optionsDialog.addEventListener('close', function() { | |
| 123 // We update the page when the options dialog closes, but only if we're | |
| 124 // still on the details page. We could be on a different page if the | |
| 125 // user hit back while the options dialog was visible; in that case, the | |
| 126 // new page is already correct. | |
| 127 if (this.currentPage_.page == Page.DETAILS) { | |
| 128 // This will update the currentPage_ and the NavigationHelper; since | |
| 129 // the active page is already the details page, no main page | |
| 130 // transition occurs. | |
| 131 this.changePage({page: Page.DETAILS, id: this.currentPage_.id}); | |
| 132 } | |
| 133 }.bind(this)); | |
| 117 }, | 134 }, |
| 118 | 135 |
| 119 get keyboardShortcuts() { | 136 get keyboardShortcuts() { |
| 120 return this.$['keyboard-shortcuts']; | 137 return this.$['keyboard-shortcuts']; |
| 121 }, | 138 }, |
| 122 | 139 |
| 123 get packDialog() { | 140 get packDialog() { |
| 124 return this.$['pack-dialog']; | 141 return this.$['pack-dialog']; |
| 125 }, | 142 }, |
| 126 | 143 |
| 127 get loadError() { | 144 get loadError() { |
| 128 return this.$['load-error']; | 145 return this.$['load-error']; |
| 129 }, | 146 }, |
| 130 | 147 |
| 131 get optionsDialog() { | 148 get optionsDialog() { |
| 132 return this.$['options-dialog']; | 149 return this.$['options-dialog']; |
| 133 }, | 150 }, |
| 134 | 151 |
| 135 get errorPage() { | 152 get errorPage() { |
| 136 return this.$['error-page']; | 153 return this.$['error-page']; |
| 137 }, | 154 }, |
| 138 | 155 |
| 139 /** | 156 /** |
| 140 * Shows the details view for a given item. | 157 * Shows the details view for a given item. |
| 141 * @param {!chrome.developerPrivate.ExtensionInfo} data | 158 * @param {!chrome.developerPrivate.ExtensionInfo} data |
| 142 */ | 159 */ |
| 143 showItemDetails: function(data) { | 160 showItemDetails: function(data) { |
| 144 this.$['items-list'].willShowItemSubpage(data.id); | 161 this.changePage({page: Page.DETAILS, id: data.id}); |
| 145 this.detailViewItem_ = data; | |
| 146 this.changePage(Page.DETAIL_VIEW); | |
| 147 }, | 162 }, |
| 148 | 163 |
| 149 /** | 164 /** |
| 165 * Initializes the page to reflect what's specified in the url so that if | |
| 166 * the user visits chrome://extensions/?id=..., we land on the proper page. | |
| 167 */ | |
| 168 initPage: function() { | |
| 169 this.changePage(this.navigationHelper_.getCurrentPage(), true); | |
| 170 }, | |
| 171 | |
| 172 /** | |
| 150 * @param {!CustomEvent} event | 173 * @param {!CustomEvent} event |
| 151 * @private | 174 * @private |
| 152 */ | 175 */ |
| 153 onFilterChanged_: function(event) { | 176 onFilterChanged_: function(event) { |
| 154 this.filter = /** @type {string} */ (event.detail); | 177 this.filter = /** @type {string} */ (event.detail); |
| 155 }, | 178 }, |
| 156 | 179 |
| 180 /** @private */ | |
| 157 onMenuButtonTap_: function() { | 181 onMenuButtonTap_: function() { |
| 158 this.$.drawer.toggle(); | 182 this.$.drawer.toggle(); |
| 159 }, | 183 }, |
| 160 | 184 |
| 161 /** | 185 /** |
| 162 * @param {chrome.developerPrivate.ExtensionType} type The type of item. | 186 * @param {chrome.developerPrivate.ExtensionType} type The type of item. |
| 163 * @return {string} The ID of the list that the item belongs in. | 187 * @return {string} The ID of the list that the item belongs in. |
| 164 * @private | 188 * @private |
| 165 */ | 189 */ |
| 166 getListId_: function(type) { | 190 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. | 215 * @return {number} The index of the item in the list, or -1 if not found. |
| 192 * @private | 216 * @private |
| 193 */ | 217 */ |
| 194 getIndexInList_: function(listId, itemId) { | 218 getIndexInList_: function(listId, itemId) { |
| 195 return this[listId].findIndex(function(item) { | 219 return this[listId].findIndex(function(item) { |
| 196 return item.id == itemId; | 220 return item.id == itemId; |
| 197 }); | 221 }); |
| 198 }, | 222 }, |
| 199 | 223 |
| 200 /** | 224 /** |
| 225 * @return {?chrome.developerPrivate.ExtensionInfo} | |
| 226 * @private | |
| 227 */ | |
| 228 getData_: function(id) { | |
| 229 return this.extensions[this.getIndexInList_('extensions', id)] || | |
| 230 this.apps[this.getIndexInList_('apps', id)]; | |
| 231 }, | |
| 232 | |
| 233 /** | |
| 201 * @return {boolean} Whether the list should be visible. | 234 * @return {boolean} Whether the list should be visible. |
| 202 * @private | 235 * @private |
| 203 */ | 236 */ |
| 204 computeListHidden_: function() { | 237 computeListHidden_: function() { |
| 205 return this.$['items-list'].items.length == 0; | 238 return this.$['items-list'].items.length == 0; |
| 206 }, | 239 }, |
| 207 | 240 |
| 208 /** | 241 /** |
| 209 * Creates and adds a new extensions-item element to the list, inserting it | 242 * Creates and adds a new extensions-item element to the list, inserting it |
| 210 * into its sorted position in the relevant section. | 243 * 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. | 266 // We should never try and update a non-existent item. |
| 234 assert(index >= 0); | 267 assert(index >= 0); |
| 235 this.set([listId, index], item); | 268 this.set([listId, index], item); |
| 236 | 269 |
| 237 // Update the subpage if it is open and displaying the item. If it's not | 270 // 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 | 271 // 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 | 272 // 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 | 273 // that the DOM will have stale data, but there's no point in causing the |
| 241 // extra work. | 274 // extra work. |
| 242 if (this.detailViewItem_ && this.detailViewItem_.id == item.id && | 275 if (this.detailViewItem_ && this.detailViewItem_.id == item.id && |
| 243 this.$.pages.selected == Page.DETAIL_VIEW) { | 276 this.$.pages.selected == Page.DETAILS) { |
| 244 this.detailViewItem_ = item; | 277 this.detailViewItem_ = item; |
| 245 } else if (this.errorPageItem_ && this.errorPageItem_.id == item.id && | 278 } else if (this.errorPageItem_ && this.errorPageItem_.id == item.id && |
| 246 this.$.pages.selected == Page.ERROR_PAGE) { | 279 this.$.pages.selected == Page.ERRORS) { |
| 247 this.errorPageItem_ = item; | 280 this.errorPageItem_ = item; |
| 248 } | 281 } |
| 249 }, | 282 }, |
| 250 | 283 |
| 251 /** | 284 /** |
| 252 * @param {!chrome.developerPrivate.ExtensionInfo} item The data for the | 285 * @param {!chrome.developerPrivate.ExtensionInfo} item The data for the |
| 253 * item to remove. | 286 * item to remove. |
| 254 */ | 287 */ |
| 255 removeItem: function(item) { | 288 removeItem: function(item) { |
| 256 var listId = this.getListId_(item.type); | 289 var listId = this.getListId_(item.type); |
| 257 var index = this.getIndexInList_(listId, item.id); | 290 var index = this.getIndexInList_(listId, item.id); |
| 258 // We should never try and remove a non-existent item. | 291 // We should never try and remove a non-existent item. |
| 259 assert(index >= 0); | 292 assert(index >= 0); |
| 260 this.splice(listId, index, 1); | 293 this.splice(listId, index, 1); |
| 261 }, | 294 }, |
| 262 | 295 |
| 263 /** | 296 /** |
| 264 * @param {Page} page | 297 * @param {Page} page |
| 265 * @return {!(extensions.KeyboardShortcuts | | 298 * @return {!(extensions.KeyboardShortcuts | |
| 266 * extensions.DetailView | | 299 * extensions.DetailView | |
| 267 * extensions.ItemList)} | 300 * extensions.ItemList)} |
| 268 * @private | 301 * @private |
| 269 */ | 302 */ |
| 270 getPage_: function(page) { | 303 getPage_: function(page) { |
| 271 switch (page) { | 304 switch (page) { |
| 272 case Page.ITEM_LIST: | 305 case Page.LIST: |
| 273 return this.$['items-list']; | 306 return this.$['items-list']; |
| 274 case Page.DETAIL_VIEW: | 307 case Page.DETAILS: |
| 275 return this.$['details-view']; | 308 return this.$['details-view']; |
| 276 case Page.KEYBOARD_SHORTCUTS: | 309 case Page.SHORTCUTS: |
| 277 return this.$['keyboard-shortcuts']; | 310 return this.$['keyboard-shortcuts']; |
| 278 case Page.ERROR_PAGE: | 311 case Page.ERRORS: |
| 279 return this.$['error-page']; | 312 return this.$['error-page']; |
| 280 } | 313 } |
| 281 assertNotReached(); | 314 assertNotReached(); |
| 282 }, | 315 }, |
| 283 | 316 |
| 284 /** | 317 /** |
| 285 * Changes the active page selection. | 318 * Changes the active page selection. |
| 286 * @param {Page} toPage | 319 * @param {PageState} newPage |
| 320 * @param {boolean=} isSilent If true, does not notify the navigation helper | |
| 321 * of the change. | |
| 287 */ | 322 */ |
| 288 changePage: function(toPage) { | 323 changePage: function(newPage, isSilent) { |
| 324 if (this.currentPage_.page == newPage.page && | |
| 325 this.currentPage_.subpage == newPage.subpage && | |
| 326 this.currentPage_.id == newPage.id) { | |
| 327 return; | |
| 328 } | |
| 329 | |
| 289 this.$.drawer.closeDrawer(); | 330 this.$.drawer.closeDrawer(); |
| 331 if (this.optionsDialog.open) | |
| 332 this.optionsDialog.close(); | |
| 333 | |
| 290 var fromPage = this.$.pages.selected; | 334 var fromPage = this.$.pages.selected; |
| 291 if (fromPage == toPage) | 335 var toPage = newPage.page; |
| 292 return; | 336 var data; |
| 293 var entry; | 337 if (newPage.id) { |
| 294 var exit; | 338 data = this.getData_(newPage.id); |
| 295 if (fromPage == Page.ITEM_LIST && (toPage == Page.DETAIL_VIEW || | 339 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 } | 340 } |
| 310 this.getPage_(fromPage).animationHelper.setExitAnimations(exit); | 341 |
| 311 this.getPage_(toPage).animationHelper.setEntryAnimations(entry); | 342 if (toPage == Page.DETAILS) { |
| 312 this.$.pages.selected = toPage; | 343 assert(newPage.id); |
|
michaelpg
2017/05/01 23:41:25
throughout this whole function: can you assert on
Devlin
2017/05/02 01:04:07
Done.
| |
| 344 this.detailViewItem_ = data; | |
| 345 } else if (toPage == Page.ERRORS) { | |
| 346 assert(newPage.id); | |
| 347 this.errorPageItem_ = data; | |
| 348 } | |
| 349 | |
| 350 if (fromPage != toPage) { | |
| 351 var entry; | |
|
michaelpg
2017/05/01 23:41:25
optional: extract this block into a standalone fun
Devlin
2017/05/02 01:04:06
I think that since it's only used here, relies on
michaelpg
2017/05/02 20:58:09
Acknowledged.
| |
| 352 var exit; | |
| 353 if (fromPage == Page.LIST && (toPage == Page.DETAILS || | |
| 354 toPage == Page.ERRORS)) { | |
| 355 assert(newPage.id); | |
|
michaelpg
2017/05/01 23:41:25
duplicate assertion?
Devlin
2017/05/02 01:04:06
Removed.
| |
| 356 this.$['items-list'].willShowItemSubpage(data.id); | |
| 357 entry = [extensions.Animation.HERO]; | |
| 358 // The item grid can be larger than the detail view that we're | |
| 359 // hero'ing into, so we want to also fade out to avoid any jarring. | |
| 360 exit = [extensions.Animation.HERO, extensions.Animation.FADE_OUT]; | |
| 361 } else if (toPage == Page.LIST) { | |
| 362 entry = [extensions.Animation.FADE_IN]; | |
| 363 exit = [extensions.Animation.SCALE_DOWN]; | |
| 364 } else { | |
| 365 assert(toPage == Page.DETAILS || | |
| 366 toPage == Page.SHORTCUTS); | |
| 367 entry = [extensions.Animation.FADE_IN]; | |
| 368 exit = [extensions.Animation.FADE_OUT]; | |
| 369 } | |
| 370 | |
| 371 this.getPage_(fromPage).animationHelper.setExitAnimations(exit); | |
| 372 this.getPage_(toPage).animationHelper.setEntryAnimations(entry); | |
| 373 this.$.pages.selected = toPage; | |
| 374 } | |
| 375 | |
| 376 if (newPage.subpage) { | |
| 377 assert(newPage.subpage == Dialog.OPTIONS); | |
| 378 assert(newPage.id); | |
| 379 this.optionsDialog.show(data); | |
| 380 } | |
| 381 | |
| 382 this.currentPage_ = newPage; | |
| 383 | |
| 384 if (!isSilent) | |
| 385 this.navigationHelper_.updateHistory(newPage); | |
| 313 }, | 386 }, |
| 314 | 387 |
| 315 /** | 388 /** |
| 316 * Handles the event for the user clicking on a details button. | 389 * Handles the event for the user clicking on a details button. |
| 317 * @param {!CustomEvent} e | 390 * @param {!CustomEvent} e |
| 318 * @private | 391 * @private |
| 319 */ | 392 */ |
| 320 onShouldShowItemDetails_: function(e) { | 393 onShouldShowItemDetails_: function(e) { |
| 321 this.showItemDetails(e.detail.data); | 394 this.showItemDetails(e.detail.data); |
| 322 }, | 395 }, |
| 323 | 396 |
| 324 /** | 397 /** |
| 325 * Handles the event for the user clicking on the errors button. | 398 * Handles the event for the user clicking on the errors button. |
| 326 * @param {!CustomEvent} e | 399 * @param {!CustomEvent} e |
| 327 * @private | 400 * @private |
| 328 */ | 401 */ |
| 329 onShouldShowItemErrors_: function(e) { | 402 onShouldShowItemErrors_: function(e) { |
| 330 var data = e.detail.data; | 403 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 }, | 404 }, |
| 335 | 405 |
| 336 /** @private */ | 406 /** @private */ |
| 337 onDetailsViewClose_: function() { | 407 onDetailsViewClose_: function() { |
| 338 // Note: we don't reset detailViewItem_ here because doing so just causes | 408 // Note: we don't reset detailViewItem_ here because doing so just causes |
| 339 // extra work for the data-bound details view. | 409 // extra work for the data-bound details view. |
| 340 this.changePage(Page.ITEM_LIST); | 410 this.changePage({page: Page.LIST}); |
| 341 }, | 411 }, |
| 342 | 412 |
| 343 /** @private */ | 413 /** @private */ |
| 344 onErrorPageClose_: function() { | 414 onErrorPageClose_: function() { |
| 345 // Note: we don't reset errorPageItem_ here because doing so just causes | 415 // Note: we don't reset errorPageItem_ here because doing so just causes |
| 346 // extra work for the data-bound error page. | 416 // extra work for the data-bound error page. |
| 347 this.changePage(Page.ITEM_LIST); | 417 this.changePage({page: Page.LIST}); |
| 348 }, | 418 }, |
| 349 | 419 |
| 350 /** @private */ | 420 /** @private */ |
| 351 onPackTap_: function() { | 421 onPackTap_: function() { |
| 352 this.$['pack-dialog'].show(); | 422 this.$['pack-dialog'].show(); |
| 353 } | 423 } |
| 354 }); | 424 }); |
| 355 | 425 |
| 356 /** | 426 /** |
| 357 * @param {extensions.Manager} manager | 427 * @param {extensions.Manager} manager |
| (...skipping 11 matching lines...) Expand all Loading... | |
| 369 switch (type) { | 439 switch (type) { |
| 370 case extensions.ShowingType.EXTENSIONS: | 440 case extensions.ShowingType.EXTENSIONS: |
| 371 items = this.manager_.extensions; | 441 items = this.manager_.extensions; |
| 372 break; | 442 break; |
| 373 case extensions.ShowingType.APPS: | 443 case extensions.ShowingType.APPS: |
| 374 items = this.manager_.apps; | 444 items = this.manager_.apps; |
| 375 break; | 445 break; |
| 376 } | 446 } |
| 377 | 447 |
| 378 this.manager_.$/* hack */ ['items-list'].set('items', assert(items)); | 448 this.manager_.$/* hack */ ['items-list'].set('items', assert(items)); |
| 379 this.manager_.changePage(Page.ITEM_LIST); | 449 this.manager_.changePage({page: Page.LIST}); |
| 380 }, | 450 }, |
| 381 | 451 |
| 382 /** @override */ | 452 /** @override */ |
| 383 showKeyboardShortcuts: function() { | 453 showKeyboardShortcuts: function() { |
| 384 this.manager_.changePage(Page.KEYBOARD_SHORTCUTS); | 454 this.manager_.changePage({page: Page.SHORTCUTS}); |
| 385 }, | 455 }, |
| 386 }; | 456 }; |
| 387 | 457 |
| 388 return {Manager: Manager}; | 458 return {Manager: Manager}; |
| 389 }); | 459 }); |
| OLD | NEW |