| 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('options', function() { | 7 cr.define('options', function() { |
| 8 'use strict'; | 8 'use strict'; |
| 9 | 9 |
| 10 /** | 10 /** |
| (...skipping 15 matching lines...) Expand all Loading... |
| 26 * @type {Object.<string, string>} A map from extension id to last reloaded | 26 * @type {Object.<string, string>} A map from extension id to last reloaded |
| 27 * timestamp. The timestamp is recorded when the user click the 'Reload' | 27 * timestamp. The timestamp is recorded when the user click the 'Reload' |
| 28 * link. It is used to refresh the icon of an unpacked extension. | 28 * link. It is used to refresh the icon of an unpacked extension. |
| 29 * This persists between calls to decorate. | 29 * This persists between calls to decorate. |
| 30 */ | 30 */ |
| 31 var extensionReloadedTimestamp = {}; | 31 var extensionReloadedTimestamp = {}; |
| 32 | 32 |
| 33 ExtensionsList.prototype = { | 33 ExtensionsList.prototype = { |
| 34 __proto__: HTMLDivElement.prototype, | 34 __proto__: HTMLDivElement.prototype, |
| 35 | 35 |
| 36 /** |
| 37 * Indicates whether an embedded options page that was navigated to through |
| 38 * the '?options=' URL query has been shown to the user. This is necessary |
| 39 * to prevent showExtensionNodes_ from opening the options more than once. |
| 40 * @type {boolean} |
| 41 * @private |
| 42 */ |
| 43 optionsShown_: false, |
| 44 |
| 36 /** @override */ | 45 /** @override */ |
| 37 decorate: function() { | 46 decorate: function() { |
| 38 this.textContent = ''; | 47 this.textContent = ''; |
| 39 | 48 |
| 40 this.showExtensionNodes_(); | 49 this.showExtensionNodes_(); |
| 41 }, | 50 }, |
| 42 | 51 |
| 43 getIdQueryParam_: function() { | 52 getIdQueryParam_: function() { |
| 44 return parseQueryParams(document.location)['id']; | 53 return parseQueryParams(document.location)['id']; |
| 45 }, | 54 }, |
| 46 | 55 |
| 56 getOptionsQueryParam_: function() { |
| 57 return parseQueryParams(document.location)['options']; |
| 58 }, |
| 59 |
| 47 /** | 60 /** |
| 48 * Creates all extension items from scratch. | 61 * Creates all extension items from scratch. |
| 49 * @private | 62 * @private |
| 50 */ | 63 */ |
| 51 showExtensionNodes_: function() { | 64 showExtensionNodes_: function() { |
| 52 // Iterate over the extension data and add each item to the list. | 65 // Iterate over the extension data and add each item to the list. |
| 53 this.data_.extensions.forEach(this.createNode_, this); | 66 this.data_.extensions.forEach(this.createNode_, this); |
| 54 | 67 |
| 55 var idToHighlight = this.getIdQueryParam_(); | 68 var idToHighlight = this.getIdQueryParam_(); |
| 56 if (idToHighlight && $(idToHighlight)) { | 69 if (idToHighlight && $(idToHighlight)) |
| 57 // Scroll offset should be calculated slightly higher than the actual | 70 this.scrollToNode_(idToHighlight); |
| 58 // offset of the element being scrolled to, so that it ends up not all | 71 |
| 59 // the way at the top. That way it is clear that there are more elements | 72 var idToOpenOptions = this.getOptionsQueryParam_(); |
| 60 // above the element being scrolled to. | 73 if (idToOpenOptions && $(idToOpenOptions)) |
| 61 var scrollFudge = 1.2; | 74 this.showEmbeddedExtensionOptions_(idToOpenOptions, true); |
| 62 var scrollTop = $(idToHighlight).offsetTop - scrollFudge * | |
| 63 $(idToHighlight).clientHeight; | |
| 64 setScrollTopForDocument(document, scrollTop); | |
| 65 } | |
| 66 | 75 |
| 67 if (this.data_.extensions.length == 0) | 76 if (this.data_.extensions.length == 0) |
| 68 this.classList.add('empty-extension-list'); | 77 this.classList.add('empty-extension-list'); |
| 69 else | 78 else |
| 70 this.classList.remove('empty-extension-list'); | 79 this.classList.remove('empty-extension-list'); |
| 71 }, | 80 }, |
| 72 | 81 |
| 73 /** | 82 /** |
| 83 * Scrolls the page down to the extension node with the given id. |
| 84 * @param {string} extensionId The id of the extension to scroll to. |
| 85 * @private |
| 86 */ |
| 87 scrollToNode_: function(extensionId) { |
| 88 // Scroll offset should be calculated slightly higher than the actual |
| 89 // offset of the element being scrolled to, so that it ends up not all |
| 90 // the way at the top. That way it is clear that there are more elements |
| 91 // above the element being scrolled to. |
| 92 var scrollFudge = 1.2; |
| 93 var scrollTop = $(extensionId).offsetTop - scrollFudge * |
| 94 $(extensionId).clientHeight; |
| 95 setScrollTopForDocument(document, scrollTop); |
| 96 }, |
| 97 |
| 98 /** |
| 74 * Synthesizes and initializes an HTML element for the extension metadata | 99 * Synthesizes and initializes an HTML element for the extension metadata |
| 75 * given in |extension|. | 100 * given in |extension|. |
| 76 * @param {Object} extension A dictionary of extension metadata. | 101 * @param {Object} extension A dictionary of extension metadata. |
| 77 * @private | 102 * @private |
| 78 */ | 103 */ |
| 79 createNode_: function(extension) { | 104 createNode_: function(extension) { |
| 80 var template = $('template-collection').querySelector( | 105 var template = $('template-collection').querySelector( |
| 81 '.extension-list-item-wrapper'); | 106 '.extension-list-item-wrapper'); |
| 82 var node = template.cloneNode(true); | 107 var node = template.cloneNode(true); |
| 83 node.id = extension.id; | 108 node.id = extension.id; |
| (...skipping 103 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 187 }); | 212 }); |
| 188 fileAccess.querySelector('input').checked = extension.allowFileAccess; | 213 fileAccess.querySelector('input').checked = extension.allowFileAccess; |
| 189 fileAccess.hidden = false; | 214 fileAccess.hidden = false; |
| 190 } | 215 } |
| 191 | 216 |
| 192 // The 'Options' link. | 217 // The 'Options' link. |
| 193 if (extension.enabled && extension.optionsUrl) { | 218 if (extension.enabled && extension.optionsUrl) { |
| 194 var options = node.querySelector('.options-link'); | 219 var options = node.querySelector('.options-link'); |
| 195 options.addEventListener('click', function(e) { | 220 options.addEventListener('click', function(e) { |
| 196 if (this.data_.enableEmbeddedExtensionOptions) { | 221 if (this.data_.enableEmbeddedExtensionOptions) { |
| 197 extensions.ExtensionOptionsOverlay.getInstance(). | 222 this.showEmbeddedExtensionOptions_(extension.id, false); |
| 198 setExtensionAndShowOverlay(extension.id, | |
| 199 extension.name, | |
| 200 extension.icon); | |
| 201 } else { | 223 } else { |
| 202 chrome.send('extensionSettingsOptions', [extension.id]); | 224 chrome.send('extensionSettingsOptions', [extension.id]); |
| 203 } | 225 } |
| 204 e.preventDefault(); | 226 e.preventDefault(); |
| 205 }.bind(this)); | 227 }.bind(this)); |
| 206 options.hidden = false; | 228 options.hidden = false; |
| 207 } | 229 } |
| 208 | 230 |
| 209 // The 'Permissions' link. | 231 // The 'Permissions' link. |
| 210 var permissions = node.querySelector('.permissions-link'); | 232 var permissions = node.querySelector('.permissions-link'); |
| (...skipping 199 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 410 if (location.hash.substr(1) == extension.id) { | 432 if (location.hash.substr(1) == extension.id) { |
| 411 // Scroll beneath the fixed header so that the extension is not | 433 // Scroll beneath the fixed header so that the extension is not |
| 412 // obscured. | 434 // obscured. |
| 413 var topScroll = node.offsetTop - $('page-header').offsetHeight; | 435 var topScroll = node.offsetTop - $('page-header').offsetHeight; |
| 414 var pad = parseInt(getComputedStyle(node, null).marginTop, 10); | 436 var pad = parseInt(getComputedStyle(node, null).marginTop, 10); |
| 415 if (!isNaN(pad)) | 437 if (!isNaN(pad)) |
| 416 topScroll -= pad / 2; | 438 topScroll -= pad / 2; |
| 417 setScrollTopForDocument(document, topScroll); | 439 setScrollTopForDocument(document, topScroll); |
| 418 } | 440 } |
| 419 }, | 441 }, |
| 442 |
| 443 /** |
| 444 * Opens the extension options overlay for the extension with the given id. |
| 445 * @param {string} extensionId The id of extension whose options page should |
| 446 * be displayed. |
| 447 * @param {boolean} scroll Whether the page should scroll to the extension |
| 448 * @private |
| 449 */ |
| 450 showEmbeddedExtensionOptions_: function(extensionId, scroll) { |
| 451 if (this.optionsShown_) |
| 452 return; |
| 453 |
| 454 // Get the extension from the given id. |
| 455 var extension = this.data_.extensions.filter(function(extension) { |
| 456 return extension.id == extensionId; |
| 457 })[0]; |
| 458 |
| 459 if (!extension) |
| 460 return; |
| 461 |
| 462 if (scroll) |
| 463 this.scrollToNode_(extensionId); |
| 464 // Add the options query string. Corner case: the 'options' query string |
| 465 // will clobber the 'id' query string if the options link is clicked when |
| 466 // 'id' is in the URL, or if both query strings are in the URL. |
| 467 uber.replaceState({}, '?options=' + extensionId); |
| 468 |
| 469 extensions.ExtensionOptionsOverlay.getInstance(). |
| 470 setExtensionAndShowOverlay(extensionId, |
| 471 extension.name, |
| 472 extension.icon); |
| 473 |
| 474 this.optionsShown_ = true; |
| 475 $('overlay').addEventListener('cancelOverlay', function() { |
| 476 this.optionsShown_ = false; |
| 477 }.bind(this)); |
| 478 }, |
| 420 }; | 479 }; |
| 421 | 480 |
| 422 return { | 481 return { |
| 423 ExtensionsList: ExtensionsList | 482 ExtensionsList: ExtensionsList |
| 424 }; | 483 }; |
| 425 }); | 484 }); |
| OLD | NEW |