Chromium Code Reviews| 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 /** | 7 /** |
| 8 * The type of the extension data object. The definition is based on | 8 * The type of the extension data object. The definition is based on |
| 9 * chrome/browser/ui/webui/extensions/extension_basic_info.cc | 9 * chrome/browser/ui/webui/extensions/extension_basic_info.cc |
| 10 * and | 10 * and |
| (...skipping 85 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 96 | 96 |
| 97 /** | 97 /** |
| 98 * Indicates whether an embedded options page that was navigated to through | 98 * Indicates whether an embedded options page that was navigated to through |
| 99 * the '?options=' URL query has been shown to the user. This is necessary | 99 * the '?options=' URL query has been shown to the user. This is necessary |
| 100 * to prevent showExtensionNodes_ from opening the options more than once. | 100 * to prevent showExtensionNodes_ from opening the options more than once. |
| 101 * @type {boolean} | 101 * @type {boolean} |
| 102 * @private | 102 * @private |
| 103 */ | 103 */ |
| 104 optionsShown_: false, | 104 optionsShown_: false, |
| 105 | 105 |
| 106 /** | |
| 107 * Necessary to only show the butterbar once. | |
| 108 * @private {boolean} | |
| 109 */ | |
| 110 butterbarShown_: false, | |
| 111 | |
| 106 decorate: function() { | 112 decorate: function() { |
| 107 this.textContent = ''; | |
| 108 | |
| 109 this.showExtensionNodes_(); | 113 this.showExtensionNodes_(); |
| 110 }, | 114 }, |
| 111 | 115 |
| 112 getIdQueryParam_: function() { | 116 getIdQueryParam_: function() { |
| 113 return parseQueryParams(document.location)['id']; | 117 return parseQueryParams(document.location)['id']; |
| 114 }, | 118 }, |
| 115 | 119 |
| 116 getOptionsQueryParam_: function() { | 120 getOptionsQueryParam_: function() { |
| 117 return parseQueryParams(document.location)['options']; | 121 return parseQueryParams(document.location)['options']; |
| 118 }, | 122 }, |
| 119 | 123 |
| 120 /** | 124 /** |
| 121 * Creates all extension items from scratch. | 125 * Creates all extension items from scratch. |
| 122 * @private | 126 * @private |
| 123 */ | 127 */ |
| 124 showExtensionNodes_: function() { | 128 showExtensionNodes_: function() { |
| 125 // Iterate over the extension data and add each item to the list. | 129 // Iterate over the extension data and add each item to the list. |
| 126 this.data_.extensions.forEach(this.createNode_, this); | 130 this.data_.extensions.forEach(function(extension) { |
| 131 var node = $(extension.id); | |
| 132 | |
| 133 if (node) | |
| 134 this.updateNode_(extension, node); | |
| 135 else | |
| 136 this.createNode_(extension); | |
| 137 }, this); | |
| 127 | 138 |
| 128 var idToHighlight = this.getIdQueryParam_(); | 139 var idToHighlight = this.getIdQueryParam_(); |
| 129 if (idToHighlight && $(idToHighlight)) | 140 if (idToHighlight && $(idToHighlight)) |
| 130 this.scrollToNode_(idToHighlight); | 141 this.scrollToNode_(idToHighlight); |
| 131 | 142 |
| 132 var idToOpenOptions = this.getOptionsQueryParam_(); | 143 var idToOpenOptions = this.getOptionsQueryParam_(); |
| 133 if (idToOpenOptions && $(idToOpenOptions)) | 144 if (idToOpenOptions && $(idToOpenOptions)) |
| 134 this.showEmbeddedExtensionOptions_(idToOpenOptions, true); | 145 this.showEmbeddedExtensionOptions_(idToOpenOptions, true); |
| 135 | 146 |
| 136 if (this.data_.extensions.length == 0) | 147 if (this.data_.extensions.length == 0) |
| (...skipping 11 matching lines...) Expand all Loading... | |
| 148 // Scroll offset should be calculated slightly higher than the actual | 159 // Scroll offset should be calculated slightly higher than the actual |
| 149 // offset of the element being scrolled to, so that it ends up not all | 160 // offset of the element being scrolled to, so that it ends up not all |
| 150 // the way at the top. That way it is clear that there are more elements | 161 // the way at the top. That way it is clear that there are more elements |
| 151 // above the element being scrolled to. | 162 // above the element being scrolled to. |
| 152 var scrollFudge = 1.2; | 163 var scrollFudge = 1.2; |
| 153 var scrollTop = $(extensionId).offsetTop - scrollFudge * | 164 var scrollTop = $(extensionId).offsetTop - scrollFudge * |
| 154 $(extensionId).clientHeight; | 165 $(extensionId).clientHeight; |
| 155 setScrollTopForDocument(document, scrollTop); | 166 setScrollTopForDocument(document, scrollTop); |
| 156 }, | 167 }, |
| 157 | 168 |
| 169 // TODO(hcarmona): Remove this temporary hack before clicking commit. | |
| 170 <include src="create_node.js"> | |
| 171 <include src="update_node.js"> | |
| 172 | |
| 158 /** | 173 /** |
| 159 * Synthesizes and initializes an HTML element for the extension metadata | 174 * Adds a listener to an element. |
| 160 * given in |extension|. | 175 * @param {string} type The type of listener to add. |
| 161 * @param {ExtensionData} extension A dictionary of extension metadata. | 176 * @param {Element} node Ancestor of the element specified by |query|. |
| 177 * @param {string} query A query to select an element in |node|. | |
| 178 * @param {function({Event} e)} onclick The function that should be called | |
| 179 * on click. | |
| 162 * @private | 180 * @private |
| 163 */ | 181 */ |
| 164 createNode_: function(extension) { | 182 addListener_: function(type, node, query, onclick) { |
| 165 var template = $('template-collection').querySelector( | 183 node.querySelector(query).addEventListener(type, onclick); |
| 166 '.extension-list-item-wrapper'); | |
| 167 var node = template.cloneNode(true); | |
| 168 node.id = extension.id; | |
| 169 | |
| 170 if (!extension.enabled || extension.terminated) | |
| 171 node.classList.add('inactive-extension'); | |
| 172 | |
| 173 var classes = []; | |
| 174 if (extension.managedInstall) { | |
| 175 classes.push('policy-controlled', 'may-not-modify'); | |
| 176 } else if (extension.dependentExtensions.length > 0) { | |
| 177 classes.push('may-not-remove', 'may-not-modify'); | |
| 178 } else if (extension.recommendedInstall) { | |
| 179 classes.push('may-not-remove'); | |
| 180 } else if (extension.suspiciousInstall || | |
| 181 extension.corruptInstall || | |
| 182 extension.updateRequiredByPolicy) { | |
| 183 classes.push('may-not-modify'); | |
| 184 } | |
| 185 node.classList.add.apply(node.classList, classes); | |
| 186 | |
| 187 var idToHighlight = this.getIdQueryParam_(); | |
| 188 if (node.id == idToHighlight) | |
| 189 node.classList.add('extension-highlight'); | |
| 190 | |
| 191 var item = node.querySelector('.extension-list-item'); | |
| 192 // Prevent the image cache of extension icon by using the reloaded | |
| 193 // timestamp as a query string. The timestamp is recorded when the user | |
| 194 // clicks the 'Reload' link. http://crbug.com/159302. | |
| 195 if (extensionReloadedTimestamp[extension.id]) { | |
| 196 item.style.backgroundImage = | |
| 197 'url(' + extension.icon + '?' + | |
| 198 extensionReloadedTimestamp[extension.id] + ')'; | |
| 199 } else { | |
| 200 item.style.backgroundImage = 'url(' + extension.icon + ')'; | |
| 201 } | |
| 202 | |
| 203 var title = node.querySelector('.extension-title'); | |
| 204 title.textContent = extension.name; | |
| 205 | |
| 206 var version = node.querySelector('.extension-version'); | |
| 207 version.textContent = extension.version; | |
| 208 | |
| 209 var locationText = node.querySelector('.location-text'); | |
| 210 locationText.textContent = extension.locationText; | |
| 211 | |
| 212 var blacklistText = node.querySelector('.blacklist-text'); | |
| 213 blacklistText.textContent = extension.blacklistText; | |
| 214 | |
| 215 var description = document.createElement('span'); | |
| 216 description.textContent = extension.description; | |
| 217 node.querySelector('.extension-description').appendChild(description); | |
| 218 | |
| 219 // The 'Show Browser Action' button. | |
| 220 if (extension.enable_show_button) { | |
| 221 var showButton = node.querySelector('.show-button'); | |
| 222 showButton.addEventListener('click', function(e) { | |
| 223 chrome.send('extensionSettingsShowButton', [extension.id]); | |
| 224 }); | |
| 225 showButton.hidden = false; | |
| 226 } | |
| 227 | |
| 228 // The 'allow in incognito' checkbox. | |
| 229 node.querySelector('.incognito-control').hidden = | |
| 230 !this.data_.incognitoAvailable; | |
| 231 var incognito = node.querySelector('.incognito-control input'); | |
| 232 incognito.disabled = !extension.incognitoCanBeEnabled; | |
| 233 incognito.checked = extension.enabledIncognito; | |
| 234 if (!incognito.disabled) { | |
| 235 incognito.addEventListener('change', function(e) { | |
| 236 var checked = e.target.checked; | |
| 237 butterBarVisibility[extension.id] = checked; | |
| 238 butterBar.hidden = !checked || extension.is_hosted_app; | |
| 239 chrome.send('extensionSettingsEnableIncognito', | |
| 240 [extension.id, String(checked)]); | |
| 241 }); | |
| 242 } | |
| 243 var butterBar = node.querySelector('.butter-bar'); | |
| 244 butterBar.hidden = !butterBarVisibility[extension.id]; | |
| 245 | |
| 246 // The 'collect errors' checkbox. This should only be visible if the | |
| 247 // error console is enabled - we can detect this by the existence of the | |
| 248 // |errorCollectionEnabled| property. | |
| 249 if (extension.wantsErrorCollection) { | |
| 250 node.querySelector('.error-collection-control').hidden = false; | |
| 251 var errorCollection = | |
| 252 node.querySelector('.error-collection-control input'); | |
| 253 errorCollection.checked = extension.errorCollectionEnabled; | |
| 254 errorCollection.addEventListener('change', function(e) { | |
| 255 chrome.send('extensionSettingsEnableErrorCollection', | |
| 256 [extension.id, String(e.target.checked)]); | |
| 257 }); | |
| 258 } | |
| 259 | |
| 260 // The 'allow on all urls' checkbox. This should only be visible if | |
| 261 // active script restrictions are enabled. If they are not enabled, no | |
| 262 // extensions should want all urls. | |
| 263 if (extension.wantsAllUrls) { | |
| 264 var allUrls = node.querySelector('.all-urls-control'); | |
| 265 allUrls.addEventListener('click', function(e) { | |
| 266 chrome.send('extensionSettingsAllowOnAllUrls', | |
| 267 [extension.id, String(e.target.checked)]); | |
| 268 }); | |
| 269 allUrls.querySelector('input').checked = extension.allowAllUrls; | |
| 270 allUrls.hidden = false; | |
| 271 } | |
| 272 | |
| 273 // The 'allow file:// access' checkbox. | |
| 274 if (extension.wantsFileAccess) { | |
| 275 var fileAccess = node.querySelector('.file-access-control'); | |
| 276 fileAccess.addEventListener('click', function(e) { | |
| 277 chrome.send('extensionSettingsAllowFileAccess', | |
| 278 [extension.id, String(e.target.checked)]); | |
| 279 }); | |
| 280 fileAccess.querySelector('input').checked = extension.allowFileAccess; | |
| 281 fileAccess.hidden = false; | |
| 282 } | |
| 283 | |
| 284 // The 'Options' button or link, depending on its behaviour. | |
| 285 if (extension.enabled && extension.optionsUrl) { | |
| 286 var options, optionsClickListener; | |
| 287 if (extension.optionsOpenInTab) { | |
| 288 options = node.querySelector('.options-link'); | |
| 289 // Set an href to get the correct mouse-over appearance (link, | |
| 290 // footer) - but the actual link opening is done through chrome.send | |
| 291 // with a preventDefault(). | |
| 292 options.setAttribute('href', extension.optionsPageHref); | |
| 293 optionsClickListener = function() { | |
| 294 chrome.send('extensionSettingsOptions', [extension.id]); | |
| 295 }; | |
| 296 } else { | |
| 297 options = node.querySelector('.options-button'); | |
| 298 optionsClickListener = function() { | |
| 299 this.showEmbeddedExtensionOptions_(extension.id, false); | |
| 300 }.bind(this); | |
| 301 } | |
| 302 options.addEventListener('click', function(e) { | |
| 303 optionsClickListener(); | |
| 304 e.preventDefault(); | |
| 305 }); | |
| 306 options.hidden = false; | |
| 307 } | |
| 308 | |
| 309 // The 'Permissions' link. | |
| 310 var permissions = node.querySelector('.permissions-link'); | |
| 311 permissions.addEventListener('click', function(e) { | |
| 312 chrome.send('extensionSettingsPermissions', [extension.id]); | |
| 313 e.preventDefault(); | |
| 314 }); | |
| 315 | |
| 316 // The 'View in Web Store/View Web Site' link. | |
| 317 if (extension.homepageUrl && !extension.enableExtensionInfoDialog) { | |
| 318 var siteLink = node.querySelector('.site-link'); | |
| 319 siteLink.href = extension.homepageUrl; | |
| 320 siteLink.textContent = loadTimeData.getString( | |
| 321 extension.homepageProvided ? 'extensionSettingsVisitWebsite' : | |
| 322 'extensionSettingsVisitWebStore'); | |
| 323 siteLink.hidden = false; | |
| 324 } | |
| 325 | |
| 326 if (extension.allow_reload) { | |
| 327 // The 'Reload' link. | |
| 328 var reload = node.querySelector('.reload-link'); | |
| 329 reload.addEventListener('click', function(e) { | |
| 330 chrome.send('extensionSettingsReload', [extension.id]); | |
| 331 extensionReloadedTimestamp[extension.id] = Date.now(); | |
| 332 }); | |
| 333 reload.hidden = false; | |
| 334 | |
| 335 if (extension.is_platform_app) { | |
| 336 // The 'Launch' link. | |
| 337 var launch = node.querySelector('.launch-link'); | |
| 338 launch.addEventListener('click', function(e) { | |
| 339 chrome.send('extensionSettingsLaunch', [extension.id]); | |
| 340 }); | |
| 341 launch.hidden = false; | |
| 342 } | |
| 343 } | |
| 344 | |
| 345 if (extension.terminated) { | |
| 346 var terminatedReload = node.querySelector('.terminated-reload-link'); | |
| 347 terminatedReload.hidden = false; | |
| 348 terminatedReload.onclick = function() { | |
| 349 chrome.send('extensionSettingsReload', [extension.id]); | |
| 350 }; | |
| 351 } else if (extension.corruptInstall && extension.isFromStore) { | |
| 352 var repair = node.querySelector('.corrupted-repair-button'); | |
| 353 repair.hidden = false; | |
| 354 repair.onclick = function() { | |
| 355 chrome.send('extensionSettingsRepair', [extension.id]); | |
| 356 }; | |
| 357 } else { | |
| 358 // The 'Enabled' checkbox. | |
| 359 var enable = node.querySelector('.enable-checkbox'); | |
| 360 enable.hidden = false; | |
| 361 var enableCheckboxDisabled = extension.managedInstall || | |
| 362 extension.suspiciousInstall || | |
| 363 extension.corruptInstall || | |
| 364 extension.updateRequiredByPolicy || | |
| 365 extension.dependentExtensions.length > 0; | |
| 366 enable.querySelector('input').disabled = enableCheckboxDisabled; | |
| 367 | |
| 368 if (extension.managedInstall) { | |
| 369 var indicator = new cr.ui.ControlledIndicator(); | |
| 370 indicator.classList.add('controlled-extension-indicator'); | |
| 371 indicator.setAttribute('controlled-by', 'policy'); | |
| 372 indicator.setAttribute('textpolicy', extension.policyText || ''); | |
| 373 node.querySelector('.enable-controls').appendChild(indicator); | |
| 374 } | |
| 375 | |
| 376 if (!enableCheckboxDisabled) { | |
| 377 enable.addEventListener('click', function(e) { | |
| 378 // When e.target is the label instead of the checkbox, it doesn't | |
| 379 // have the checked property and the state of the checkbox is | |
| 380 // left unchanged. | |
| 381 var checked = e.target.checked; | |
| 382 if (checked == undefined) | |
| 383 checked = !e.currentTarget.querySelector('input').checked; | |
| 384 chrome.send('extensionSettingsEnable', | |
| 385 [extension.id, checked ? 'true' : 'false']); | |
| 386 | |
| 387 // This may seem counter-intuitive (to not set/clear the checkmark) | |
| 388 // but this page will be updated asynchronously if the extension | |
| 389 // becomes enabled/disabled. It also might not become enabled or | |
| 390 // disabled, because the user might e.g. get prompted when enabling | |
| 391 // and choose not to. | |
| 392 e.preventDefault(); | |
| 393 }); | |
| 394 } | |
| 395 | |
| 396 enable.querySelector('input').checked = extension.enabled; | |
| 397 } | |
| 398 | |
| 399 // 'Remove' button. | |
| 400 var trashTemplate = $('template-collection').querySelector('.trash'); | |
| 401 var trash = trashTemplate.cloneNode(true); | |
| 402 trash.title = loadTimeData.getString('extensionUninstall'); | |
| 403 trash.addEventListener('click', function(e) { | |
| 404 butterBarVisibility[extension.id] = false; | |
| 405 chrome.send('extensionSettingsUninstall', [extension.id]); | |
| 406 }); | |
| 407 node.querySelector('.enable-controls').appendChild(trash); | |
| 408 | |
| 409 // Developer mode //////////////////////////////////////////////////////// | |
| 410 | |
| 411 // First we have the id. | |
| 412 var idLabel = node.querySelector('.extension-id'); | |
| 413 idLabel.textContent = ' ' + extension.id; | |
| 414 | |
| 415 // Then the path, if provided by unpacked extension. | |
| 416 if (extension.isUnpacked) { | |
| 417 var loadPath = node.querySelector('.load-path'); | |
| 418 loadPath.hidden = false; | |
| 419 var pathLink = loadPath.querySelector('a:nth-of-type(1)'); | |
| 420 pathLink.textContent = ' ' + extension.prettifiedPath; | |
| 421 pathLink.addEventListener('click', function(e) { | |
| 422 chrome.send('extensionSettingsShowPath', [String(extension.id)]); | |
| 423 e.preventDefault(); | |
| 424 }); | |
| 425 } | |
| 426 | |
| 427 // Then the 'managed, cannot uninstall/disable' message. | |
| 428 if (extension.managedInstall || extension.recommendedInstall) { | |
| 429 node.querySelector('.managed-message').hidden = false; | |
| 430 } else { | |
| 431 if (extension.suspiciousInstall) { | |
| 432 // Then the 'This isn't from the webstore, looks suspicious' message. | |
| 433 node.querySelector('.suspicious-install-message').hidden = false; | |
| 434 } | |
| 435 if (extension.corruptInstall) { | |
| 436 // Then the 'This is a corrupt extension' message. | |
| 437 node.querySelector('.corrupt-install-message').hidden = false; | |
| 438 } | |
| 439 } | |
| 440 | |
| 441 // Then the 'An update required by enterprise policy' message. Note that | |
| 442 // a force-installed extension might be disabled due to being outdated | |
| 443 // as well. | |
| 444 if (extension.updateRequiredByPolicy) { | |
| 445 node.querySelector('.update-required-message').hidden = false; | |
| 446 // We would like to hide managed installed message since this | |
| 447 // extension is disabled. | |
| 448 node.querySelector('.managed-message').hidden = true; | |
| 449 } | |
| 450 | |
| 451 if (extension.dependentExtensions.length > 0) { | |
| 452 node.classList.add('developer-extras'); | |
| 453 var dependentMessage = | |
| 454 node.querySelector('.dependent-extensions-message'); | |
| 455 dependentMessage.hidden = false; | |
| 456 var dependentList = dependentMessage.querySelector('ul'); | |
| 457 var dependentTemplate = $('template-collection').querySelector( | |
| 458 '.dependent-list-item'); | |
| 459 extension.dependentExtensions.forEach(function(elem) { | |
| 460 var depNode = dependentTemplate.cloneNode(true); | |
| 461 depNode.querySelector('.dep-extension-title').textContent = elem.name; | |
| 462 depNode.querySelector('.dep-extension-id').textContent = elem.id; | |
| 463 dependentList.appendChild(depNode); | |
| 464 }); | |
| 465 } | |
| 466 | |
| 467 // Then active views. | |
| 468 if (extension.views.length > 0) { | |
| 469 var activeViews = node.querySelector('.active-views'); | |
| 470 activeViews.hidden = false; | |
| 471 var link = activeViews.querySelector('a'); | |
| 472 | |
| 473 extension.views.forEach(function(view, i) { | |
| 474 var displayName = view.generatedBackgroundPage ? | |
| 475 loadTimeData.getString('backgroundPage') : view.path; | |
| 476 var label = displayName + | |
| 477 (view.incognito ? | |
| 478 ' ' + loadTimeData.getString('viewIncognito') : '') + | |
| 479 (view.renderProcessId == -1 ? | |
| 480 ' ' + loadTimeData.getString('viewInactive') : ''); | |
| 481 link.textContent = label; | |
| 482 link.addEventListener('click', function(e) { | |
| 483 // TODO(estade): remove conversion to string? | |
| 484 chrome.send('extensionSettingsInspect', [ | |
| 485 String(extension.id), | |
| 486 String(view.renderProcessId), | |
| 487 String(view.renderViewId), | |
| 488 view.incognito | |
| 489 ]); | |
| 490 }); | |
| 491 | |
| 492 if (i < extension.views.length - 1) { | |
| 493 link = link.cloneNode(true); | |
| 494 activeViews.appendChild(link); | |
| 495 } | |
| 496 }); | |
| 497 } | |
| 498 | |
| 499 // The extension warnings (describing runtime issues). | |
| 500 if (extension.warnings) { | |
| 501 var panel = node.querySelector('.extension-warnings'); | |
| 502 panel.hidden = false; | |
| 503 var list = panel.querySelector('ul'); | |
| 504 extension.warnings.forEach(function(warning) { | |
| 505 list.appendChild(document.createElement('li')).innerText = warning; | |
| 506 }); | |
| 507 } | |
| 508 | |
| 509 // If the ErrorConsole is enabled, we should have manifest and/or runtime | |
| 510 // errors. Otherwise, we may have install warnings. We should not have | |
| 511 // both ErrorConsole errors and install warnings. | |
| 512 if (extension.manifestErrors) { | |
| 513 var panel = node.querySelector('.manifest-errors'); | |
| 514 panel.hidden = false; | |
| 515 panel.appendChild(new extensions.ExtensionErrorList( | |
| 516 extension.manifestErrors)); | |
| 517 } | |
| 518 if (extension.runtimeErrors) { | |
| 519 var panel = node.querySelector('.runtime-errors'); | |
| 520 panel.hidden = false; | |
| 521 panel.appendChild(new extensions.ExtensionErrorList( | |
| 522 extension.runtimeErrors)); | |
| 523 } | |
| 524 if (extension.installWarnings) { | |
| 525 var panel = node.querySelector('.install-warnings'); | |
| 526 panel.hidden = false; | |
| 527 var list = panel.querySelector('ul'); | |
| 528 extension.installWarnings.forEach(function(warning) { | |
| 529 var li = document.createElement('li'); | |
| 530 li.innerText = warning.message; | |
| 531 list.appendChild(li); | |
| 532 }); | |
| 533 } | |
| 534 | |
| 535 this.appendChild(node); | |
| 536 if (location.hash.substr(1) == extension.id) { | |
| 537 // Scroll beneath the fixed header so that the extension is not | |
| 538 // obscured. | |
| 539 var topScroll = node.offsetTop - $('page-header').offsetHeight; | |
| 540 var pad = parseInt(window.getComputedStyle(node, null).marginTop, 10); | |
| 541 if (!isNaN(pad)) | |
| 542 topScroll -= pad / 2; | |
| 543 setScrollTopForDocument(document, topScroll); | |
| 544 } | |
| 545 }, | 184 }, |
| 546 | 185 |
| 547 /** | 186 /** |
| 187 * Updates an element's textContent. | |
| 188 * @param {Element} node Ancestor of the element specified by |query|. | |
| 189 * @param {string} query A query to select an element in |node|. | |
| 190 * @param {string} textContent | |
| 191 * @private | |
| 192 */ | |
| 193 setTextContent_: function(node, query, textContent) { | |
| 194 node.querySelector(query).textContent = textContent; | |
| 195 }, | |
| 196 | |
| 197 /** | |
| 198 * Updates an element's visibility and calls |callback| if it is visible. | |
| 199 * @param {Element} node Ancestor of the element specified by |query|. | |
| 200 * @param {string} query A query to select an element in |node|. | |
| 201 * @param {boolean} visible Whether the element should be visible or not. | |
| 202 * @param {function({Element} item)} callback Callback if the element | |
| 203 * is visible. | |
|
not at google - send to devlin
2015/02/10 22:14:37
Mention that the Element it's called with is the i
hcarmona
2015/02/11 02:22:07
Done.
| |
| 204 * @private | |
| 205 */ | |
| 206 updateElement_: function(node, query, visible, callback) { | |
|
not at google - send to devlin
2015/02/10 22:14:37
A more descriptive name would be updateVisibility
hcarmona
2015/02/11 02:22:07
Done.
| |
| 207 var item = node.querySelector(query); | |
|
not at google - send to devlin
2015/02/10 22:14:37
Can you assert that the element existed?
hcarmona
2015/02/11 02:22:07
Done.
| |
| 208 item.hidden = !visible; | |
| 209 if (visible && callback) | |
| 210 callback(item); | |
| 211 }, | |
| 212 | |
| 213 /** | |
| 214 * Updates an element to show a list of errors. | |
| 215 * @param {Element} panel An element to hold the errors. | |
| 216 * @param {?Array<RuntimeError>} errors The errors to be displayed. | |
| 217 * @private | |
| 218 */ | |
| 219 updateErrors_: function(panel, errors) { | |
| 220 // TODO(hcarmona): Look into updating the ExtensionErrorList rather than | |
| 221 // rebuilding it every time. | |
| 222 panel.hidden = !errors; | |
| 223 panel.textContent = ''; | |
| 224 if (errors) | |
| 225 panel.appendChild(new extensions.ExtensionErrorList(errors)); | |
| 226 }, | |
| 227 | |
| 228 /** | |
| 548 * Opens the extension options overlay for the extension with the given id. | 229 * Opens the extension options overlay for the extension with the given id. |
| 549 * @param {string} extensionId The id of extension whose options page should | 230 * @param {string} extensionId The id of extension whose options page should |
| 550 * be displayed. | 231 * be displayed. |
| 551 * @param {boolean} scroll Whether the page should scroll to the extension | 232 * @param {boolean} scroll Whether the page should scroll to the extension |
| 552 * @private | 233 * @private |
| 553 */ | 234 */ |
| 554 showEmbeddedExtensionOptions_: function(extensionId, scroll) { | 235 showEmbeddedExtensionOptions_: function(extensionId, scroll) { |
| 555 if (this.optionsShown_) | 236 if (this.optionsShown_) |
| 556 return; | 237 return; |
| 557 | 238 |
| (...skipping 21 matching lines...) Expand all Loading... | |
| 579 $('overlay').addEventListener('cancelOverlay', function() { | 260 $('overlay').addEventListener('cancelOverlay', function() { |
| 580 this.optionsShown_ = false; | 261 this.optionsShown_ = false; |
| 581 }.bind(this)); | 262 }.bind(this)); |
| 582 }, | 263 }, |
| 583 }; | 264 }; |
| 584 | 265 |
| 585 return { | 266 return { |
| 586 ExtensionsList: ExtensionsList | 267 ExtensionsList: ExtensionsList |
| 587 }; | 268 }; |
| 588 }); | 269 }); |
| OLD | NEW |