| OLD | NEW |
| 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2012 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 // <include src="extension_error.js"> | 5 // <include src="extension_error.js"> |
| 6 | 6 |
| 7 cr.define('extensions', function() { | 7 cr.define('extensions', function() { |
| 8 'use strict'; | 8 'use strict'; |
| 9 | 9 |
| 10 var ExtensionType = chrome.developerPrivate.ExtensionType; | 10 var ExtensionType = chrome.developerPrivate.ExtensionType; |
| (...skipping 66 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 77 function compareLocation(x, y) { | 77 function compareLocation(x, y) { |
| 78 if (x.location == y.location) | 78 if (x.location == y.location) |
| 79 return 0; | 79 return 0; |
| 80 if (x.location == chrome.developerPrivate.Location.UNPACKED) | 80 if (x.location == chrome.developerPrivate.Location.UNPACKED) |
| 81 return -1; | 81 return -1; |
| 82 if (y.location == chrome.developerPrivate.Location.UNPACKED) | 82 if (y.location == chrome.developerPrivate.Location.UNPACKED) |
| 83 return 1; | 83 return 1; |
| 84 return 0; | 84 return 0; |
| 85 } | 85 } |
| 86 return compareLocation(a, b) || | 86 return compareLocation(a, b) || |
| 87 compare(a.name.toLowerCase(), b.name.toLowerCase()) || | 87 compare(a.name.toLowerCase(), b.name.toLowerCase()) || |
| 88 compare(a.id, b.id); | 88 compare(a.id, b.id); |
| 89 } | 89 } |
| 90 | 90 |
| 91 /** @interface */ | 91 /** @interface */ |
| 92 function ExtensionListDelegate() {} | 92 function ExtensionListDelegate() {} |
| 93 | 93 |
| 94 ExtensionListDelegate.prototype = { | 94 ExtensionListDelegate.prototype = { |
| 95 /** | 95 /** |
| 96 * Called when the number of extensions in the list has changed. | 96 * Called when the number of extensions in the list has changed. |
| 97 */ | 97 */ |
| 98 onExtensionCountChanged: assertNotReached, | 98 onExtensionCountChanged: assertNotReached, |
| (...skipping 65 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 164 */ | 164 */ |
| 165 initialize: function(delegate) { | 165 initialize: function(delegate) { |
| 166 /** @private {!Array<chrome.developerPrivate.ExtensionInfo>} */ | 166 /** @private {!Array<chrome.developerPrivate.ExtensionInfo>} */ |
| 167 this.extensions_ = []; | 167 this.extensions_ = []; |
| 168 | 168 |
| 169 /** @private {!extensions.ExtensionListDelegate} */ | 169 /** @private {!extensions.ExtensionListDelegate} */ |
| 170 this.delegate_ = delegate; | 170 this.delegate_ = delegate; |
| 171 | 171 |
| 172 this.resetLoadFinished(); | 172 this.resetLoadFinished(); |
| 173 | 173 |
| 174 chrome.developerPrivate.onItemStateChanged.addListener( | 174 chrome.developerPrivate.onItemStateChanged.addListener(function( |
| 175 function(eventData) { | 175 eventData) { |
| 176 var EventType = chrome.developerPrivate.EventType; | 176 var EventType = chrome.developerPrivate.EventType; |
| 177 switch (eventData.event_type) { | 177 switch (eventData.event_type) { |
| 178 case EventType.VIEW_REGISTERED: | 178 case EventType.VIEW_REGISTERED: |
| 179 case EventType.VIEW_UNREGISTERED: | 179 case EventType.VIEW_UNREGISTERED: |
| 180 case EventType.INSTALLED: | 180 case EventType.INSTALLED: |
| 181 case EventType.LOADED: | 181 case EventType.LOADED: |
| 182 case EventType.UNLOADED: | 182 case EventType.UNLOADED: |
| 183 case EventType.ERROR_ADDED: | 183 case EventType.ERROR_ADDED: |
| 184 case EventType.ERRORS_REMOVED: | 184 case EventType.ERRORS_REMOVED: |
| 185 case EventType.PREFS_CHANGED: | 185 case EventType.PREFS_CHANGED: |
| (...skipping 60 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 246 updateExtensionsData: function(incognitoAvailable, enableAppInfoDialog) { | 246 updateExtensionsData: function(incognitoAvailable, enableAppInfoDialog) { |
| 247 // If we start to need more information about the extension configuration, | 247 // If we start to need more information about the extension configuration, |
| 248 // consider passing in the full object from the ExtensionSettings. | 248 // consider passing in the full object from the ExtensionSettings. |
| 249 this.incognitoAvailable_ = incognitoAvailable; | 249 this.incognitoAvailable_ = incognitoAvailable; |
| 250 this.enableAppInfoDialog_ = enableAppInfoDialog; | 250 this.enableAppInfoDialog_ = enableAppInfoDialog; |
| 251 /** @private {Promise} */ | 251 /** @private {Promise} */ |
| 252 this.extensionsUpdated_ = new Promise(function(resolve, reject) { | 252 this.extensionsUpdated_ = new Promise(function(resolve, reject) { |
| 253 chrome.developerPrivate.getExtensionsInfo( | 253 chrome.developerPrivate.getExtensionsInfo( |
| 254 {includeDisabled: true, includeTerminated: true}, | 254 {includeDisabled: true, includeTerminated: true}, |
| 255 function(extensions) { | 255 function(extensions) { |
| 256 // Sort in order of unpacked vs. packed, followed by name, followed by | 256 // Sort in order of unpacked vs. packed, followed by name, |
| 257 // id. | 257 // followed by id. |
| 258 extensions.sort(compareExtensions); | 258 extensions.sort(compareExtensions); |
| 259 this.extensions_ = extensions; | 259 this.extensions_ = extensions; |
| 260 this.showExtensionNodes_(); | 260 this.showExtensionNodes_(); |
| 261 | 261 |
| 262 // We keep the commands overlay's extension info in sync, so that we | 262 // We keep the commands overlay's extension info in sync, so that |
| 263 // don't duplicate the same querying logic there. | 263 // we don't duplicate the same querying logic there. |
| 264 ExtensionCommandsOverlay.updateExtensionsData(this.extensions_); | 264 ExtensionCommandsOverlay.updateExtensionsData(this.extensions_); |
| 265 | 265 |
| 266 resolve(); | 266 resolve(); |
| 267 | 267 |
| 268 // |resolve| is async so it's necessary to use |then| here in order to | 268 // |resolve| is async so it's necessary to use |then| here in |
| 269 // do work after other |then|s have finished. This is important so | 269 // order to do work after other |then|s have finished. This is |
| 270 // elements are visible when these updates happen. | 270 // important so elements are visible when these updates happen. |
| 271 this.extensionsUpdated_.then(function() { | 271 this.extensionsUpdated_.then(function() { |
| 272 this.onUpdateFinished_(); | 272 this.onUpdateFinished_(); |
| 273 this.resolveLoadFinished_(); | 273 this.resolveLoadFinished_(); |
| 274 }.bind(this)); | 274 }.bind(this)); |
| 275 }.bind(this)); | 275 }.bind(this)); |
| 276 }.bind(this)); | 276 }.bind(this)); |
| 277 return this.extensionsUpdated_; | 277 return this.extensionsUpdated_; |
| 278 }, | 278 }, |
| 279 | 279 |
| 280 /** | 280 /** |
| 281 * Updates elements that need to be visible in order to update properly. | 281 * Updates elements that need to be visible in order to update properly. |
| 282 * @private | 282 * @private |
| 283 */ | 283 */ |
| 284 onUpdateFinished_: function() { | 284 onUpdateFinished_: function() { |
| 285 // Cannot focus or highlight a extension if there are none, and we should | 285 // Cannot focus or highlight a extension if there are none, and we should |
| 286 // only scroll to a particular extension or open the options page once. | 286 // only scroll to a particular extension or open the options page once. |
| 287 if (this.extensions_.length == 0 || this.didInitialNavigation_) | 287 if (this.extensions_.length == 0 || this.didInitialNavigation_) |
| 288 return; | 288 return; |
| 289 | 289 |
| 290 this.didInitialNavigation_ = true; | 290 this.didInitialNavigation_ = true; |
| 291 assert(!this.hidden); | 291 assert(!this.hidden); |
| 292 assert(!this.parentElement.hidden); | 292 assert(!this.parentElement.hidden); |
| 293 | 293 |
| 294 var idToHighlight = this.getIdQueryParam_(); | 294 var idToHighlight = this.getIdQueryParam_(); |
| 295 if (idToHighlight) { | 295 if (idToHighlight) { |
| 296 var wrapper = $(idToHighlight); | 296 var wrapper = $(idToHighlight); |
| 297 if (wrapper) { | 297 if (wrapper) { |
| 298 this.scrollToWrapper_(idToHighlight); | 298 this.scrollToWrapper_(idToHighlight); |
| 299 | 299 |
| 300 var focusRow = wrapper.getFocusRow(); | 300 var focusRow = wrapper.getFocusRow(); |
| 301 (focusRow.getFirstFocusable('enabled') || | 301 (focusRow.getFirstFocusable('enabled') || |
| 302 focusRow.getFirstFocusable('remove-enterprise') || | 302 focusRow.getFirstFocusable('remove-enterprise') || |
| 303 focusRow.getFirstFocusable('website') || | 303 focusRow.getFirstFocusable('website') || |
| 304 focusRow.getFirstFocusable('details')).focus(); | 304 focusRow.getFirstFocusable('details')) |
| 305 .focus(); |
| 305 } | 306 } |
| 306 } | 307 } |
| 307 | 308 |
| 308 var idToOpenOptions = this.getOptionsQueryParam_(); | 309 var idToOpenOptions = this.getOptionsQueryParam_(); |
| 309 if (idToOpenOptions && $(idToOpenOptions)) | 310 if (idToOpenOptions && $(idToOpenOptions)) |
| 310 this.showEmbeddedExtensionOptions_(idToOpenOptions, true); | 311 this.showEmbeddedExtensionOptions_(idToOpenOptions, true); |
| 311 }, | 312 }, |
| 312 | 313 |
| 313 /** @return {number} The number of extensions being displayed. */ | 314 /** @return {number} The number of extensions being displayed. */ |
| 314 getNumExtensions: function() { | 315 getNumExtensions: function() { |
| (...skipping 30 matching lines...) Expand all Loading... |
| 345 var seenIds = []; | 346 var seenIds = []; |
| 346 | 347 |
| 347 // Iterate over the extension data and add each item to the list. | 348 // Iterate over the extension data and add each item to the list. |
| 348 this.extensions_.forEach(function(extension) { | 349 this.extensions_.forEach(function(extension) { |
| 349 seenIds.push(extension.id); | 350 seenIds.push(extension.id); |
| 350 this.updateOrCreateWrapper_(extension); | 351 this.updateOrCreateWrapper_(extension); |
| 351 }, this); | 352 }, this); |
| 352 this.focusGrid_.ensureRowActive(); | 353 this.focusGrid_.ensureRowActive(); |
| 353 | 354 |
| 354 // Remove extensions that are no longer installed. | 355 // Remove extensions that are no longer installed. |
| 355 var wrappers = document.querySelectorAll( | 356 var wrappers = |
| 356 '.extension-list-item-wrapper[id]'); | 357 document.querySelectorAll('.extension-list-item-wrapper[id]'); |
| 357 Array.prototype.forEach.call(wrappers, function(wrapper) { | 358 Array.prototype.forEach.call(wrappers, function(wrapper) { |
| 358 if (seenIds.indexOf(wrapper.id) < 0) | 359 if (seenIds.indexOf(wrapper.id) < 0) |
| 359 this.removeWrapper_(wrapper); | 360 this.removeWrapper_(wrapper); |
| 360 }, this); | 361 }, this); |
| 361 }, | 362 }, |
| 362 | 363 |
| 363 /** | 364 /** |
| 364 * Removes the wrapper from the DOM and updates the focused element if | 365 * Removes the wrapper from the DOM and updates the focused element if |
| 365 * needed. | 366 * needed. |
| 366 * @param {!Element} wrapper | 367 * @param {!Element} wrapper |
| 367 * @private | 368 * @private |
| 368 */ | 369 */ |
| 369 removeWrapper_: function(wrapper) { | 370 removeWrapper_: function(wrapper) { |
| 370 // If focus is in the wrapper about to be removed, move it first. This | 371 // If focus is in the wrapper about to be removed, move it first. This |
| 371 // happens when clicking the trash can to remove an extension. | 372 // happens when clicking the trash can to remove an extension. |
| 372 if (wrapper.contains(document.activeElement)) { | 373 if (wrapper.contains(document.activeElement)) { |
| 373 var wrappers = document.querySelectorAll( | 374 var wrappers = |
| 374 '.extension-list-item-wrapper[id]'); | 375 document.querySelectorAll('.extension-list-item-wrapper[id]'); |
| 375 var index = Array.prototype.indexOf.call(wrappers, wrapper); | 376 var index = Array.prototype.indexOf.call(wrappers, wrapper); |
| 376 assert(index != -1); | 377 assert(index != -1); |
| 377 var focusableWrapper = wrappers[index + 1] || wrappers[index - 1]; | 378 var focusableWrapper = wrappers[index + 1] || wrappers[index - 1]; |
| 378 if (focusableWrapper) { | 379 if (focusableWrapper) { |
| 379 var newFocusRow = focusableWrapper.getFocusRow(); | 380 var newFocusRow = focusableWrapper.getFocusRow(); |
| 380 newFocusRow.getEquivalentElement(document.activeElement).focus(); | 381 newFocusRow.getEquivalentElement(document.activeElement).focus(); |
| 381 } | 382 } |
| 382 } | 383 } |
| 383 | 384 |
| 384 var focusRow = wrapper.getFocusRow(); | 385 var focusRow = wrapper.getFocusRow(); |
| (...skipping 30 matching lines...) Expand all Loading... |
| 415 * wrapper list). | 416 * wrapper list). |
| 416 * @private | 417 * @private |
| 417 */ | 418 */ |
| 418 createWrapper_: function(extension, nextWrapper) { | 419 createWrapper_: function(extension, nextWrapper) { |
| 419 var wrapper = new ExtensionWrapper; | 420 var wrapper = new ExtensionWrapper; |
| 420 wrapper.id = extension.id; | 421 wrapper.id = extension.id; |
| 421 | 422 |
| 422 // The 'Permissions' link. | 423 // The 'Permissions' link. |
| 423 wrapper.setupColumn('details', '.permissions-link', 'click', function(e) { | 424 wrapper.setupColumn('details', '.permissions-link', 'click', function(e) { |
| 424 if (!this.permissionsPromptIsShowing_) { | 425 if (!this.permissionsPromptIsShowing_) { |
| 425 chrome.developerPrivate.showPermissionsDialog(extension.id, | 426 chrome.developerPrivate.showPermissionsDialog( |
| 426 function() { | 427 extension.id, function() { |
| 427 this.permissionsPromptIsShowing_ = false; | 428 this.permissionsPromptIsShowing_ = false; |
| 428 }.bind(this)); | 429 }.bind(this)); |
| 429 this.permissionsPromptIsShowing_ = true; | 430 this.permissionsPromptIsShowing_ = true; |
| 430 } | 431 } |
| 431 e.preventDefault(); | 432 e.preventDefault(); |
| 432 }); | 433 }); |
| 433 | 434 |
| 434 wrapper.setupColumn('options', '.options-button', 'click', function(e) { | 435 wrapper.setupColumn('options', '.options-button', 'click', function(e) { |
| 435 this.showEmbeddedExtensionOptions_(extension.id, false); | 436 this.showEmbeddedExtensionOptions_(extension.id, false); |
| 436 e.preventDefault(); | 437 e.preventDefault(); |
| 437 }.bind(this)); | 438 }.bind(this)); |
| 438 | 439 |
| (...skipping 25 matching lines...) Expand all Loading... |
| 464 var extensionId = extension.id; | 465 var extensionId = extension.id; |
| 465 assert(this.extensions_.length > 0); | 466 assert(this.extensions_.length > 0); |
| 466 var newEx = this.extensions_.filter(function(e) { | 467 var newEx = this.extensions_.filter(function(e) { |
| 467 return e.id == extensionId; | 468 return e.id == extensionId; |
| 468 })[0]; | 469 })[0]; |
| 469 var errors = newEx.manifestErrors.concat(newEx.runtimeErrors); | 470 var errors = newEx.manifestErrors.concat(newEx.runtimeErrors); |
| 470 extensions.ExtensionErrorOverlay.getInstance().setErrorsAndShowOverlay( | 471 extensions.ExtensionErrorOverlay.getInstance().setErrorsAndShowOverlay( |
| 471 errors, extensionId, newEx.name); | 472 errors, extensionId, newEx.name); |
| 472 }.bind(this)); | 473 }.bind(this)); |
| 473 | 474 |
| 474 wrapper.setupColumn('suspiciousLearnMore', | 475 wrapper.setupColumn( |
| 475 '.suspicious-install-message .learn-more-link'); | 476 'suspiciousLearnMore', |
| 477 '.suspicious-install-message .learn-more-link'); |
| 476 | 478 |
| 477 // The path, if provided by unpacked extension. | 479 // The path, if provided by unpacked extension. |
| 478 wrapper.setupColumn('loadPath', '.load-path a:first-of-type', 'click', | 480 wrapper.setupColumn( |
| 479 function(e) { | 481 'loadPath', '.load-path a:first-of-type', 'click', function(e) { |
| 480 chrome.developerPrivate.showPath(extension.id); | 482 chrome.developerPrivate.showPath(extension.id); |
| 481 e.preventDefault(); | 483 e.preventDefault(); |
| 482 }); | 484 }); |
| 483 | 485 |
| 484 // The 'allow in incognito' checkbox. | 486 // The 'allow in incognito' checkbox. |
| 485 wrapper.setupColumn('incognito', '.incognito-control input', 'change', | 487 wrapper.setupColumn( |
| 486 function(e) { | 488 'incognito', '.incognito-control input', 'change', function(e) { |
| 487 var butterBar = wrapper.querySelector('.butter-bar'); | 489 var butterBar = wrapper.querySelector('.butter-bar'); |
| 488 var checked = e.target.checked; | 490 var checked = e.target.checked; |
| 489 butterBar.hidden = !checked || | 491 butterBar.hidden = |
| 490 extension.type == ExtensionType.HOSTED_APP; | 492 !checked || extension.type == ExtensionType.HOSTED_APP; |
| 491 chrome.developerPrivate.updateExtensionConfiguration({ | 493 chrome.developerPrivate.updateExtensionConfiguration( |
| 492 extensionId: extension.id, | 494 {extensionId: extension.id, incognitoAccess: e.target.checked}); |
| 493 incognitoAccess: e.target.checked | 495 }.bind(this)); |
| 494 }); | |
| 495 }.bind(this)); | |
| 496 | 496 |
| 497 // The 'collect errors' checkbox. This should only be visible if the | 497 // The 'collect errors' checkbox. This should only be visible if the |
| 498 // error console is enabled - we can detect this by the existence of the | 498 // error console is enabled - we can detect this by the existence of the |
| 499 // |errorCollectionEnabled| property. | 499 // |errorCollectionEnabled| property. |
| 500 wrapper.setupColumn('collectErrors', '.error-collection-control input', | 500 wrapper.setupColumn( |
| 501 'change', function(e) { | 501 'collectErrors', '.error-collection-control input', 'change', |
| 502 chrome.developerPrivate.updateExtensionConfiguration({ | 502 function(e) { |
| 503 extensionId: extension.id, | 503 chrome.developerPrivate.updateExtensionConfiguration( |
| 504 errorCollection: e.target.checked | 504 {extensionId: extension.id, errorCollection: e.target.checked}); |
| 505 }); | 505 }); |
| 506 }); | |
| 507 | 506 |
| 508 // The 'allow on all urls' checkbox. This should only be visible if | 507 // The 'allow on all urls' checkbox. This should only be visible if |
| 509 // active script restrictions are enabled. If they are not enabled, no | 508 // active script restrictions are enabled. If they are not enabled, no |
| 510 // extensions should want all urls. | 509 // extensions should want all urls. |
| 511 wrapper.setupColumn('allUrls', '.all-urls-control input', 'click', | 510 wrapper.setupColumn( |
| 512 function(e) { | 511 'allUrls', '.all-urls-control input', 'click', function(e) { |
| 513 chrome.developerPrivate.updateExtensionConfiguration({ | 512 chrome.developerPrivate.updateExtensionConfiguration( |
| 514 extensionId: extension.id, | 513 {extensionId: extension.id, runOnAllUrls: e.target.checked}); |
| 515 runOnAllUrls: e.target.checked | 514 }); |
| 516 }); | |
| 517 }); | |
| 518 | 515 |
| 519 // The 'allow file:// access' checkbox. | 516 // The 'allow file:// access' checkbox. |
| 520 wrapper.setupColumn('localUrls', '.file-access-control input', 'click', | 517 wrapper.setupColumn( |
| 521 function(e) { | 518 'localUrls', '.file-access-control input', 'click', function(e) { |
| 522 chrome.developerPrivate.updateExtensionConfiguration({ | 519 chrome.developerPrivate.updateExtensionConfiguration( |
| 523 extensionId: extension.id, | 520 {extensionId: extension.id, fileAccess: e.target.checked}); |
| 524 fileAccess: e.target.checked | 521 }); |
| 525 }); | |
| 526 }); | |
| 527 | 522 |
| 528 // The 'Reload' terminated link. | 523 // The 'Reload' terminated link. |
| 529 wrapper.setupColumn('terminatedReload', '.terminated-reload-link', | 524 wrapper.setupColumn( |
| 530 'click', function(e) { | 525 'terminatedReload', '.terminated-reload-link', 'click', function(e) { |
| 531 chrome.developerPrivate.reload(extension.id, {failQuietly: true}); | 526 chrome.developerPrivate.reload(extension.id, {failQuietly: true}); |
| 532 }); | 527 }); |
| 533 | 528 |
| 534 // The 'Repair' corrupted link. | 529 // The 'Repair' corrupted link. |
| 535 wrapper.setupColumn('repair', '.corrupted-repair-button', 'click', | 530 wrapper.setupColumn( |
| 536 function(e) { | 531 'repair', '.corrupted-repair-button', 'click', function(e) { |
| 537 chrome.developerPrivate.repairExtension(extension.id); | 532 chrome.developerPrivate.repairExtension(extension.id); |
| 538 }); | 533 }); |
| 539 | 534 |
| 540 // The 'Enabled' checkbox. | 535 // The 'Enabled' checkbox. |
| 541 wrapper.setupColumn('enabled', '.enable-checkbox input', 'click', | 536 wrapper.setupColumn( |
| 542 function(e) { | 537 'enabled', '.enable-checkbox input', 'click', function(e) { |
| 543 var checked = e.target.checked; | 538 var checked = e.target.checked; |
| 544 // TODO(devlin): What should we do if this fails? Ideally we want to | 539 // TODO(devlin): What should we do if this fails? Ideally we want to |
| 545 // show some kind of error or feedback to the user if this fails. | 540 // show some kind of error or feedback to the user if this fails. |
| 546 chrome.management.setEnabled(extension.id, checked); | 541 chrome.management.setEnabled(extension.id, checked); |
| 547 | 542 |
| 548 // This may seem counter-intuitive (to not set/clear the checkmark) | 543 // This may seem counter-intuitive (to not set/clear the checkmark) |
| 549 // but this page will be updated asynchronously if the extension | 544 // but this page will be updated asynchronously if the extension |
| 550 // becomes enabled/disabled. It also might not become enabled or | 545 // becomes enabled/disabled. It also might not become enabled or |
| 551 // disabled, because the user might e.g. get prompted when enabling | 546 // disabled, because the user might e.g. get prompted when enabling |
| 552 // and choose not to. | 547 // and choose not to. |
| 553 e.preventDefault(); | 548 e.preventDefault(); |
| 554 }); | 549 }); |
| 555 | 550 |
| 556 // 'Remove' button. | 551 // 'Remove' button. |
| 557 var trash = cloneTemplate('trash'); | 552 var trash = cloneTemplate('trash'); |
| 558 trash.title = loadTimeData.getString('extensionUninstall'); | 553 trash.title = loadTimeData.getString('extensionUninstall'); |
| 559 | 554 |
| 560 wrapper.querySelector('.enable-controls').appendChild(trash); | 555 wrapper.querySelector('.enable-controls').appendChild(trash); |
| 561 | 556 |
| 562 wrapper.setupColumn('remove-enterprise', '.trash', 'click', function(e) { | 557 wrapper.setupColumn('remove-enterprise', '.trash', 'click', function(e) { |
| 563 trash.classList.add('open'); | 558 trash.classList.add('open'); |
| 564 trash.classList.toggle('mouse-clicked', e.detail > 0); | 559 trash.classList.toggle('mouse-clicked', e.detail > 0); |
| 565 if (this.uninstallIsShowing_) | 560 if (this.uninstallIsShowing_) |
| 566 return; | 561 return; |
| 567 this.uninstallIsShowing_ = true; | 562 this.uninstallIsShowing_ = true; |
| 568 chrome.management.uninstall(extension.id, | 563 chrome.management.uninstall( |
| 569 {showConfirmDialog: true}, | 564 extension.id, {showConfirmDialog: true}, function() { |
| 570 function() { | 565 // TODO(devlin): What should we do if the uninstall fails? |
| 571 // TODO(devlin): What should we do if the uninstall fails? | 566 this.uninstallIsShowing_ = false; |
| 572 this.uninstallIsShowing_ = false; | |
| 573 | 567 |
| 574 if (trash.classList.contains('mouse-clicked')) | 568 if (trash.classList.contains('mouse-clicked')) |
| 575 trash.blur(); | 569 trash.blur(); |
| 576 | 570 |
| 577 if (chrome.runtime.lastError) { | 571 if (chrome.runtime.lastError) { |
| 578 // The uninstall failed (e.g. a cancel). Allow the trash to close. | 572 // The uninstall failed (e.g. a cancel). Allow the trash to |
| 579 trash.classList.remove('open'); | 573 // close. |
| 580 } else { | 574 trash.classList.remove('open'); |
| 581 // Leave the trash open if the uninstall succeded. Otherwise it can | 575 } else { |
| 582 // half-close right before it's removed when the DOM is modified. | 576 // Leave the trash open if the uninstall succeded. Otherwise it |
| 583 } | 577 // can half-close right before it's removed when the DOM is |
| 584 }.bind(this)); | 578 // modified. |
| 579 } |
| 580 }.bind(this)); |
| 585 }.bind(this)); | 581 }.bind(this)); |
| 586 | 582 |
| 587 // Maintain the order that nodes should be in when creating as well as | 583 // Maintain the order that nodes should be in when creating as well as |
| 588 // when adding only one new wrapper. | 584 // when adding only one new wrapper. |
| 589 this.insertBefore(wrapper, nextWrapper); | 585 this.insertBefore(wrapper, nextWrapper); |
| 590 this.updateWrapper_(extension, wrapper); | 586 this.updateWrapper_(extension, wrapper); |
| 591 | 587 |
| 592 var nextRow = this.focusGrid_.getRowForRoot(nextWrapper); // May be null. | 588 var nextRow = this.focusGrid_.getRowForRoot(nextWrapper); // May be null. |
| 593 this.focusGrid_.addRowBefore(wrapper.getFocusRow(), nextRow); | 589 this.focusGrid_.addRowBefore(wrapper.getFocusRow(), nextRow); |
| 594 }, | 590 }, |
| 595 | 591 |
| 596 /** | 592 /** |
| 597 * Updates an HTML element for the extension metadata given in |extension|. | 593 * Updates an HTML element for the extension metadata given in |extension|. |
| 598 * @param {!chrome.developerPrivate.ExtensionInfo} extension A dictionary of | 594 * @param {!chrome.developerPrivate.ExtensionInfo} extension A dictionary of |
| 599 * extension metadata. | 595 * extension metadata. |
| 600 * @param {!Element} wrapper The extension wrapper element to update. | 596 * @param {!Element} wrapper The extension wrapper element to update. |
| 601 * @private | 597 * @private |
| 602 */ | 598 */ |
| 603 updateWrapper_: function(extension, wrapper) { | 599 updateWrapper_: function(extension, wrapper) { |
| 604 var isActive = | 600 var isActive = |
| 605 extension.state == chrome.developerPrivate.ExtensionState.ENABLED; | 601 extension.state == chrome.developerPrivate.ExtensionState.ENABLED; |
| 606 wrapper.classList.toggle('inactive-extension', !isActive); | 602 wrapper.classList.toggle('inactive-extension', !isActive); |
| 607 wrapper.classList.remove('controlled', 'may-not-remove'); | 603 wrapper.classList.remove('controlled', 'may-not-remove'); |
| 608 | 604 |
| 609 if (extension.controlledInfo) { | 605 if (extension.controlledInfo) { |
| 610 wrapper.classList.add('controlled'); | 606 wrapper.classList.add('controlled'); |
| 611 } else if (!extension.userMayModify || | 607 } else if ( |
| 612 extension.mustRemainInstalled || | 608 !extension.userMayModify || extension.mustRemainInstalled || |
| 613 extension.dependentExtensions.length > 0) { | 609 extension.dependentExtensions.length > 0) { |
| 614 wrapper.classList.add('may-not-remove'); | 610 wrapper.classList.add('may-not-remove'); |
| 615 } | 611 } |
| 616 | 612 |
| 617 var item = wrapper.querySelector('.extension-list-item'); | 613 var item = wrapper.querySelector('.extension-list-item'); |
| 618 item.style.backgroundImage = 'url(' + extension.iconUrl + ')'; | 614 item.style.backgroundImage = 'url(' + extension.iconUrl + ')'; |
| 619 | 615 |
| 620 this.setText_(wrapper, '.extension-title', extension.name); | 616 this.setText_(wrapper, '.extension-title', extension.name); |
| 621 this.setText_(wrapper, '.extension-version', extension.version); | 617 this.setText_(wrapper, '.extension-version', extension.version); |
| 622 this.setText_(wrapper, '.location-text', extension.locationText || ''); | 618 this.setText_(wrapper, '.location-text', extension.locationText || ''); |
| 623 this.setText_(wrapper, '.blacklist-text', extension.blacklistText || ''); | 619 this.setText_(wrapper, '.blacklist-text', extension.blacklistText || ''); |
| 624 this.setText_(wrapper, '.extension-description', extension.description); | 620 this.setText_(wrapper, '.extension-description', extension.description); |
| 625 | 621 |
| 626 // The 'allow in incognito' checkbox. | 622 // The 'allow in incognito' checkbox. |
| 627 this.updateVisibility_(wrapper, '.incognito-control', | 623 this.updateVisibility_( |
| 628 isActive && this.incognitoAvailable_, | 624 wrapper, '.incognito-control', isActive && this.incognitoAvailable_, |
| 629 function(item) { | 625 function(item) { |
| 630 var incognito = item.querySelector('input'); | 626 var incognito = item.querySelector('input'); |
| 631 incognito.disabled = !extension.incognitoAccess.isEnabled; | 627 incognito.disabled = !extension.incognitoAccess.isEnabled; |
| 632 incognito.checked = extension.incognitoAccess.isActive; | 628 incognito.checked = extension.incognitoAccess.isActive; |
| 633 }); | 629 }); |
| 634 var showButterBar = isActive && | 630 var showButterBar = isActive && extension.incognitoAccess.isActive && |
| 635 extension.incognitoAccess.isActive && | 631 extension.type != ExtensionType.HOSTED_APP; |
| 636 extension.type != ExtensionType.HOSTED_APP; | |
| 637 // The 'allow in incognito' butter bar. | 632 // The 'allow in incognito' butter bar. |
| 638 this.updateVisibility_(wrapper, '.butter-bar', showButterBar); | 633 this.updateVisibility_(wrapper, '.butter-bar', showButterBar); |
| 639 | 634 |
| 640 // The 'collect errors' checkbox. This should only be visible if the | 635 // The 'collect errors' checkbox. This should only be visible if the |
| 641 // error console is enabled - we can detect this by the existence of the | 636 // error console is enabled - we can detect this by the existence of the |
| 642 // |errorCollectionEnabled| property. | 637 // |errorCollectionEnabled| property. |
| 643 this.updateVisibility_( | 638 this.updateVisibility_( |
| 644 wrapper, '.error-collection-control', | 639 wrapper, '.error-collection-control', |
| 645 isActive && extension.errorCollection.isEnabled, | 640 isActive && extension.errorCollection.isEnabled, function(item) { |
| 646 function(item) { | 641 item.querySelector('input').checked = |
| 647 item.querySelector('input').checked = | 642 extension.errorCollection.isActive; |
| 648 extension.errorCollection.isActive; | 643 }); |
| 649 }); | |
| 650 | 644 |
| 651 // The 'allow on all urls' checkbox. This should only be visible if | 645 // The 'allow on all urls' checkbox. This should only be visible if |
| 652 // active script restrictions are enabled. If they are not enabled, no | 646 // active script restrictions are enabled. If they are not enabled, no |
| 653 // extensions should want all urls. | 647 // extensions should want all urls. |
| 654 this.updateVisibility_( | 648 this.updateVisibility_( |
| 655 wrapper, '.all-urls-control', | 649 wrapper, '.all-urls-control', |
| 656 isActive && extension.runOnAllUrls.isEnabled, | 650 isActive && extension.runOnAllUrls.isEnabled, function(item) { |
| 657 function(item) { | 651 item.querySelector('input').checked = |
| 658 item.querySelector('input').checked = extension.runOnAllUrls.isActive; | 652 extension.runOnAllUrls.isActive; |
| 659 }); | 653 }); |
| 660 | 654 |
| 661 // The 'allow file:// access' checkbox. | 655 // The 'allow file:// access' checkbox. |
| 662 this.updateVisibility_(wrapper, '.file-access-control', | 656 this.updateVisibility_( |
| 663 isActive && extension.fileAccess.isEnabled, | 657 wrapper, '.file-access-control', |
| 664 function(item) { | 658 isActive && extension.fileAccess.isEnabled, function(item) { |
| 665 item.querySelector('input').checked = extension.fileAccess.isActive; | 659 item.querySelector('input').checked = extension.fileAccess.isActive; |
| 666 }); | 660 }); |
| 667 | 661 |
| 668 // The 'Options' button or link, depending on its behaviour. | 662 // The 'Options' button or link, depending on its behaviour. |
| 669 var optionsEnabled = isActive && !!extension.optionsPage; | 663 var optionsEnabled = isActive && !!extension.optionsPage; |
| 670 this.updateVisibility_(wrapper, '.options-link', optionsEnabled && | 664 this.updateVisibility_( |
| 671 extension.optionsPage.openInTab); | 665 wrapper, '.options-link', |
| 672 this.updateVisibility_(wrapper, '.options-button', optionsEnabled && | 666 optionsEnabled && extension.optionsPage.openInTab); |
| 673 !extension.optionsPage.openInTab); | 667 this.updateVisibility_( |
| 668 wrapper, '.options-button', |
| 669 optionsEnabled && !extension.optionsPage.openInTab); |
| 674 | 670 |
| 675 // The 'View in Web Store/View Web Site' link. | 671 // The 'View in Web Store/View Web Site' link. |
| 676 var siteLinkEnabled = !!extension.homePage.url && | 672 var siteLinkEnabled = |
| 677 !this.enableAppInfoDialog_; | 673 !!extension.homePage.url && !this.enableAppInfoDialog_; |
| 678 this.updateVisibility_(wrapper, '.site-link', siteLinkEnabled, | 674 this.updateVisibility_( |
| 679 function(item) { | 675 wrapper, '.site-link', siteLinkEnabled, function(item) { |
| 680 item.href = extension.homePage.url; | 676 item.href = extension.homePage.url; |
| 681 item.textContent = loadTimeData.getString( | 677 item.textContent = loadTimeData.getString( |
| 682 extension.homePage.specified ? 'extensionSettingsVisitWebsite' : | 678 extension.homePage.specified ? |
| 683 'extensionSettingsVisitWebStore'); | 679 'extensionSettingsVisitWebsite' : |
| 684 }); | 680 'extensionSettingsVisitWebStore'); |
| 681 }); |
| 685 | 682 |
| 686 var isUnpacked = | 683 var isUnpacked = |
| 687 extension.location == chrome.developerPrivate.Location.UNPACKED; | 684 extension.location == chrome.developerPrivate.Location.UNPACKED; |
| 688 // The 'Reload' link. | 685 // The 'Reload' link. |
| 689 this.updateVisibility_(wrapper, '.reload-link', isActive && isUnpacked); | 686 this.updateVisibility_(wrapper, '.reload-link', isActive && isUnpacked); |
| 690 | 687 |
| 691 // The 'Launch' link. | 688 // The 'Launch' link. |
| 692 this.updateVisibility_( | 689 this.updateVisibility_( |
| 693 wrapper, '.launch-link', | 690 wrapper, '.launch-link', |
| 694 isUnpacked && extension.type == ExtensionType.PLATFORM_APP && | 691 isUnpacked && extension.type == ExtensionType.PLATFORM_APP && |
| 695 isActive); | 692 isActive); |
| 696 | 693 |
| 697 // The 'Errors' link. | 694 // The 'Errors' link. |
| 698 var hasErrors = extension.runtimeErrors.length > 0 || | 695 var hasErrors = extension.runtimeErrors.length > 0 || |
| 699 extension.manifestErrors.length > 0; | 696 extension.manifestErrors.length > 0; |
| 700 this.updateVisibility_(wrapper, '.errors-link', hasErrors, | 697 this.updateVisibility_( |
| 701 function(item) { | 698 wrapper, '.errors-link', hasErrors, function(item) { |
| 702 var Level = chrome.developerPrivate.ErrorLevel; | 699 var Level = chrome.developerPrivate.ErrorLevel; |
| 703 | 700 |
| 704 var map = {}; | 701 var map = {}; |
| 705 map[Level.LOG] = {weight: 0, name: 'extension-error-info-icon'}; | 702 map[Level.LOG] = {weight: 0, name: 'extension-error-info-icon'}; |
| 706 map[Level.WARN] = {weight: 1, name: 'extension-error-warning-icon'}; | 703 map[Level.WARN] = {weight: 1, name: 'extension-error-warning-icon'}; |
| 707 map[Level.ERROR] = {weight: 2, name: 'extension-error-fatal-icon'}; | 704 map[Level.ERROR] = {weight: 2, name: 'extension-error-fatal-icon'}; |
| 708 | 705 |
| 709 // Find the highest severity of all the errors; manifest errors all have | 706 // Find the highest severity of all the errors; manifest errors all |
| 710 // a 'warning' level severity. | 707 // have a 'warning' level severity. |
| 711 var highestSeverity = extension.runtimeErrors.reduce( | 708 var highestSeverity = |
| 712 function(prev, error) { | 709 extension.runtimeErrors.reduce(function(prev, error) { |
| 713 return map[error.severity].weight > map[prev].weight ? | 710 return map[error.severity].weight > map[prev].weight ? |
| 714 error.severity : prev; | 711 error.severity : |
| 715 }, extension.manifestErrors.length ? Level.WARN : Level.LOG); | 712 prev; |
| 713 }, extension.manifestErrors.length ? Level.WARN : Level.LOG); |
| 716 | 714 |
| 717 // Adjust the class on the icon. | 715 // Adjust the class on the icon. |
| 718 var icon = item.querySelector('.extension-error-icon'); | 716 var icon = item.querySelector('.extension-error-icon'); |
| 719 // TODO(hcarmona): Populate alt text with a proper description since | 717 // TODO(hcarmona): Populate alt text with a proper description since |
| 720 // this icon conveys the severity of the error. (info, warning, fatal). | 718 // this icon conveys the severity of the error. (info, warning, |
| 721 icon.alt = ''; | 719 // fatal). |
| 722 icon.className = 'extension-error-icon'; // Remove other classes. | 720 icon.alt = ''; |
| 723 icon.classList.add(map[highestSeverity].name); | 721 icon.className = 'extension-error-icon'; // Remove other classes. |
| 724 }); | 722 icon.classList.add(map[highestSeverity].name); |
| 723 }); |
| 725 | 724 |
| 726 // The 'Reload' terminated link. | 725 // The 'Reload' terminated link. |
| 727 var isTerminated = | 726 var isTerminated = |
| 728 extension.state == chrome.developerPrivate.ExtensionState.TERMINATED; | 727 extension.state == chrome.developerPrivate.ExtensionState.TERMINATED; |
| 729 this.updateVisibility_(wrapper, '.terminated-reload-link', isTerminated); | 728 this.updateVisibility_(wrapper, '.terminated-reload-link', isTerminated); |
| 730 | 729 |
| 731 // The 'Repair' corrupted link. | 730 // The 'Repair' corrupted link. |
| 732 var canRepair = !isTerminated && | 731 var canRepair = !isTerminated && |
| 733 extension.disableReasons.corruptInstall && | 732 extension.disableReasons.corruptInstall && |
| 734 extension.location == | 733 extension.location == chrome.developerPrivate.Location.FROM_STORE; |
| 735 chrome.developerPrivate.Location.FROM_STORE; | |
| 736 this.updateVisibility_(wrapper, '.corrupted-repair-button', canRepair); | 734 this.updateVisibility_(wrapper, '.corrupted-repair-button', canRepair); |
| 737 | 735 |
| 738 // The 'Enabled' checkbox. | 736 // The 'Enabled' checkbox. |
| 739 var isOK = !isTerminated && !canRepair; | 737 var isOK = !isTerminated && !canRepair; |
| 740 this.updateVisibility_(wrapper, '.enable-checkbox', isOK, function(item) { | 738 this.updateVisibility_(wrapper, '.enable-checkbox', isOK, function(item) { |
| 741 var enableCheckboxDisabled = | 739 var enableCheckboxDisabled = !extension.userMayModify || |
| 742 !extension.userMayModify || | |
| 743 extension.disableReasons.suspiciousInstall || | 740 extension.disableReasons.suspiciousInstall || |
| 744 extension.disableReasons.corruptInstall || | 741 extension.disableReasons.corruptInstall || |
| 745 extension.disableReasons.updateRequired || | 742 extension.disableReasons.updateRequired || |
| 746 extension.dependentExtensions.length > 0 || | 743 extension.dependentExtensions.length > 0 || |
| 747 extension.state == | 744 extension.state == |
| 748 chrome.developerPrivate.ExtensionState.BLACKLISTED; | 745 chrome.developerPrivate.ExtensionState.BLACKLISTED; |
| 749 item.querySelector('input').disabled = enableCheckboxDisabled; | 746 item.querySelector('input').disabled = enableCheckboxDisabled; |
| 750 item.querySelector('input').checked = isActive; | 747 item.querySelector('input').checked = isActive; |
| 751 }); | 748 }); |
| 752 | 749 |
| (...skipping 29 matching lines...) Expand all Loading... |
| 782 controlNode.removeChild(indicator); | 779 controlNode.removeChild(indicator); |
| 783 } | 780 } |
| 784 | 781 |
| 785 // Developer mode //////////////////////////////////////////////////////// | 782 // Developer mode //////////////////////////////////////////////////////// |
| 786 | 783 |
| 787 // First we have the id. | 784 // First we have the id. |
| 788 var idLabel = wrapper.querySelector('.extension-id'); | 785 var idLabel = wrapper.querySelector('.extension-id'); |
| 789 idLabel.textContent = ' ' + extension.id; | 786 idLabel.textContent = ' ' + extension.id; |
| 790 | 787 |
| 791 // Then the path, if provided by unpacked extension. | 788 // Then the path, if provided by unpacked extension. |
| 792 this.updateVisibility_(wrapper, '.load-path', isUnpacked, | 789 this.updateVisibility_(wrapper, '.load-path', isUnpacked, function(item) { |
| 793 function(item) { | |
| 794 item.querySelector('a:first-of-type').textContent = | 790 item.querySelector('a:first-of-type').textContent = |
| 795 ' ' + extension.prettifiedPath; | 791 ' ' + extension.prettifiedPath; |
| 796 }); | 792 }); |
| 797 | 793 |
| 798 // Then the 'managed, cannot uninstall/disable' message. | 794 // Then the 'managed, cannot uninstall/disable' message. |
| 799 // We would like to hide managed installed message since this | 795 // We would like to hide managed installed message since this |
| 800 // extension is disabled. | 796 // extension is disabled. |
| 801 var isRequired = | 797 var isRequired = |
| 802 !extension.userMayModify || extension.mustRemainInstalled; | 798 !extension.userMayModify || extension.mustRemainInstalled; |
| 803 this.updateVisibility_(wrapper, '.managed-message', isRequired && | 799 this.updateVisibility_( |
| 804 !extension.disableReasons.updateRequired); | 800 wrapper, '.managed-message', |
| 801 isRequired && !extension.disableReasons.updateRequired); |
| 805 | 802 |
| 806 // Then the 'This isn't from the webstore, looks suspicious' message. | 803 // Then the 'This isn't from the webstore, looks suspicious' message. |
| 807 var isSuspicious = extension.disableReasons.suspiciousInstall; | 804 var isSuspicious = extension.disableReasons.suspiciousInstall; |
| 808 this.updateVisibility_(wrapper, '.suspicious-install-message', | 805 this.updateVisibility_( |
| 809 !isRequired && isSuspicious); | 806 wrapper, '.suspicious-install-message', !isRequired && isSuspicious); |
| 810 | 807 |
| 811 // Then the 'This is a corrupt extension' message. | 808 // Then the 'This is a corrupt extension' message. |
| 812 this.updateVisibility_(wrapper, '.corrupt-install-message', !isRequired && | 809 this.updateVisibility_( |
| 813 extension.disableReasons.corruptInstall); | 810 wrapper, '.corrupt-install-message', |
| 811 !isRequired && extension.disableReasons.corruptInstall); |
| 814 | 812 |
| 815 // Then the 'An update required by enterprise policy' message. Note that | 813 // Then the 'An update required by enterprise policy' message. Note that |
| 816 // a force-installed extension might be disabled due to being outdated | 814 // a force-installed extension might be disabled due to being outdated |
| 817 // as well. | 815 // as well. |
| 818 this.updateVisibility_(wrapper, '.update-required-message', | 816 this.updateVisibility_( |
| 819 extension.disableReasons.updateRequired); | 817 wrapper, '.update-required-message', |
| 818 extension.disableReasons.updateRequired); |
| 820 | 819 |
| 821 // The 'following extensions depend on this extension' list. | 820 // The 'following extensions depend on this extension' list. |
| 822 var hasDependents = extension.dependentExtensions.length > 0; | 821 var hasDependents = extension.dependentExtensions.length > 0; |
| 823 wrapper.classList.toggle('developer-extras', hasDependents); | 822 wrapper.classList.toggle('developer-extras', hasDependents); |
| 824 this.updateVisibility_(wrapper, '.dependent-extensions-message', | 823 this.updateVisibility_( |
| 825 hasDependents, function(item) { | 824 wrapper, '.dependent-extensions-message', hasDependents, |
| 826 var dependentList = item.querySelector('ul'); | 825 function(item) { |
| 827 dependentList.textContent = ''; | 826 var dependentList = item.querySelector('ul'); |
| 828 extension.dependentExtensions.forEach(function(dependentExtension) { | 827 dependentList.textContent = ''; |
| 829 var depNode = cloneTemplate('dependent-list-item'); | 828 extension.dependentExtensions.forEach(function(dependentExtension) { |
| 830 depNode.querySelector('.dep-extension-title').textContent = | 829 var depNode = cloneTemplate('dependent-list-item'); |
| 831 dependentExtension.name; | 830 depNode.querySelector('.dep-extension-title').textContent = |
| 832 depNode.querySelector('.dep-extension-id').textContent = | 831 dependentExtension.name; |
| 833 dependentExtension.id; | 832 depNode.querySelector('.dep-extension-id').textContent = |
| 834 dependentList.appendChild(depNode); | 833 dependentExtension.id; |
| 835 }, this); | 834 dependentList.appendChild(depNode); |
| 836 }.bind(this)); | 835 }, this); |
| 836 }.bind(this)); |
| 837 | 837 |
| 838 // The active views. | 838 // The active views. |
| 839 this.updateVisibility_(wrapper, '.active-views', | 839 this.updateVisibility_( |
| 840 extension.views.length > 0, function(item) { | 840 wrapper, '.active-views', extension.views.length > 0, function(item) { |
| 841 var link = item.querySelector('a'); | 841 var link = item.querySelector('a'); |
| 842 | 842 |
| 843 // Link needs to be an only child before the list is updated. | 843 // Link needs to be an only child before the list is updated. |
| 844 while (link.nextElementSibling) | 844 while (link.nextElementSibling) |
| 845 item.removeChild(link.nextElementSibling); | 845 item.removeChild(link.nextElementSibling); |
| 846 | 846 |
| 847 // Link needs to be cleaned up if it was used before. | 847 // Link needs to be cleaned up if it was used before. |
| 848 link.textContent = ''; | 848 link.textContent = ''; |
| 849 if (link.clickHandler) | 849 if (link.clickHandler) |
| 850 link.removeEventListener('click', link.clickHandler); | 850 link.removeEventListener('click', link.clickHandler); |
| 851 | 851 |
| 852 extension.views.forEach(function(view, i) { | 852 extension.views.forEach(function(view, i) { |
| 853 if (view.type == chrome.developerPrivate.ViewType.EXTENSION_DIALOG || | 853 if (view.type == |
| 854 view.type == chrome.developerPrivate.ViewType.EXTENSION_POPUP) { | 854 chrome.developerPrivate.ViewType.EXTENSION_DIALOG || |
| 855 return; | 855 view.type == |
| 856 } | 856 chrome.developerPrivate.ViewType.EXTENSION_POPUP) { |
| 857 var displayName; | 857 return; |
| 858 if (view.url.startsWith('chrome-extension://')) { | 858 } |
| 859 var pathOffset = 'chrome-extension://'.length + 32 + 1; | 859 var displayName; |
| 860 displayName = view.url.substring(pathOffset); | 860 if (view.url.startsWith('chrome-extension://')) { |
| 861 if (displayName == '_generated_background_page.html') | 861 var pathOffset = 'chrome-extension://'.length + 32 + 1; |
| 862 displayName = loadTimeData.getString('backgroundPage'); | 862 displayName = view.url.substring(pathOffset); |
| 863 } else { | 863 if (displayName == '_generated_background_page.html') |
| 864 displayName = view.url; | 864 displayName = loadTimeData.getString('backgroundPage'); |
| 865 } | 865 } else { |
| 866 var label = displayName + | 866 displayName = view.url; |
| 867 (view.incognito ? | 867 } |
| 868 ' ' + loadTimeData.getString('viewIncognito') : '') + | 868 var label = displayName + |
| 869 (view.renderProcessId == -1 ? | 869 (view.incognito ? |
| 870 ' ' + loadTimeData.getString('viewInactive') : '') + | 870 ' ' + loadTimeData.getString('viewIncognito') : |
| 871 (view.isIframe ? | 871 '') + |
| 872 ' ' + loadTimeData.getString('viewIframe') : ''); | 872 (view.renderProcessId == -1 ? |
| 873 link.textContent = label; | 873 ' ' + loadTimeData.getString('viewInactive') : |
| 874 link.clickHandler = function(e) { | 874 '') + |
| 875 chrome.developerPrivate.openDevTools({ | 875 (view.isIframe ? ' ' + loadTimeData.getString('viewIframe') : |
| 876 extensionId: extension.id, | 876 ''); |
| 877 renderProcessId: view.renderProcessId, | 877 link.textContent = label; |
| 878 renderViewId: view.renderViewId, | 878 link.clickHandler = function(e) { |
| 879 incognito: view.incognito | 879 chrome.developerPrivate.openDevTools({ |
| 880 extensionId: extension.id, |
| 881 renderProcessId: view.renderProcessId, |
| 882 renderViewId: view.renderViewId, |
| 883 incognito: view.incognito |
| 884 }); |
| 885 }; |
| 886 link.addEventListener('click', link.clickHandler); |
| 887 |
| 888 if (i < extension.views.length - 1) { |
| 889 link = link.cloneNode(true); |
| 890 item.appendChild(link); |
| 891 } |
| 892 |
| 893 wrapper.setupColumn('activeView', '.active-views a:last-of-type'); |
| 880 }); | 894 }); |
| 881 }; | 895 }); |
| 882 link.addEventListener('click', link.clickHandler); | |
| 883 | |
| 884 if (i < extension.views.length - 1) { | |
| 885 link = link.cloneNode(true); | |
| 886 item.appendChild(link); | |
| 887 } | |
| 888 | |
| 889 wrapper.setupColumn('activeView', '.active-views a:last-of-type'); | |
| 890 }); | |
| 891 }); | |
| 892 | 896 |
| 893 // The extension warnings (describing runtime issues). | 897 // The extension warnings (describing runtime issues). |
| 894 this.updateVisibility_(wrapper, '.extension-warnings', | 898 this.updateVisibility_( |
| 895 extension.runtimeWarnings.length > 0, | 899 wrapper, '.extension-warnings', extension.runtimeWarnings.length > 0, |
| 896 function(item) { | 900 function(item) { |
| 897 var warningList = item.querySelector('ul'); | 901 var warningList = item.querySelector('ul'); |
| 898 warningList.textContent = ''; | 902 warningList.textContent = ''; |
| 899 extension.runtimeWarnings.forEach(function(warning) { | 903 extension.runtimeWarnings.forEach(function(warning) { |
| 900 var li = document.createElement('li'); | 904 var li = document.createElement('li'); |
| 901 warningList.appendChild(li).innerText = warning; | 905 warningList.appendChild(li).innerText = warning; |
| 902 }); | 906 }); |
| 903 }); | 907 }); |
| 904 | 908 |
| 905 // Install warnings. | 909 // Install warnings. |
| 906 this.updateVisibility_(wrapper, '.install-warnings', | 910 this.updateVisibility_( |
| 907 extension.installWarnings.length > 0, | 911 wrapper, '.install-warnings', extension.installWarnings.length > 0, |
| 908 function(item) { | 912 function(item) { |
| 909 var installWarningList = item.querySelector('ul'); | 913 var installWarningList = item.querySelector('ul'); |
| 910 installWarningList.textContent = ''; | 914 installWarningList.textContent = ''; |
| 911 if (extension.installWarnings) { | 915 if (extension.installWarnings) { |
| 912 extension.installWarnings.forEach(function(warning) { | 916 extension.installWarnings.forEach(function(warning) { |
| 913 var li = document.createElement('li'); | 917 var li = document.createElement('li'); |
| 914 li.innerText = warning; | 918 li.innerText = warning; |
| 915 installWarningList.appendChild(li); | 919 installWarningList.appendChild(li); |
| 920 }); |
| 921 } |
| 916 }); | 922 }); |
| 917 } | |
| 918 }); | |
| 919 | 923 |
| 920 if (location.hash.substr(1) == extension.id) { | 924 if (location.hash.substr(1) == extension.id) { |
| 921 // Scroll beneath the fixed header so that the extension is not | 925 // Scroll beneath the fixed header so that the extension is not |
| 922 // obscured. | 926 // obscured. |
| 923 var topScroll = wrapper.offsetTop - $('page-header').offsetHeight; | 927 var topScroll = wrapper.offsetTop - $('page-header').offsetHeight; |
| 924 var pad = parseInt(window.getComputedStyle(wrapper).marginTop, 10); | 928 var pad = parseInt(window.getComputedStyle(wrapper).marginTop, 10); |
| 925 if (!isNaN(pad)) | 929 if (!isNaN(pad)) |
| 926 topScroll -= pad / 2; | 930 topScroll -= pad / 2; |
| 927 setScrollTopForDocument(document, topScroll); | 931 setScrollTopForDocument(document, topScroll); |
| 928 } | 932 } |
| (...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 964 * @param {boolean} scroll Whether the page should scroll to the extension | 968 * @param {boolean} scroll Whether the page should scroll to the extension |
| 965 * @private | 969 * @private |
| 966 */ | 970 */ |
| 967 showEmbeddedExtensionOptions_: function(extensionId, scroll) { | 971 showEmbeddedExtensionOptions_: function(extensionId, scroll) { |
| 968 if (this.optionsShown_) | 972 if (this.optionsShown_) |
| 969 return; | 973 return; |
| 970 | 974 |
| 971 // Get the extension from the given id. | 975 // Get the extension from the given id. |
| 972 var extension = this.extensions_.filter(function(extension) { | 976 var extension = this.extensions_.filter(function(extension) { |
| 973 return extension.state == | 977 return extension.state == |
| 974 chrome.developerPrivate.ExtensionState.ENABLED && | 978 chrome.developerPrivate.ExtensionState.ENABLED && |
| 975 extension.id == extensionId; | 979 extension.id == extensionId; |
| 976 })[0]; | 980 })[0]; |
| 977 | 981 |
| 978 if (!extension) | 982 if (!extension) |
| 979 return; | 983 return; |
| 980 | 984 |
| 981 if (scroll) | 985 if (scroll) |
| 982 this.scrollToWrapper_(extensionId); | 986 this.scrollToWrapper_(extensionId); |
| 983 | 987 |
| 984 // Add the options query string. Corner case: the 'options' query string | 988 // Add the options query string. Corner case: the 'options' query string |
| 985 // will clobber the 'id' query string if the options link is clicked when | 989 // will clobber the 'id' query string if the options link is clicked when |
| 986 // 'id' is in the URL, or if both query strings are in the URL. | 990 // 'id' is in the URL, or if both query strings are in the URL. |
| 987 window.history.replaceState({}, '', '/?options=' + extensionId); | 991 window.history.replaceState({}, '', '/?options=' + extensionId); |
| 988 | 992 |
| 989 var overlay = extensions.ExtensionOptionsOverlay.getInstance(); | 993 var overlay = extensions.ExtensionOptionsOverlay.getInstance(); |
| 990 var shownCallback = function() { | 994 var shownCallback = function() { |
| 991 // This overlay doesn't get focused automatically as <extensionoptions> | 995 // This overlay doesn't get focused automatically as <extensionoptions> |
| 992 // is created after the overlay is shown. | 996 // is created after the overlay is shown. |
| 993 if (cr.ui.FocusOutlineManager.forDocument(document).visible) | 997 if (cr.ui.FocusOutlineManager.forDocument(document).visible) |
| 994 overlay.setInitialFocus(); | 998 overlay.setInitialFocus(); |
| 995 }; | 999 }; |
| 996 overlay.setExtensionAndShow(extensionId, extension.name, | 1000 overlay.setExtensionAndShow( |
| 997 extension.iconUrl, shownCallback); | 1001 extensionId, extension.name, extension.iconUrl, shownCallback); |
| 998 this.optionsShown_ = true; | 1002 this.optionsShown_ = true; |
| 999 | 1003 |
| 1000 var self = this; | 1004 var self = this; |
| 1001 $('overlay').addEventListener('cancelOverlay', function f() { | 1005 $('overlay').addEventListener('cancelOverlay', function f() { |
| 1002 self.optionsShown_ = false; | 1006 self.optionsShown_ = false; |
| 1003 $('overlay').removeEventListener('cancelOverlay', f); | 1007 $('overlay').removeEventListener('cancelOverlay', f); |
| 1004 | 1008 |
| 1005 // Remove the options query string. | 1009 // Remove the options query string. |
| 1006 window.history.replaceState({}, '', '/'); | 1010 window.history.replaceState({}, '', '/'); |
| 1007 }); | 1011 }); |
| (...skipping 47 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1055 this.createWrapper_(extension, nextExt ? $(nextExt.id) : null); | 1059 this.createWrapper_(extension, nextExt ? $(nextExt.id) : null); |
| 1056 } | 1060 } |
| 1057 } | 1061 } |
| 1058 }; | 1062 }; |
| 1059 | 1063 |
| 1060 return { | 1064 return { |
| 1061 ExtensionList: ExtensionList, | 1065 ExtensionList: ExtensionList, |
| 1062 ExtensionListDelegate: ExtensionListDelegate | 1066 ExtensionListDelegate: ExtensionListDelegate |
| 1063 }; | 1067 }; |
| 1064 }); | 1068 }); |
| OLD | NEW |