summaryrefslogtreecommitdiffstats
path: root/chrome
diff options
context:
space:
mode:
authorfinnur@chromium.org <finnur@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2011-09-02 18:12:34 +0000
committerfinnur@chromium.org <finnur@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2011-09-02 18:12:34 +0000
commitf94d3119c96ed2ef9a48475f3963a2d75441a991 (patch)
tree18d24d3dc91725553996af50d4f91e49112a17e1 /chrome
parentf671d792836ac7781f19d3bf605db25472a7e4a4 (diff)
downloadchromium_src-f94d3119c96ed2ef9a48475f3963a2d75441a991.zip
chromium_src-f94d3119c96ed2ef9a48475f3963a2d75441a991.tar.gz
chromium_src-f94d3119c96ed2ef9a48475f3963a2d75441a991.tar.bz2
Convert chrome://extensions to a settings page within the options pages.
BUG=87378 TEST=The new settings page (chrome://settings/extensionSettings) should work the same as the old one (chrome://extensions). Review URL: http://codereview.chromium.org/7794023 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@99402 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'chrome')
-rw-r--r--chrome/app/generated_resources.grd19
-rw-r--r--chrome/browser/resources/options/extension_list.js684
-rw-r--r--chrome/browser/resources/options/extension_settings.css261
-rw-r--r--chrome/browser/resources/options/extension_settings.html40
-rw-r--r--chrome/browser/resources/options/extension_settings.js179
-rw-r--r--chrome/browser/resources/options/options.html4
-rw-r--r--chrome/browser/resources/options/options.js6
-rw-r--r--chrome/browser/resources/options/options_bundle.js3
-rw-r--r--chrome/browser/resources/options/pack_extension_overlay.css18
-rw-r--r--chrome/browser/resources/options/pack_extension_overlay.html28
-rw-r--r--chrome/browser/resources/options/pack_extension_overlay.js90
-rw-r--r--chrome/browser/resources/options/zippy.pngbin189 -> 279 bytes
-rw-r--r--chrome/browser/ui/webui/options/extension_settings_handler.cc600
-rw-r--r--chrome/browser/ui/webui/options/extension_settings_handler.h103
-rw-r--r--chrome/browser/ui/webui/options/options_ui.cc4
-rw-r--r--chrome/browser/ui/webui/options/options_ui_uitest.cc13
-rw-r--r--chrome/browser/ui/webui/options/pack_extension_handler.cc99
-rw-r--r--chrome/browser/ui/webui/options/pack_extension_handler.h49
-rw-r--r--chrome/chrome_browser.gypi4
19 files changed, 1782 insertions, 422 deletions
diff --git a/chrome/app/generated_resources.grd b/chrome/app/generated_resources.grd
index 999f766..cc64bd4 100644
--- a/chrome/app/generated_resources.grd
+++ b/chrome/app/generated_resources.grd
@@ -4007,12 +4007,21 @@ are declared in build/common.gypi.
<message name="IDS_EXTENSIONS_ENABLE" desc="The link for enabling extensions.">
Enable
</message>
+ <message name="IDS_EXTENSIONS_ENABLED" desc="The label for have been enabled extensions.">
+ Enabled
+ </message>
+ <message name="IDS_EXTENSIONS_REMOVE" desc="The label for uninstalling an extension.">
+ Remove
+ </message>
<message name="IDS_EXTENSIONS_ENABLE_INCOGNITO" desc="The checkbox for enabling extensions in incognito.">
Allow in incognito
</message>
<message name="IDS_EXTENSIONS_ALLOW_FILE_ACCESS" desc="The checkbox for allowing an extension access to run scripts on file URLs.">
Allow access to file URLs
</message>
+ <message name="IDS_EXTENSIONS_VISIT_WEBSITE" desc="The link for visiting the extension's gallery page.">
+ Visit website
+ </message>
<message name="IDS_EXTENSIONS_INCOGNITO_WARNING" desc="Warns the user that Chrome cannot prevent extensions from recording history in incognito mode. Displayed in extensions management UI after an extension is selected to be run in incognito mode.">
<ph name="BEGIN_BOLD">&lt;b&gt;</ph>Warning:<ph name="END_BOLD">&lt;/b&gt;</ph> <ph name="PRODUCT_NAME">$1<ex>Google Chrome</ex></ph> cannot prevent extensions from recording your browsing history. To disable this extension in incognito mode, unselect this option.
</message>
@@ -4038,7 +4047,7 @@ are declared in build/common.gypi.
(this extension is managed and can not be uninstalled or disabled)
</message>
<message name="IDS_GET_MORE_EXTENSIONS" desc="The link for getting more extensions. Displayed at bottom of extension management page when there is at least one extension installed.">
- Get more extensions >>
+ Get more extensions
</message>
<message name="IDS_EXTENSION_LOAD_FROM_DIRECTORY" desc="Title of directory browse dialog when user wants to load an extension from a directory.">
Select the extension directory.
@@ -4046,6 +4055,9 @@ are declared in build/common.gypi.
<message name="IDS_EXTENSION_PACK_DIALOG_TITLE" desc="Title of pack extension dialog">
Pack Extension
</message>
+ <message name="IDS_EXTENSION_PACK_BUTTON" desc="Text of the pack extension button">
+ Pack Extension
+ </message>
<message name="IDS_EXTENSION_PACK_DIALOG_HEADING" desc="The heading of the pack extension dialog.">
Select the root directory of the extension to pack. To update an extension, also select the private key file to reuse.
</message>
@@ -7183,6 +7195,11 @@ Keep your key file in a safe place. You will need it to create new versions of y
Unlock
</message>
+ <!-- Extension settings -->
+ <message name="IDS_MANAGE_EXTENSIONS_SETTING_WINDOWS_TITLE" desc="Title that appears in the dialogue title bar for manage extensions settings">
+ Extensions
+ </message>
+
<!-- Font settings -->
<message name="IDS_FONT_LANGUAGE_SETTING_FONT_TAB_TITLE" desc="Title that appears in the Fonts and Encoding subpage">
Fonts and Encoding
diff --git a/chrome/browser/resources/options/extension_list.js b/chrome/browser/resources/options/extension_list.js
new file mode 100644
index 0000000..3314a32
--- /dev/null
+++ b/chrome/browser/resources/options/extension_list.js
@@ -0,0 +1,684 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+cr.define('options', function() {
+ /**
+ * Creates a new list of extensions.
+ * @param {Object=} opt_propertyBag Optional properties.
+ * @constructor
+ * @extends {cr.ui.div}
+ */
+ var ExtensionsList = cr.ui.define('div');
+
+ var handleInstalled = false;
+
+ ExtensionsList.prototype = {
+ __proto__: HTMLDivElement.prototype,
+
+ /** @inheritDoc */
+ decorate: function() {
+ this.initControlsAndHandlers_();
+
+ var showingDetails = [];
+ var showingWarning = [];
+ this.deleteExistingExtensionNodes_(showingDetails, showingWarning);
+
+ this.showExtensionNodes_(showingDetails, showingWarning);
+ },
+
+ /**
+ * Initializes the controls (toggle section and button) and installs
+ * handlers.
+ * @private
+ */
+ initControlsAndHandlers_: function() {
+ // Make sure developer mode section is set correctly as per saved setting.
+ var toggleButton = $('toggle-dev-on');
+ var toggleSection = $('dev');
+ if (this.data_.developerMode) {
+ toggleSection.classList.add('dev-open');
+ toggleSection.classList.remove('dev-closed');
+ toggleButton.checked = true;
+ } else {
+ toggleSection.classList.remove('dev-open');
+ toggleSection.classList.add('dev-closed');
+ }
+
+ // Install handler for key presses.
+ if (!handleInstalled) {
+ document.addEventListener('keyup', this.upEventHandler_.bind(this));
+ document.addEventListener('mouseup', this.upEventHandler_.bind(this));
+ handleInstalled = true;
+ }
+ },
+
+ /**
+ * Deletes the existing Extension nodes from the page to make room for new
+ * ones. It also keeps track of who was showing details so when the
+ * extension list gets recreated we can recreate that state.
+ * @param {Array} showingDetails An array that will contain the list of id's
+ * of extension that had the details section expanded.
+ * @param {Array} showingWarning An array that will contain the list of id's
+ * of extension that were showing a warning.
+ * @private
+ */
+ deleteExistingExtensionNodes_: function(showingDetails, showingWarning) {
+ // Delete all child nodes before adding them back and while we are at it
+ // make a note of which ones were in expanded state (and which showing
+ // the warning) so we can restore those to the same state afterwards.
+ while (this.hasChildNodes()){
+ var child = this.firstChild;
+
+ // See if the item is expanded.
+ if (child.classList.contains('extension-list-item-expanded'))
+ showingDetails.push(child.id);
+
+ // See if the butterbar is showing.
+ var butterBar = document.getElementById(child.id + '_incognitoWarning');
+ if (!(butterBar === null) && !butterBar.hidden)
+ showingWarning.push(child.id);
+
+ // Now we can delete it.
+ this.removeChild(child);
+ }
+ },
+
+ /**
+ * Handles decorating the details section.
+ * @param {Element} details The div that the details should be attached to.
+ * @param {Object} extension The extension we are shoting the details for.
+ * @param {boolean} expanded Whether to show the details expanded or not.
+ * @param {boolean} showButterbar Whether to show the incognito warning or
+ * not.
+ * @private
+ */
+ showExtensionNodes_: function(showingDetails, showingWarning) {
+ // Keeps track of differences in checkbox width.
+ var minCheckboxWidth = 999999;
+ var maxCheckboxWidth = 0;
+
+ // Iterate over the extension data and add each item to the list.
+ for (var i = 0; i < this.data_.extensions.length; ++i) {
+ var extension = this.data_.extensions[i];
+ var id = extension.id;
+
+ var wrapper = this.ownerDocument.createElement('div');
+
+ // Figure out if the item should open expanded or not based on the state
+ // of things before we deleted the items.
+ var iter = showingDetails.length;
+ var expanded = false;
+ while (iter--) {
+ if (showingDetails[iter] == id) {
+ expanded = true;
+ break;
+ }
+ }
+ // Figure out if the butterbar should be showing.
+ iter = showingWarning.length;
+ var butterbar = false;
+ while (iter--) {
+ if (showingWarning[iter] == id) {
+ butterbar = true;
+ break;
+ }
+ }
+
+ wrapper.classList.add(expanded ? 'extension-list-item-expanded' :
+ 'extension-list-item-collaped');
+ if (!extension.enabled)
+ wrapper.classList.add('disabled');
+ wrapper.id = id;
+ this.appendChild(wrapper);
+
+ var vbox_outer = this.ownerDocument.createElement('div');
+ vbox_outer.classList.add('vbox');
+ vbox_outer.classList.add('extension-list-item');
+ wrapper.appendChild(vbox_outer);
+
+ var hbox = this.ownerDocument.createElement('div');
+ hbox.classList.add('hbox');
+ vbox_outer.appendChild(hbox);
+
+ // Add a container div for the zippy, so we can extend the hit area.
+ var container = this.ownerDocument.createElement('div');
+ // Clicking anywhere on the div expands/collapses the details.
+ container.classList.add('extension-zippy-container');
+ container.addEventListener('click', this.handleZippyClick_.bind(this));
+ hbox.appendChild(container);
+
+ // On the far left we have the zippy icon.
+ div = this.ownerDocument.createElement('div');
+ div.id = id + '_zippy';
+ div.classList.add('extension-zippy-default');
+ div.classList.add(expanded ? 'extension-zippy-expanded' :
+ 'extension-zippy-collapsed');
+ container.appendChild(div);
+
+ // Next to it, we have the extension icon.
+ icon = this.ownerDocument.createElement('img');
+ icon.classList.add('extension-icon');
+ icon.src = extension.icon;
+ hbox.appendChild(icon);
+
+ // Start a vertical box for showing the details.
+ var vbox = this.ownerDocument.createElement('div');
+ vbox.classList.add('vbox');
+ vbox.classList.add('stretch');
+ hbox.appendChild(vbox);
+
+ div = this.ownerDocument.createElement('div');
+ vbox.appendChild(div);
+
+ // Title comes next.
+ var title = this.ownerDocument.createElement('span');
+ title.classList.add('extension-title');
+ title.textContent = extension.name;
+ vbox.appendChild(title);
+
+ // Followed by version.
+ var version = this.ownerDocument.createElement('span');
+ version.classList.add('extension-version');
+ version.textContent = extension.version;
+ vbox.appendChild(version);
+
+ div = this.ownerDocument.createElement('div');
+ vbox.appendChild(div);
+
+ // And below that we have description (if provided).
+ if (extension.description.length > 0) {
+ var description = this.ownerDocument.createElement('span');
+ description.classList.add('extension-description');
+ description.textContent = extension.description;
+ vbox.appendChild(description);
+ }
+
+ // Immediately following the description, we have the
+ // Options link (optional).
+ if (extension.options_url) {
+ var link = this.ownerDocument.createElement('a');
+ link.classList.add('extension-links-trailing');
+ link.textContent = localStrings.getString('extensionSettingsOptions');
+ link.href = '#';
+ link.addEventListener('click', this.handleOptions_.bind(this));
+ vbox.appendChild(link);
+ }
+
+ // Then the optional Visit Website link.
+ if (extension.homepageUrl) {
+ var link = this.ownerDocument.createElement('a');
+ link.classList.add('extension-links-trailing');
+ link.textContent =
+ localStrings.getString('extensionSettingsVisitWebsite');
+ link.href = '#';
+ link.addEventListener('click', this.handleVisitWebsite_.bind(this));
+ vbox.appendChild(link);
+ }
+
+ // And now the details section that is normally hidden.
+ var details = this.ownerDocument.createElement('div');
+ details.classList.add('vbox');
+ vbox.appendChild(details);
+
+ this.decorateDetailsSection_(details, extension, expanded, butterbar);
+
+ // And on the right of the details we have the Enable/Enabled checkbox.
+ div = this.ownerDocument.createElement('div');
+ hbox.appendChild(div);
+
+ var section = this.ownerDocument.createElement('section');
+ section.classList.add('extension-enabling');
+ div.appendChild(section);
+
+ // The Enable checkbox.
+ var input = this.ownerDocument.createElement('input');
+ input.addEventListener('click', this.handleEnable_.bind(this));
+ input.type = 'checkbox';
+ input.name = 'toggle-' + id;
+ if (!extension.mayDisable)
+ input.disabled = true;
+ if (extension.enabled)
+ input.checked = true;
+ input.id = 'toggle-' + id;
+ section.appendChild(input);
+ var label = this.ownerDocument.createElement('label');
+ label.classList.add('extension-enabling-label');
+ if (extension.enabled)
+ label.classList.add('extension-enabling-label-bold');
+ label.setAttribute('for', 'toggle-' + id);
+ label.id = 'toggle-' + id + '-label';
+ if (extension.enabled) {
+ // Enabled (with a d).
+ label.textContent =
+ localStrings.getString('extensionSettingsEnabled');
+ } else {
+ // Enable (no d).
+ label.textContent = localStrings.getString('extensionSettingsEnable');
+ }
+ section.appendChild(label);
+
+ if (label.offsetWidth > maxCheckboxWidth)
+ maxCheckboxWidth = label.offsetWidth;
+ if (label.offsetWidth < minCheckboxWidth)
+ minCheckboxWidth = label.offsetWidth;
+
+ // And, on the far right we have the uninstall button.
+ var button = this.ownerDocument.createElement('button');
+ button.classList.add('extension-delete');
+ button.id = id;
+ if (!extension.mayDisable)
+ button.disabled = true;
+ button.textContent = localStrings.getString('extensionSettingsRemove');
+ button.addEventListener('click', this.handleUninstall_.bind(this));
+ hbox.appendChild(button);
+ }
+
+ // Do another pass, making sure checkboxes line up.
+ var difference = maxCheckboxWidth - minCheckboxWidth;
+ for (var i = 0; i < this.data_.extensions.length; ++i) {
+ var extension = this.data_.extensions[i];
+ var id = extension.id;
+ var label = $('toggle-' + id + '-label');
+ if (label.offsetWidth < maxCheckboxWidth)
+ label.style.marginRight = difference.toString() + 'px';
+ }
+ },
+
+ /**
+ * Handles decorating the details section.
+ * @param {Element} details The div that the details should be attached to.
+ * @param {Object} extension The extension we are shoting the details for.
+ * @param {boolean} expanded Whether to show the details expanded or not.
+ * @param {boolean} showButterbar Whether to show the incognito warning or
+ * not.
+ * @private
+ */
+ decorateDetailsSection_: function(details, extension,
+ expanded, showButterbar) {
+ // This container div is needed because vbox display
+ // overrides display:hidden.
+ var details_contents = this.ownerDocument.createElement('div');
+ details_contents.classList.add(expanded ? 'extension-details-visible' :
+ 'extension-details-hidden');
+ details_contents.id = extension.id + '_details';
+ details.appendChild(details_contents);
+
+ var div = this.ownerDocument.createElement('div');
+ div.classList.add('informative-text');
+ details_contents.appendChild(div);
+
+ // Keep track of how many items we'll show in the details section.
+ var itemsShown = 0;
+
+ if (this.data_.developerMode) {
+ // First we have the id.
+ var content = this.ownerDocument.createElement('div');
+ content.textContent =
+ localStrings.getString('extensionSettingsExtensionId') +
+ ' ' + extension.id;
+ div.appendChild(content);
+ itemsShown++;
+
+ // Then, the path, if provided by unpacked extension.
+ if (extension.isUnpacked) {
+ content = this.ownerDocument.createElement('div');
+ content.textContent =
+ localStrings.getString('extensionSettingsExtensionPath') +
+ ' ' + extension.path;
+ div.appendChild(content);
+ itemsShown++;
+ }
+
+ // Then, the 'managed, cannot uninstall/disable' message.
+ if (!extension.mayDisable) {
+ content = this.ownerDocument.createElement('div');
+ content.textContent =
+ localStrings.getString('extensionSettingsPolicyControlled');
+ div.appendChild(content);
+ itemsShown++;
+ }
+
+ // Then active views:
+ if (extension.views.length > 0) {
+ var table = this.ownerDocument.createElement('table');
+ table.classList.add('extension-inspect-table');
+ div.appendChild(table);
+ var tr = this.ownerDocument.createElement('tr');
+ table.appendChild(tr);
+ var td = this.ownerDocument.createElement('td');
+ td.classList.add('extension-inspect-left-column');
+ tr.appendChild(td);
+ var span = this.ownerDocument.createElement('span');
+ td.appendChild(span);
+ span.textContent =
+ localStrings.getString('extensionSettingsInspectViews');
+
+ td = this.ownerDocument.createElement('td');
+ for (var i = 0; i < extension.views.length; ++i) {
+ // Then active views:
+ content = this.ownerDocument.createElement('div');
+ var link = this.ownerDocument.createElement('a');
+ link.classList.add('extension-links-view');
+ link.textContent = extension.views[i].path;
+ link.id = extension.id;
+ link.href = '#';
+ link.addEventListener('click', this.sendInspectMessage_.bind(this));
+ content.appendChild(link);
+ td.appendChild(content);
+ tr.appendChild(td);
+
+ itemsShown++;
+ }
+ }
+ }
+
+ var content = this.ownerDocument.createElement('div');
+ details_contents.appendChild(content);
+
+ // Then Reload:
+ if (extension.enabled && extension.allow_reload) {
+ var link = this.ownerDocument.createElement('a');
+ link.classList.add('extension-links-trailing');
+ link.textContent = localStrings.getString('extensionSettingsReload');
+ link.id = extension.id;
+ link.href = '#';
+ link.addEventListener('click', this.handleReload_.bind(this));
+ content.appendChild(link);
+ itemsShown++;
+ }
+
+ // Then Show (Browser Action) Button:
+ if (extension.enabled && extension.enable_show_button) {
+ link = this.ownerDocument.createElement('a');
+ link.classList.add('extension-links-trailing');
+ link.textContent =
+ localStrings.getString('extensionSettingsShowButton');
+ link.id = extension.id;
+ link.href = '#';
+ link.addEventListener('click', this.handleShowButton_.bind(this));
+ content.appendChild(link);
+ itemsShown++;
+ }
+
+ if (extension.enabled && !extension.wantsFileAccess) {
+ // The 'allow in incognito' checkbox.
+ var label = this.ownerDocument.createElement('label');
+ label.classList.add('extension-checkbox-label');
+ content.appendChild(label);
+ var input = this.ownerDocument.createElement('input');
+ input.addEventListener('click',
+ this.handleToggleEnableIncognito_.bind(this));
+ input.id = extension.id;
+ input.type = 'checkbox';
+ if (extension.enabledIncognito)
+ input.checked = true;
+ label.appendChild(input);
+ var span = this.ownerDocument.createElement('span');
+ span.classList.add('extension-checkbox-span');
+ span.textContent =
+ localStrings.getString('extensionSettingsEnableIncognito');
+ label.appendChild(span);
+ itemsShown++;
+ }
+
+ if (extension.enabled && !extension.wantsFileAccess) {
+ // The 'allow access to file URLs' checkbox.
+ label = this.ownerDocument.createElement('label');
+ label.classList.add('extension-checkbox-label');
+ content.appendChild(label);
+ var input = this.ownerDocument.createElement('input');
+ input.addEventListener('click',
+ this.handleToggleAllowFileUrls_.bind(this));
+ input.id = extension.id;
+ input.type = 'checkbox';
+ if (extension.allowFileAccess)
+ input.checked = true;
+ label.appendChild(input);
+ var span = this.ownerDocument.createElement('span');
+ span.classList.add('extension-checkbox-span');
+ span.textContent =
+ localStrings.getString('extensionSettingsAllowFileAccess');
+ label.appendChild(span);
+ itemsShown++;
+ }
+
+ if (extension.enabled && !extension.is_hosted_app) {
+ // And add a hidden warning message for allowInIncognito.
+ content = this.ownerDocument.createElement('div');
+ content.id = extension.id + '_incognitoWarning';
+ content.classList.add('butter-bar');
+ content.hidden = !showButterbar;
+ details_contents.appendChild(content);
+
+ var span = this.ownerDocument.createElement('span');
+ span.innerHTML =
+ localStrings.getString('extensionSettingsIncognitoWarning');
+ content.appendChild(span);
+ itemsShown++;
+ }
+
+ var zippy = extension.id + '_zippy';
+ $(zippy).style.display = (itemsShown > 0) ? 'block' : 'none';
+ },
+
+ /**
+ * A lookup helper function to find an extension based on an id.
+ * @param {string} id The |id| of the extension to look up.
+ * @private
+ */
+ getExtensionWithId_: function(id) {
+ for (var i = 0; i < this.data_.extensions.length; ++i) {
+ if (this.data_.extensions[i].id == id)
+ return this.data_.extensions[i];
+ }
+ return null;
+ },
+
+ /**
+ * A lookup helper function to find the first node that has an id (starting
+ * at |node| and going up the parent chain.
+ * @param {Element} node The node to start looking at.
+ * @private
+ */
+ findIdNode_: function(node) {
+ while (node.id.length == 0) {
+ node = node.parentNode;
+ if (!node)
+ return null;
+ }
+ return node;
+ },
+
+ /**
+ * Handles the mouseclick on the zippy icon (that expands and collapses the
+ * details section).
+ * @param {Event} e Change event.
+ * @private
+ */
+ handleZippyClick_: function(e) {
+ var node = this.findIdNode_(e.target.parentNode);
+ var iter = this.firstChild;
+ while (iter) {
+ var zippy = $(iter.id + '_zippy');
+ var details = $(iter.id + '_details');
+ if (iter.id == node.id) {
+ // Toggle visibility.
+ if (iter.classList.contains('extension-list-item-expanded')) {
+ // Hide yo kids! Hide yo wife!
+ zippy.classList.remove('extension-zippy-expanded');
+ zippy.classList.add('extension-zippy-collapsed');
+ details.classList.remove('extension-details-visible');
+ details.classList.add('extension-details-hidden');
+ iter.classList.remove('extension-list-item-expanded');
+ iter.classList.add('extension-list-item-collaped');
+
+ // Hide yo incognito warning.
+ var butterBar = this.ownerDocument.getElementById(
+ iter.id + '_incognitoWarning');
+ if (!(butterBar === null))
+ butterBar.hidden = true;
+ } else {
+ // Show the contents.
+ zippy.classList.remove('extension-zippy-collapsed');
+ zippy.classList.add('extension-zippy-expanded');
+ details.classList.remove('extension-details-hidden');
+ details.classList.add('extension-details-visible');
+ iter.classList.remove('extension-list-item-collaped');
+ iter.classList.add('extension-list-item-expanded');
+ }
+ }
+ iter = iter.nextSibling;
+ }
+ },
+
+ /**
+ * Handles the mouse-up and keyboard-up events. This is used to limit the
+ * number of items to show in the list, when the user is searching for items
+ * with the search box. Otherwise, if one match is found, the whole list of
+ * extensions would be shown when we only want the matching items to be
+ * found.
+ * @param {Event} e Change event.
+ * @private
+ */
+ upEventHandler_: function(e) {
+ var searchString = $('search-field').value.toLowerCase();
+ var child = this.firstChild;
+ while (child){
+ var extension = this.getExtensionWithId_(child.id);
+ if (searchString.length == 0) {
+ // Show all.
+ child.classList.remove('search-suppress');
+ } else {
+ // If the search string does not appear within the text of the
+ // extension, then hide it.
+ if ((extension.name.toLowerCase().indexOf(searchString) < 0) &&
+ (extension.version.toLowerCase().indexOf(searchString) < 0) &&
+ (extension.description.toLowerCase().indexOf(searchString) < 0)) {
+ // Hide yo extension!
+ child.classList.add('search-suppress');
+ } else {
+ // Show yourself!
+ child.classList.remove('search-suppress');
+ }
+ }
+ child = child.nextSibling;
+ }
+ },
+
+ /**
+ * Handles the Reload Extension functionality.
+ * @param {Event} e Change event.
+ * @private
+ */
+ handleReload_: function(e) {
+ var node = this.findIdNode_(e.target);
+ chrome.send('extensionSettingsReload', [node.id]);
+ },
+
+ /**
+ * Handles the Show (Browser Action) Button functionality.
+ * @param {Event} e Change event.
+ * @private
+ */
+ handleShowButton_: function(e) {
+ var node = this.findIdNode_(e.target);
+ chrome.send('extensionSettingsShowButton', [node.id]);
+ },
+
+ /**
+ * Handles the Enable/Disable Extension functionality.
+ * @param {Event} e Change event.
+ * @private
+ */
+ handleEnable_: function(e) {
+ var node = this.findIdNode_(e.target.parentNode);
+ var extension = this.getExtensionWithId_(node.id);
+ chrome.send('extensionSettingsEnable',
+ [node.id, extension.enabled ? 'false' : 'true']);
+ chrome.send('extensionSettingsRequestExtensionsData');
+ },
+
+ /**
+ * Handles the Uninstall Extension functionality.
+ * @param {Event} e Change event.
+ * @private
+ */
+ handleUninstall_: function(e) {
+ var node = this.findIdNode_(e.target.parentNode);
+ chrome.send('extensionSettingsUninstall', [node.id]);
+ chrome.send('extensionSettingsRequestExtensionsData');
+ },
+
+ /**
+ * Handles the View Options link.
+ * @param {Event} e Change event.
+ * @private
+ */
+ handleOptions_: function(e) {
+ var node = this.findIdNode_(e.target.parentNode);
+ var extension = this.getExtensionWithId_(node.id);
+ chrome.send('extensionSettingsOptions', [extension.id]);
+ },
+
+ /**
+ * Handles the Visit Extension Website link.
+ * @param {Event} e Change event.
+ * @private
+ */
+ handleVisitWebsite_: function(e) {
+ var node = this.findIdNode_(e.target.parentNode);
+ var extension = this.getExtensionWithId_(node.id);
+ document.location = extension.homepageUrl;
+ },
+
+ /**
+ * Handles the Enable Extension In Incognito functionality.
+ * @param {Event} e Change event.
+ * @private
+ */
+ handleToggleEnableIncognito_: function(e) {
+ var node = this.findIdNode_(e.target);
+ var butterBar = document.getElementById(node.id + '_incognitoWarning');
+ butterBar.hidden = !e.target.checked;
+ chrome.send('extensionSettingsEnableIncognito',
+ [node.id, String(e.target.checked)]);
+ },
+
+ /**
+ * Handles the Allow On File URLs functionality.
+ * @param {Event} e Change event.
+ * @private
+ */
+ handleToggleAllowFileUrls_: function(e) {
+ var node = this.findIdNode_(e.target);
+ chrome.send('extensionSettingsAllowFileAccess',
+ [node.id, String(e.target.checked)]);
+ },
+
+ /**
+ * Tell the C++ ExtensionDOMHandler to inspect the page detailed in
+ * |viewData|.
+ * @param {Event} e Change event.
+ * @private
+ */
+ sendInspectMessage_: function(e) {
+ var extension = this.getExtensionWithId_(e.srcElement.id);
+ for (var i = 0; i < extension.views.length; ++i) {
+ if (extension.views[i].path == e.srcElement.innerText) {
+ // TODO(aa): This is ghetto, but WebUIBindings doesn't support sending
+ // anything other than arrays of strings, and this is all going to get
+ // replaced with V8 extensions soon anyway.
+ chrome.send('extensionSettingsInspect', [
+ String(extension.views[i].renderProcessId),
+ String(extension.views[i].renderViewId)
+ ]);
+ }
+ }
+ },
+ };
+
+ return {
+ ExtensionsList: ExtensionsList
+ };
+}); \ No newline at end of file
diff --git a/chrome/browser/resources/options/extension_settings.css b/chrome/browser/resources/options/extension_settings.css
new file mode 100644
index 0000000..c7c4a25
--- /dev/null
+++ b/chrome/browser/resources/options/extension_settings.css
@@ -0,0 +1,261 @@
+/*
+Copyright (c) 2011 The Chromium Authors. All rights reserved.
+Use of this source code is governed by a BSD-style license that can be
+found in the LICENSE file.
+*/
+
+/* TODO(finnur): Move these into a central location, either options_page.css or
+ somewhere in the shared directory */
+.hbox {
+ display: -webkit-box;
+ -webkit-box-orient: horizontal;
+}
+
+.vbox {
+ display: -webkit-box;
+ -webkit-box-orient: vertical;
+}
+
+.stretch {
+ padding-right: 10px;
+ -webkit-box-flex: 1;
+}
+
+.extension-list-item {
+ padding-bottom: 7px;
+ padding-top: 7px;
+ width: 100%;
+ -webkit-user-select: auto;
+}
+
+/* Get rid of display: table, which causes width issues. */
+.displaytable {
+ display: block;
+}
+/* Get rid of display: table row, which causes width issues. */
+.displaytable > section {
+ display: block;
+}
+/* Get rid of display: table cell, which causes width issues. */
+.displaytable > section > * {
+ display: block;
+}
+
+.extension-settings-content {
+ border-bottom : 0px solid #eee;
+ margin-top: 3px;
+}
+
+.big-list {
+ overflow-y: hidden;
+}
+
+/* Get rid of the light-blue background on list item hover. */
+.big-list:not([disabled]) > :hover {
+ background-color: white;
+ border-color: #CDCDCD;
+}
+
+.butter-bar {
+ background: #FFF299;
+ padding: 2px 5px;
+ border-radius: 3px;
+ white-space: normal;
+}
+
+.search-suppress {
+ display: none;
+ height: 0;
+}
+
+.extension-list-item-collaped {
+ height: auto;
+ margin-bottom: 16px;
+ -webkit-transition: padding 300ms, overflow 300ms, opacity 700ms;
+}
+
+.extension-list-item-expanded {
+ height: auto;
+ margin-bottom: 16px;
+ overflow: visible;
+ -webkit-transition: padding 300ms, overflow 300ms, opacity 700ms;
+}
+
+.extension-settings {
+ overflow-x: hidden;
+}
+
+.extension-icon {
+ height: 48px;
+ padding-left: 15px;
+ padding-right: 15px;
+ vertical-align: text-top;
+ width: 48px;
+ -webkit-user-select: none;
+}
+
+.extension-title {
+ font-size: 16px;
+ font-weight: 500;
+ padding-right: 20px;
+}
+
+.extension-version {
+ font-size: 13px;
+ font-weight: 400;
+}
+
+.extension-description {
+ font-size: 13px;
+ white-space: normal;
+ padding-right: 5px;
+}
+
+.extension-checkbox-span {
+ margin-left: 7px;
+}
+
+.extension-checkbox-label {
+ margin-right: 10px;
+}
+
+.extension-delete {
+ margin-left: 5px;
+}
+
+.extension-details-hidden {
+ opacity: 0;
+ max-height: 0;
+ -webkit-transition: max-height 400ms, opacity 200ms;
+}
+
+.extension-details-visible {
+ opacity: 1;
+ max-height: 100px;
+ -webkit-transition: max-height 200ms, opacity 300ms;
+}
+
+.extension-links-view {
+ padding-left: 15px;
+}
+
+.extension-links-trailing {
+ padding-right: 7px;
+}
+
+.extension-zippy-container {
+ cursor: pointer;
+ width: 20px;
+ -webkit-user-select: none;
+}
+
+.informative-text {
+ color: gray;
+}
+
+.extension-zippy-default {
+ background-image: url('zippy.png');
+ background-repeat: no-repeat;
+ background-position: center top;
+ position: absolute;
+ left: 12px;
+ top: 25px;
+ width: 6px;
+ height: 16px;
+ opacity: .25;
+}
+
+.extension-zippy-collapsed {
+ -webkit-transition: -webkit-transform .1s;
+ -webkit-transform: rotate(0deg);
+}
+
+.extension-zippy-collapsed:hover {
+ -webkit-transition: -webkit-transform .1s, opacity .1s;
+ opacity: .5;
+ -webkit-transform: rotate(5deg);
+}
+
+.extension-zippy-expanded {
+ -webkit-transition: -webkit-transform .1s;
+ -webkit-transform: rotate(90deg);
+}
+
+.extension-zippy-expanded:hover {
+ -webkit-transition: -webkit-transform .1s;
+ -webkit-transform: rotate(85deg);
+}
+
+.extension-enabling {
+ position: relative;
+ top: 3px;
+}
+
+.extension-enabling-label {
+ padding-left: 3px;
+ padding-right: 9px;
+ color: black;
+}
+
+.extension-enabling-label-bold {
+ font-weight: bold;
+}
+
+.extension-inspect-table {
+ padding: 0;
+ border-spacing: 0;
+}
+
+.extension-inspect-left-column {
+ vertical-align: text-top;
+}
+
+/* Dev */
+
+.dev-open {
+ border-bottom: 1px solid rgb(205, 205, 205);
+ height: 32px;
+ padding-bottom: 7px;
+ padding-left: 4px;
+ padding-right: 3px;
+ padding-top: 4px;
+ -webkit-transition: padding 300ms, height 300ms, opacity 700ms;
+}
+.dev-closed {
+ height: 0;
+ opacity: 0;
+ padding-left: 4px;
+ padding-right: 3px;
+ -webkit-transition: padding 300ms, height 700ms, opacity 200ms;
+}
+
+.dev-button-visible {
+ display: inherit;
+ opacity: 1;
+ -webkit-transition: opacity 200ms;
+}
+
+.dev-button-hidden {
+ display: none;
+}
+
+#suggest-gallery {
+ padding-left: 10px;
+}
+
+#dev-toggle {
+ display: block;
+ float: right;
+ margin-top: -28px;
+ margin-right: 8px;
+}
+
+#get-more-extensions-container {
+ display: -webkit-box;
+}
+
+#get-more-extensions {
+ padding-left: 10px;
+ padding-top: 5px;
+ font-size: 15px;
+}
diff --git a/chrome/browser/resources/options/extension_settings.html b/chrome/browser/resources/options/extension_settings.html
new file mode 100644
index 0000000..5a0b210
--- /dev/null
+++ b/chrome/browser/resources/options/extension_settings.html
@@ -0,0 +1,40 @@
+<div id="extension-settings" class="page" hidden>
+ <h1 i18n-content="extensionSettingsTitle"></h1>
+ <div id="dev-toggle">
+ <input id="toggle-dev-on" type="checkbox" value="off"></input>
+ <label for="toggle-dev-on" i18n-content="extensionSettingsDeveloperMode" />
+ </div>
+ <div class="displaytable">
+ <div id="dev" class="dev-closed">
+ <table id="dev-table" width="100%">
+ <tr>
+ <td>
+ <button id="load-unpacked"
+ i18n-content="extensionSettingsLoadUnpackedButton"></button>
+ <button id="pack-extension"
+ i18n-content="extensionSettingsPackButton"></button>
+ </td>
+ <td align="right">
+ <button id="update-extensions-now"
+ i18n-content="extensionSettingsUpdateButton"></button>
+ </td>
+ </tr>
+ </table>
+ </div>
+ <section class="extension-settings-content">
+ <div class="extension-settings">
+ <list class="big-list" id="extension-settings-list"></list>
+ </div>
+ </section>
+ </div>
+ <section>
+ <div><strong id="no-extensions"
+ i18n-content="extensionSettingsNoExtensions"
+ hidden="true"></strong></div>
+ <div id="suggest-gallery" hidden="true"></div>
+ <div id="get-more-extensions-container">
+ <image src="chrome://theme/IDR_WEBSTORE_ICON_32">
+ <div id="get-more-extensions"></div>
+ </div>
+ </section>
+</div>
diff --git a/chrome/browser/resources/options/extension_settings.js b/chrome/browser/resources/options/extension_settings.js
new file mode 100644
index 0000000..d58d482
--- /dev/null
+++ b/chrome/browser/resources/options/extension_settings.js
@@ -0,0 +1,179 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+cr.define('options', function() {
+ var OptionsPage = options.OptionsPage;
+ var ExtensionsList = options.ExtensionsList;
+
+ /**
+ * ExtensionSettings class
+ * Encapsulated handling of the 'Manage Extensions' page.
+ * @class
+ */
+ function ExtensionSettings() {
+ OptionsPage.call(this,
+ 'extensionSettings',
+ templateData.extensionSettingsTitle,
+ 'extension-settings');
+ }
+
+ cr.addSingletonGetter(ExtensionSettings);
+
+ ExtensionSettings.prototype = {
+ __proto__: OptionsPage.prototype,
+
+ /**
+ * Initialize the page.
+ */
+ initializePage: function() {
+ OptionsPage.prototype.initializePage.call(this);
+
+ // This will request the data to show on the page and will get a response
+ // back in returnExtensionsData.
+ chrome.send('extensionSettingsRequestExtensionsData');
+
+ // Set up the developer mode button.
+ var toggleDevMode = $('toggle-dev-on');
+ toggleDevMode.addEventListener('click',
+ this.handleToggleDevMode_.bind(this));
+
+ // Setup the gallery related links and text.
+ $('suggest-gallery').innerHTML =
+ localStrings.getString('extensionSettingsSuggestGallery');
+ $('get-more-extensions').innerHTML =
+ localStrings.getString('extensionSettingsGetMoreExtensions');
+
+ // Set up the three dev mode buttons (load unpacked, pack and update).
+ $('load-unpacked').addEventListener('click',
+ this.handleLoadUnpackedExtension_.bind(this));
+ $('pack-extension').addEventListener('click',
+ this.handlePackExtension_.bind(this));
+ $('update-extensions-now').addEventListener('click',
+ this.handleUpdateExtensionNow_.bind(this));
+ },
+
+ /**
+ * Utility function which asks the C++ to show a platform-specific file
+ * select dialog, and fire |callback| with the |filePath| that resulted.
+ * |selectType| can be either 'file' or 'folder'. |operation| can be 'load',
+ * 'packRoot', or 'pem' which are signals to the C++ to do some
+ * operation-specific configuration.
+ * @private
+ */
+ showFileDialog_: function(selectType, operation, callback) {
+ handleFilePathSelected = function(filePath) {
+ callback(filePath);
+ handleFilePathSelected = function() {};
+ };
+
+ chrome.send('extensionSettingsSelectFilePath', [selectType, operation]);
+ },
+
+ /**
+ * Handles the Load Unpacked Extension button.
+ * @param {Event} e Change event.
+ * @private
+ */
+ handleLoadUnpackedExtension_: function(e) {
+ this.showFileDialog_('folder', 'load', function(filePath) {
+ chrome.send('extensionSettingsLoad', [String(filePath)]);
+ });
+
+ chrome.send('coreOptionsUserMetricsAction',
+ ['Options_LoadUnpackedExtension']);
+ },
+
+ /**
+ * Handles the Pack Extension button.
+ * @param {Event} e Change event.
+ * @private
+ */
+ handlePackExtension_: function(e) {
+ OptionsPage.navigateToPage('packExtensionOverlay');
+ chrome.send('coreOptionsUserMetricsAction', ['Options_PackExtension']);
+ },
+
+ /**
+ * Handles the Update Extension Now button.
+ * @param {Event} e Change event.
+ * @private
+ */
+ handleUpdateExtensionNow_: function(e) {
+ chrome.send('extensionSettingsAutoupdate', []);
+ },
+
+ /**
+ * Handles the Toggle Dev Mode button.
+ * @param {Event} e Change event.
+ * @private
+ */
+ handleToggleDevMode_: function(e) {
+ var dev = $('dev');
+ if (!dev.classList.contains('dev-open')) {
+ // Make the Dev section visible.
+ dev.classList.add('dev-open');
+ dev.classList.remove('dev-closed');
+
+ $('load-unpacked').classList.add('dev-button-visible');
+ $('load-unpacked').classList.remove('dev-button-hidden');
+ $('pack-extension').classList.add('dev-button-visible');
+ $('pack-extension').classList.remove('dev-button-hidden');
+ $('update-extensions-now').classList.add('dev-button-visible');
+ $('update-extensions-now').classList.remove('dev-button-hidden');
+ } else {
+ // Hide the Dev section.
+ dev.classList.add('dev-closed');
+ dev.classList.remove('dev-open');
+
+ $('load-unpacked').classList.add('dev-button-hidden');
+ $('load-unpacked').classList.remove('dev-button-visible');
+ $('pack-extension').classList.add('dev-button-hidden');
+ $('pack-extension').classList.remove('dev-button-visible');
+ $('update-extensions-now').classList.add('dev-button-hidden');
+ $('update-extensions-now').classList.remove('dev-button-visible');
+ }
+
+ chrome.send('extensionSettingsToggleDeveloperMode', []);
+ },
+ };
+
+ /**
+ * Called by the dom_ui_ to re-populate the page with data representing
+ * the current state of installed extensions.
+ */
+ ExtensionSettings.returnExtensionsData = function(extensionsData) {
+ $('no-extensions').hidden = true;
+ $('suggest-gallery').hidden = true;
+ $('get-more-extensions-container').hidden = true;
+
+ if (extensionsData.extensions.length > 0) {
+ // Enforce order specified in the data or (if equal) then sort by
+ // extension name (case-insensitive).
+ extensionsData.extensions.sort(function(a, b) {
+ if (a.order == b.order) {
+ a = a.name.toLowerCase();
+ b = b.name.toLowerCase();
+ return a < b ? -1 : (a > b ? 1 : 0);
+ } else {
+ return a.order < b.order ? -1 : 1;
+ }
+ });
+
+ $('get-more-extensions-container').hidden = false;
+ } else {
+ $('no-extensions').hidden = false;
+ $('suggest-gallery').hidden = false;
+ }
+
+ ExtensionsList.prototype.data_ = extensionsData;
+
+ var extensionList = $('extension-settings-list');
+ ExtensionsList.decorate(extensionList);
+ }
+
+ // Export
+ return {
+ ExtensionSettings: ExtensionSettings
+ };
+});
diff --git a/chrome/browser/resources/options/options.html b/chrome/browser/resources/options/options.html
index de3754c..0b14ab8 100644
--- a/chrome/browser/resources/options/options.html
+++ b/chrome/browser/resources/options/options.html
@@ -24,6 +24,7 @@
<link rel="stylesheet" href="clear_browser_data_overlay.css">
<link rel="stylesheet" href="content_settings.css">
<link rel="stylesheet" href="cookies_view.css">
+<link rel="stylesheet" href="extension_settings.css">
<link rel="stylesheet" href="font_settings.css">
<if expr="pp_ifdef('enable_register_protocol_handler')">
<link rel="stylesheet" href="handler_options.css">
@@ -34,6 +35,7 @@
</if>
<link rel="stylesheet" href="language_options.css">
<link rel="stylesheet" href="manage_profile_overlay.css">
+<link rel="stylesheet" href="pack_extension_overlay.css">
<link rel="stylesheet" href="password_manager.css">
<link rel="stylesheet" href="password_manager_list.css">
<link rel="stylesheet" href="personal_options.css">
@@ -88,6 +90,7 @@
<include src="instant_confirm_overlay.html">
<include src="language_add_language_overlay.html">
<include src="manage_profile_overlay.html">
+ <include src="pack_extension_overlay.html">
<include src="../sync_setup_overlay.html">
<if expr="pp_ifdef('chromeos')">
<include
@@ -126,6 +129,7 @@
<include src="chromeos/accounts_options.html">
</if>
<include src="advanced_options.html">
+ <include src="extension_settings.html">
</div>
<div id="subpage-sheet-container-1"
class="subpage-sheet-container transparent" hidden>
diff --git a/chrome/browser/resources/options/options.js b/chrome/browser/resources/options/options.js
index 3e5c41b..bb0f3d2 100644
--- a/chrome/browser/resources/options/options.js
+++ b/chrome/browser/resources/options/options.js
@@ -14,6 +14,7 @@ var ContentSettings = options.ContentSettings;
var ContentSettingsExceptionsArea =
options.contentSettings.ContentSettingsExceptionsArea;
var CookiesView = options.CookiesView;
+var ExtensionSettings = options.ExtensionSettings;
var FontSettings = options.FontSettings;
var HandlerOptions = options.HandlerOptions;
var ImportDataOverlay = options.ImportDataOverlay;
@@ -21,6 +22,7 @@ var IntentsView = options.IntentsView;
var InstantConfirmOverlay = options.InstantConfirmOverlay;
var LanguageOptions = options.LanguageOptions;
var OptionsPage = options.OptionsPage;
+var PackExtensionOverlay = options.PackExtensionOverlay;
var PasswordManager = options.PasswordManager;
var PersonalOptions = options.PersonalOptions;
var Preferences = options.Preferences;
@@ -166,6 +168,10 @@ function load() {
OptionsPage.registerOverlay(ManageProfileOverlay.getInstance(),
PersonalOptions.getInstance());
+ OptionsPage.register(ExtensionSettings.getInstance());
+ OptionsPage.registerOverlay(PackExtensionOverlay.getInstance(),
+ ExtensionSettings.getInstance());
+
if (cr.isChromeOS) {
OptionsPage.register(AccountsOptions.getInstance());
OptionsPage.registerSubPage(ProxyOptions.getInstance(),
diff --git a/chrome/browser/resources/options/options_bundle.js b/chrome/browser/resources/options/options_bundle.js
index 0b58a74..3701f1a 100644
--- a/chrome/browser/resources/options/options_bundle.js
+++ b/chrome/browser/resources/options/options_bundle.js
@@ -61,6 +61,8 @@
<include src="content_settings_ui.js"></include>
<include src="cookies_list.js"></include>
<include src="cookies_view.js"></include>
+<include src="extension_list.js"></include>
+<include src="extension_settings.js"></include>
<include src="font_settings.js"></include>
<if expr="pp_ifdef('enable_register_protocol_handler')">
<include src="handler_options.js"></script>
@@ -76,6 +78,7 @@
<include src="language_list.js"></include>
<include src="language_options.js"></include>
<include src="manage_profile_overlay.js"></include>
+<include src="pack_extension_overlay.js"></include>
<include src="password_manager.js"></include>
<include src="password_manager_list.js"></include>
<include src="personal_options.js"></include>
diff --git a/chrome/browser/resources/options/pack_extension_overlay.css b/chrome/browser/resources/options/pack_extension_overlay.css
new file mode 100644
index 0000000..169750b
--- /dev/null
+++ b/chrome/browser/resources/options/pack_extension_overlay.css
@@ -0,0 +1,18 @@
+/*
+Copyright (c) 2011 The Chromium Authors. All rights reserved.
+Use of this source code is governed by a BSD-style license that can be
+found in the LICENSE file.
+*/
+
+.packExtensionHeading {
+ width: 520px;
+ padding-bottom: 5px;
+}
+
+.packExtensionTextBoxes {
+ text-align: right;
+}
+
+.packExtensionTextArea {
+ width: 260px;
+}
diff --git a/chrome/browser/resources/options/pack_extension_overlay.html b/chrome/browser/resources/options/pack_extension_overlay.html
new file mode 100644
index 0000000..bd77789
--- /dev/null
+++ b/chrome/browser/resources/options/pack_extension_overlay.html
@@ -0,0 +1,28 @@
+<div id="packExtensionOverlay" class="page" hidden>
+ <h1 i18n-content="packExtensionOverlay"></h1>
+ <div id="cbdContentArea" class="content-area">
+ <div class="packExtensionHeading" i18n-content="packExtensionHeading"></div>
+ <div class="packExtensionTextBoxes">
+ <label i18n-content="packExtensionRootDir"></label>
+ <input class="packExtensionTextArea" id="extensionRootDir" type="text" />
+ <button id="browseExtensionDir"
+ i18n-content="packExtensionBrowseButton"></button>
+ </div>
+ <div class="packExtensionTextBoxes">
+ <label i18n-content="packExtensionPrivateKey"></label>
+ <input class="packExtensionTextArea"
+ id="extensionPrivateKey" type="text" />
+ <button id="browsePrivateKey"
+ i18n-content="packExtensionBrowseButton"></button>
+ </div>
+ </div>
+ <div class="action-area">
+ <div class="action-area-right">
+ <div class="button-strip">
+ <button id="packExtensionDismiss" i18n-content="cancel"></button>
+ <button id="packExtensionCommit"
+ i18n-content="packExtensionCommit"></button>
+ </div>
+ </div>
+ </div>
+</div> \ No newline at end of file
diff --git a/chrome/browser/resources/options/pack_extension_overlay.js b/chrome/browser/resources/options/pack_extension_overlay.js
new file mode 100644
index 0000000..6e69b03
--- /dev/null
+++ b/chrome/browser/resources/options/pack_extension_overlay.js
@@ -0,0 +1,90 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+cr.define('options', function() {
+ const OptionsPage = options.OptionsPage;
+
+ /**
+ * PackExtensionOverlay class
+ * Encapsulated handling of the 'Pack Extension' overlay page.
+ * @class
+ */
+ function PackExtensionOverlay() {
+ OptionsPage.call(this, 'packExtensionOverlay',
+ templateData.packExtensionOverlayTabTitle,
+ 'packExtensionOverlay');
+ }
+
+ cr.addSingletonGetter(PackExtensionOverlay);
+
+ PackExtensionOverlay.prototype = {
+ // Inherit PackExtensionOverlay from OptionsPage.
+ __proto__: OptionsPage.prototype,
+
+ /**
+ * Initialize the page.
+ */
+ initializePage: function() {
+ // Call base class implementation to starts preference initialization.
+ OptionsPage.prototype.initializePage.call(this);
+
+ $('packExtensionDismiss').onclick = function(event) {
+ OptionsPage.closeOverlay();
+ };
+ $('packExtensionCommit').onclick = function(event) {
+ var extensionPath = $('extensionRootDir').value;
+ var privateKeyPath = $('extensionPrivateKey').value;
+ chrome.send('pack', [extensionPath, privateKeyPath]);
+ };
+ $('browseExtensionDir').addEventListener('click',
+ this.handleBrowseExtensionDir_.bind(this));
+ $('browsePrivateKey').addEventListener('click',
+ this.handleBrowsePrivateKey_.bind(this));
+ },
+
+ /**
+ * Utility function which asks the C++ to show a platform-specific file
+ * select dialog, and fire |callback| with the |filePath| that resulted.
+ * |selectType| can be either 'file' or 'folder'. |operation| can be 'load',
+ * 'packRoot', or 'pem' which are signals to the C++ to do some
+ * operation-specific configuration.
+ @private
+ */
+ showFileDialog_: function(selectType, operation, callback) {
+ handleFilePathSelected = function(filePath) {
+ callback(filePath);
+ handleFilePathSelected = function() {};
+ };
+
+ chrome.send('extensionSettingsSelectFilePath', [selectType, operation]);
+ },
+
+ /**
+ * Handles the showing of the extension directory browser.
+ * @param {Event} e Change event.
+ * @private
+ */
+ handleBrowseExtensionDir_: function(e) {
+ this.showFileDialog_('folder', 'load', function(filePath) {
+ $('extensionRootDir').value = filePath;
+ });
+ },
+
+ /**
+ * Handles the showing of the extension private key file.
+ * @param {Event} e Change event.
+ * @private
+ */
+ handleBrowsePrivateKey_: function(e) {
+ this.showFileDialog_('file', 'load', function(filePath) {
+ $('extensionPrivateKey').value = filePath;
+ });
+ },
+ };
+
+ // Export
+ return {
+ PackExtensionOverlay: PackExtensionOverlay
+ };
+});
diff --git a/chrome/browser/resources/options/zippy.png b/chrome/browser/resources/options/zippy.png
index 4b4adff..c16f42e 100644
--- a/chrome/browser/resources/options/zippy.png
+++ b/chrome/browser/resources/options/zippy.png
Binary files differ
diff --git a/chrome/browser/ui/webui/options/extension_settings_handler.cc b/chrome/browser/ui/webui/options/extension_settings_handler.cc
index b7ac296..4fb7156 100644
--- a/chrome/browser/ui/webui/options/extension_settings_handler.cc
+++ b/chrome/browser/ui/webui/options/extension_settings_handler.cc
@@ -2,42 +2,27 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#include "chrome/browser/extensions/extensions_ui.h"
-
-#include <algorithm>
+#include "chrome/browser/ui/webui/options/extension_settings_handler.h"
#include "base/base64.h"
-#include "base/callback.h"
#include "base/file_util.h"
-#include "base/memory/singleton.h"
#include "base/string_number_conversions.h"
-#include "base/string_util.h"
-#include "base/threading/thread.h"
#include "base/utf_string_conversions.h"
+#include "base/values.h"
#include "base/version.h"
+#include "chrome/browser/debugger/devtools_window.h"
#include "chrome/browser/extensions/crx_installer.h"
#include "chrome/browser/extensions/extension_disabled_infobar_delegate.h"
-#include "chrome/browser/extensions/extension_error_reporter.h"
-#include "chrome/browser/extensions/extension_host.h"
-#include "chrome/browser/extensions/extension_message_service.h"
#include "chrome/browser/extensions/extension_service.h"
#include "chrome/browser/extensions/extension_updater.h"
#include "chrome/browser/google/google_util.h"
-#include "chrome/browser/prefs/pref_service.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/tab_contents/background_contents.h"
-#include "chrome/browser/ui/browser_list.h"
#include "chrome/common/extensions/extension.h"
-#include "chrome/common/extensions/extension_icon_set.h"
-#include "chrome/common/extensions/url_pattern.h"
-#include "chrome/common/extensions/user_script.h"
-#include "chrome/common/jstemplate_builder.h"
#include "chrome/common/pref_names.h"
#include "chrome/common/url_constants.h"
-#include "content/browser/debugger/devtools_window.h"
#include "content/browser/renderer_host/render_process_host.h"
#include "content/browser/renderer_host/render_view_host.h"
-#include "content/browser/renderer_host/render_widget_host.h"
#include "content/browser/tab_contents/tab_contents.h"
#include "content/browser/tab_contents/tab_contents_view.h"
#include "content/common/content_notification_types.h"
@@ -46,7 +31,6 @@
#include "grit/chromium_strings.h"
#include "grit/generated_resources.h"
#include "grit/theme_resources.h"
-#include "net/base/net_util.h"
#include "ui/base/l10n/l10n_util.h"
#include "ui/base/resource/resource_bundle.h"
#include "ui/gfx/codec/png_codec.h"
@@ -81,130 +65,16 @@ bool ShouldShowExtension(const Extension* extension) {
////////////////////////////////////////////////////////////////////////////////
//
-// ExtensionsHTMLSource
-//
-////////////////////////////////////////////////////////////////////////////////
-
-ExtensionsUIHTMLSource::ExtensionsUIHTMLSource()
- : DataSource(chrome::kChromeUIExtensionsHost, MessageLoop::current()) {
-}
-
-void ExtensionsUIHTMLSource::StartDataRequest(const std::string& path,
- bool is_incognito,
- int request_id) {
- DictionaryValue localized_strings;
- localized_strings.SetString("title",
- l10n_util::GetStringUTF16(IDS_EXTENSIONS_TITLE));
- localized_strings.SetString("devModeLink",
- l10n_util::GetStringUTF16(IDS_EXTENSIONS_DEVELOPER_MODE_LINK));
- localized_strings.SetString("devModePrefix",
- l10n_util::GetStringUTF16(IDS_EXTENSIONS_DEVELOPER_MODE_PREFIX));
- localized_strings.SetString("loadUnpackedButton",
- l10n_util::GetStringUTF16(IDS_EXTENSIONS_LOAD_UNPACKED_BUTTON));
- localized_strings.SetString("packButton",
- l10n_util::GetStringUTF16(IDS_EXTENSIONS_PACK_BUTTON));
- localized_strings.SetString("updateButton",
- l10n_util::GetStringUTF16(IDS_EXTENSIONS_UPDATE_BUTTON));
- localized_strings.SetString("noExtensions",
- l10n_util::GetStringUTF16(IDS_EXTENSIONS_NONE_INSTALLED));
- localized_strings.SetString("suggestGallery",
- l10n_util::GetStringFUTF16(IDS_EXTENSIONS_NONE_INSTALLED_SUGGEST_GALLERY,
- ASCIIToUTF16("<a href='") +
- ASCIIToUTF16(google_util::AppendGoogleLocaleParam(
- GURL(Extension::ChromeStoreLaunchURL())).spec()) +
- ASCIIToUTF16("'>"),
- ASCIIToUTF16("</a>")));
- localized_strings.SetString("getMoreExtensions",
- ASCIIToUTF16("<a href='") +
- ASCIIToUTF16(google_util::AppendGoogleLocaleParam(
- GURL(Extension::ChromeStoreLaunchURL())).spec()) +
- ASCIIToUTF16("'>") +
- l10n_util::GetStringUTF16(IDS_GET_MORE_EXTENSIONS) +
- ASCIIToUTF16("</a>"));
- localized_strings.SetString("extensionCrashed",
- l10n_util::GetStringUTF16(IDS_EXTENSIONS_CRASHED_EXTENSION));
- localized_strings.SetString("extensionDisabled",
- l10n_util::GetStringUTF16(IDS_EXTENSIONS_DISABLED_EXTENSION));
- localized_strings.SetString("inDevelopment",
- l10n_util::GetStringUTF16(IDS_EXTENSIONS_IN_DEVELOPMENT));
- localized_strings.SetString("viewIncognito",
- l10n_util::GetStringUTF16(IDS_EXTENSIONS_VIEW_INCOGNITO));
- localized_strings.SetString("extensionId",
- l10n_util::GetStringUTF16(IDS_EXTENSIONS_ID));
- localized_strings.SetString("extensionVersion",
- l10n_util::GetStringUTF16(IDS_EXTENSIONS_VERSION));
- localized_strings.SetString("inspectViews",
- l10n_util::GetStringUTF16(IDS_EXTENSIONS_INSPECT_VIEWS));
- localized_strings.SetString("inspectPopupsInstructions",
- l10n_util::GetStringUTF16(IDS_EXTENSIONS_INSPECT_POPUPS_INSTRUCTIONS));
- localized_strings.SetString("disable",
- l10n_util::GetStringUTF16(IDS_EXTENSIONS_DISABLE));
- localized_strings.SetString("enable",
- l10n_util::GetStringUTF16(IDS_EXTENSIONS_ENABLE));
- localized_strings.SetString("enableIncognito",
- l10n_util::GetStringUTF16(IDS_EXTENSIONS_ENABLE_INCOGNITO));
- localized_strings.SetString("allowFileAccess",
- l10n_util::GetStringUTF16(IDS_EXTENSIONS_ALLOW_FILE_ACCESS));
- localized_strings.SetString("incognitoWarning",
- l10n_util::GetStringFUTF16(IDS_EXTENSIONS_INCOGNITO_WARNING,
- l10n_util::GetStringUTF16(IDS_PRODUCT_NAME)));
- localized_strings.SetString("reload",
- l10n_util::GetStringUTF16(IDS_EXTENSIONS_RELOAD));
- localized_strings.SetString("uninstall",
- l10n_util::GetStringUTF16(IDS_EXTENSIONS_UNINSTALL));
- localized_strings.SetString("options",
- l10n_util::GetStringUTF16(IDS_EXTENSIONS_OPTIONS));
- localized_strings.SetString("packDialogTitle",
- l10n_util::GetStringUTF16(IDS_EXTENSION_PACK_DIALOG_TITLE));
- localized_strings.SetString("packDialogHeading",
- l10n_util::GetStringUTF16(IDS_EXTENSION_PACK_DIALOG_HEADING));
- localized_strings.SetString("rootDirectoryLabel",
- l10n_util::GetStringUTF16(
- IDS_EXTENSION_PACK_DIALOG_ROOT_DIRECTORY_LABEL));
- localized_strings.SetString("packDialogBrowse",
- l10n_util::GetStringUTF16(IDS_EXTENSION_PACK_DIALOG_BROWSE));
- localized_strings.SetString("privateKeyLabel",
- l10n_util::GetStringUTF16(IDS_EXTENSION_PACK_DIALOG_PRIVATE_KEY_LABEL));
- localized_strings.SetString("okButton",
- l10n_util::GetStringUTF16(IDS_OK));
- localized_strings.SetString("cancelButton",
- l10n_util::GetStringUTF16(IDS_CANCEL));
- localized_strings.SetString("showButton",
- l10n_util::GetStringUTF16(IDS_EXTENSIONS_SHOW_BUTTON));
-
- SetFontAndTextDirection(&localized_strings);
-
- static const base::StringPiece extensions_html(
- ResourceBundle::GetSharedInstance().GetRawDataResource(
- IDR_EXTENSIONS_UI_HTML));
- std::string full_html(extensions_html.data(), extensions_html.size());
- jstemplate_builder::AppendJsonHtml(&localized_strings, &full_html);
- jstemplate_builder::AppendI18nTemplateSourceHtml(&full_html);
- jstemplate_builder::AppendI18nTemplateProcessHtml(&full_html);
- jstemplate_builder::AppendJsTemplateSourceHtml(&full_html);
-
- scoped_refptr<RefCountedBytes> html_bytes(new RefCountedBytes);
- html_bytes->data.resize(full_html.size());
- std::copy(full_html.begin(), full_html.end(), html_bytes->data.begin());
-
- SendResponse(request_id, html_bytes);
-}
-
-std::string ExtensionsUIHTMLSource::GetMimeType(const std::string&) const {
- return "text/html";
-}
-
-////////////////////////////////////////////////////////////////////////////////
-//
-// ExtensionsDOMHandler::IconLoader
+// ExtensionSettingsHandler::IconLoader
//
////////////////////////////////////////////////////////////////////////////////
-ExtensionsDOMHandler::IconLoader::IconLoader(ExtensionsDOMHandler* handler)
+ExtensionSettingsHandler::IconLoader::IconLoader(
+ ExtensionSettingsHandler* handler)
: handler_(handler) {
}
-void ExtensionsDOMHandler::IconLoader::LoadIcons(
+void ExtensionSettingsHandler::IconLoader::LoadIcons(
std::vector<ExtensionResource>* icons, DictionaryValue* json) {
BrowserThread::PostTask(
BrowserThread::FILE, FROM_HERE,
@@ -212,11 +82,11 @@ void ExtensionsDOMHandler::IconLoader::LoadIcons(
&IconLoader::LoadIconsOnFileThread, icons, json));
}
-void ExtensionsDOMHandler::IconLoader::Cancel() {
+void ExtensionSettingsHandler::IconLoader::Cancel() {
handler_ = NULL;
}
-void ExtensionsDOMHandler::IconLoader::LoadIconsOnFileThread(
+void ExtensionSettingsHandler::IconLoader::LoadIconsOnFileThread(
std::vector<ExtensionResource>* icons, DictionaryValue* json) {
scoped_ptr<std::vector<ExtensionResource> > icons_deleter(icons);
scoped_ptr<DictionaryValue> json_deleter(json);
@@ -279,7 +149,7 @@ void ExtensionsDOMHandler::IconLoader::LoadIconsOnFileThread(
json_deleter.release()));
}
-void ExtensionsDOMHandler::IconLoader::ReportResultOnUIThread(
+void ExtensionSettingsHandler::IconLoader::ReportResultOnUIThread(
DictionaryValue* json) {
if (handler_)
handler_->OnIconsLoaded(json);
@@ -288,48 +158,62 @@ void ExtensionsDOMHandler::IconLoader::ReportResultOnUIThread(
///////////////////////////////////////////////////////////////////////////////
//
-// ExtensionsDOMHandler
+// ExtensionSettingsHandler
//
///////////////////////////////////////////////////////////////////////////////
-ExtensionsDOMHandler::ExtensionsDOMHandler(ExtensionService* extension_service)
- : extension_service_(extension_service),
+ExtensionSettingsHandler::ExtensionSettingsHandler()
+ : extension_service_(NULL),
ignore_notifications_(false),
deleting_rvh_(NULL) {
}
-void ExtensionsDOMHandler::RegisterMessages() {
- web_ui_->RegisterMessageCallback("requestExtensionsData",
- NewCallback(this, &ExtensionsDOMHandler::HandleRequestExtensionsData));
- web_ui_->RegisterMessageCallback("toggleDeveloperMode",
- NewCallback(this, &ExtensionsDOMHandler::HandleToggleDeveloperMode));
- web_ui_->RegisterMessageCallback("inspect",
- NewCallback(this, &ExtensionsDOMHandler::HandleInspectMessage));
- web_ui_->RegisterMessageCallback("reload",
- NewCallback(this, &ExtensionsDOMHandler::HandleReloadMessage));
- web_ui_->RegisterMessageCallback("enable",
- NewCallback(this, &ExtensionsDOMHandler::HandleEnableMessage));
- web_ui_->RegisterMessageCallback("enableIncognito",
- NewCallback(this, &ExtensionsDOMHandler::HandleEnableIncognitoMessage));
- web_ui_->RegisterMessageCallback("allowFileAccess",
- NewCallback(this, &ExtensionsDOMHandler::HandleAllowFileAccessMessage));
- web_ui_->RegisterMessageCallback("uninstall",
- NewCallback(this, &ExtensionsDOMHandler::HandleUninstallMessage));
- web_ui_->RegisterMessageCallback("options",
- NewCallback(this, &ExtensionsDOMHandler::HandleOptionsMessage));
- web_ui_->RegisterMessageCallback("showButton",
- NewCallback(this, &ExtensionsDOMHandler::HandleShowButtonMessage));
- web_ui_->RegisterMessageCallback("load",
- NewCallback(this, &ExtensionsDOMHandler::HandleLoadMessage));
- web_ui_->RegisterMessageCallback("pack",
- NewCallback(this, &ExtensionsDOMHandler::HandlePackMessage));
- web_ui_->RegisterMessageCallback("autoupdate",
- NewCallback(this, &ExtensionsDOMHandler::HandleAutoUpdateMessage));
- web_ui_->RegisterMessageCallback("selectFilePath",
- NewCallback(this, &ExtensionsDOMHandler::HandleSelectFilePathMessage));
-}
-
-void ExtensionsDOMHandler::HandleRequestExtensionsData(const ListValue* args) {
+ExtensionSettingsHandler::~ExtensionSettingsHandler() {
+ // There may be pending file dialogs, we need to tell them that we've gone
+ // away so they don't try and call back to us.
+ if (load_extension_dialog_.get())
+ load_extension_dialog_->ListenerDestroyed();
+
+ if (icon_loader_.get())
+ icon_loader_->Cancel();
+}
+
+void ExtensionSettingsHandler::RegisterMessages() {
+ web_ui_->RegisterMessageCallback("extensionSettingsRequestExtensionsData",
+ NewCallback(this,
+ &ExtensionSettingsHandler::HandleRequestExtensionsData));
+ web_ui_->RegisterMessageCallback("extensionSettingsToggleDeveloperMode",
+ NewCallback(this, &ExtensionSettingsHandler::HandleToggleDeveloperMode));
+ web_ui_->RegisterMessageCallback("extensionSettingsInspect",
+ NewCallback(this, &ExtensionSettingsHandler::HandleInspectMessage));
+ web_ui_->RegisterMessageCallback("extensionSettingsReload",
+ NewCallback(this, &ExtensionSettingsHandler::HandleReloadMessage));
+ web_ui_->RegisterMessageCallback("extensionSettingsEnable",
+ NewCallback(this,
+ &ExtensionSettingsHandler::HandleEnableMessage));
+ web_ui_->RegisterMessageCallback("extensionSettingsEnableIncognito",
+ NewCallback(this,
+ &ExtensionSettingsHandler::HandleEnableIncognitoMessage));
+ web_ui_->RegisterMessageCallback("extensionSettingsAllowFileAccess",
+ NewCallback(this,
+ &ExtensionSettingsHandler::HandleAllowFileAccessMessage));
+ web_ui_->RegisterMessageCallback("extensionSettingsUninstall",
+ NewCallback(this, &ExtensionSettingsHandler::HandleUninstallMessage));
+ web_ui_->RegisterMessageCallback("extensionSettingsOptions",
+ NewCallback(this, &ExtensionSettingsHandler::HandleOptionsMessage));
+ web_ui_->RegisterMessageCallback("extensionSettingsShowButton",
+ NewCallback(this, &ExtensionSettingsHandler::HandleShowButtonMessage));
+ web_ui_->RegisterMessageCallback("extensionSettingsLoad",
+ NewCallback(this, &ExtensionSettingsHandler::HandleLoadMessage));
+ web_ui_->RegisterMessageCallback("extensionSettingsAutoupdate",
+ NewCallback(this, &ExtensionSettingsHandler::HandleAutoUpdateMessage));
+ web_ui_->RegisterMessageCallback("extensionSettingsSelectFilePath",
+ NewCallback(this,
+ &ExtensionSettingsHandler::HandleSelectFilePathMessage));
+}
+
+void ExtensionSettingsHandler::HandleRequestExtensionsData(
+ const ListValue* args) {
DictionaryValue* results = new DictionaryValue();
// Add the extensions to the results structure.
@@ -346,7 +230,7 @@ void ExtensionsDOMHandler::HandleRequestExtensionsData(const ListValue* args) {
extension != extensions->end(); ++extension) {
if (ShouldShowExtension(*extension)) {
extensions_list->Append(CreateExtensionDetailValue(
- extension_service_.get(),
+ extension_service_,
*extension,
GetActivePagesForExtension(*extension),
true, false)); // enabled, terminated
@@ -358,7 +242,7 @@ void ExtensionsDOMHandler::HandleRequestExtensionsData(const ListValue* args) {
extension != extensions->end(); ++extension) {
if (ShouldShowExtension(*extension)) {
extensions_list->Append(CreateExtensionDetailValue(
- extension_service_.get(),
+ extension_service_,
*extension,
GetActivePagesForExtension(*extension),
false, false)); // enabled, terminated
@@ -371,7 +255,7 @@ void ExtensionsDOMHandler::HandleRequestExtensionsData(const ListValue* args) {
extension != extensions->end(); ++extension) {
if (ShouldShowExtension(*extension)) {
extensions_list->Append(CreateExtensionDetailValue(
- extension_service_.get(),
+ extension_service_,
*extension,
empty_pages, // Terminated process has no active pages.
false, true)); // enabled, terminated
@@ -380,8 +264,9 @@ void ExtensionsDOMHandler::HandleRequestExtensionsData(const ListValue* args) {
}
results->Set("extensions", extensions_list);
- bool developer_mode = web_ui_->GetProfile()->GetPrefs()
- ->GetBoolean(prefs::kExtensionsUIDeveloperMode);
+ Profile* profile = Profile::FromWebUI(web_ui_);
+ bool developer_mode =
+ profile->GetPrefs()->GetBoolean(prefs::kExtensionsUIDeveloperMode);
results->SetBoolean("developerMode", developer_mode);
if (icon_loader_.get())
@@ -391,67 +276,72 @@ void ExtensionsDOMHandler::HandleRequestExtensionsData(const ListValue* args) {
icon_loader_->LoadIcons(extension_icons, results);
}
-void ExtensionsDOMHandler::OnIconsLoaded(DictionaryValue* json) {
- web_ui_->CallJavascriptFunction(L"returnExtensionsData", *json);
+void ExtensionSettingsHandler::OnIconsLoaded(DictionaryValue* json) {
+ web_ui_->CallJavascriptFunction("ExtensionSettings.returnExtensionsData",
+ *json);
delete json;
// Register for notifications that we need to reload the page.
registrar_.RemoveAll();
- registrar_.Add(this, chrome::EXTENSION_LOADED,
+ registrar_.Add(this, chrome::NOTIFICATION_EXTENSION_LOADED,
NotificationService::AllSources());
- registrar_.Add(this, chrome::EXTENSION_PROCESS_CREATED,
+ registrar_.Add(this, chrome::NOTIFICATION_EXTENSION_PROCESS_CREATED,
NotificationService::AllSources());
- registrar_.Add(this, chrome::EXTENSION_UNLOADED,
+ registrar_.Add(this, chrome::NOTIFICATION_EXTENSION_UNLOADED,
NotificationService::AllSources());
- registrar_.Add(this, chrome::EXTENSION_UPDATE_DISABLED,
+ registrar_.Add(this, chrome::NOTIFICATION_EXTENSION_UPDATE_DISABLED,
NotificationService::AllSources());
registrar_.Add(this,
- chrome::NAV_ENTRY_COMMITTED,
+ content::NOTIFICATION_NAV_ENTRY_COMMITTED,
NotificationService::AllSources());
registrar_.Add(this,
- chrome::RENDER_VIEW_HOST_CREATED,
+ content::NOTIFICATION_RENDER_VIEW_HOST_CREATED,
NotificationService::AllSources());
registrar_.Add(this,
- chrome::RENDER_VIEW_HOST_DELETED,
+ content::NOTIFICATION_RENDER_VIEW_HOST_DELETED,
NotificationService::AllSources());
registrar_.Add(this,
- chrome::BACKGROUND_CONTENTS_NAVIGATED,
+ chrome::NOTIFICATION_BACKGROUND_CONTENTS_NAVIGATED,
NotificationService::AllSources());
registrar_.Add(this,
- chrome::BACKGROUND_CONTENTS_DELETED,
+ chrome::NOTIFICATION_BACKGROUND_CONTENTS_DELETED,
NotificationService::AllSources());
registrar_.Add(this,
- chrome::EXTENSION_BROWSER_ACTION_VISIBILITY_CHANGED,
+ chrome::NOTIFICATION_EXTENSION_BROWSER_ACTION_VISIBILITY_CHANGED,
NotificationService::AllSources());
}
-ExtensionResource ExtensionsDOMHandler::PickExtensionIcon(
+ExtensionResource ExtensionSettingsHandler::PickExtensionIcon(
const Extension* extension) {
return extension->GetIconResource(Extension::EXTENSION_ICON_MEDIUM,
ExtensionIconSet::MATCH_BIGGER);
}
-ExtensionUninstallDialog* ExtensionsDOMHandler::GetExtensionUninstallDialog() {
+ExtensionUninstallDialog*
+ExtensionSettingsHandler::GetExtensionUninstallDialog() {
if (!extension_uninstall_dialog_.get()) {
extension_uninstall_dialog_.reset(
- new ExtensionUninstallDialog(web_ui_->GetProfile()));
+ new ExtensionUninstallDialog(Profile::FromWebUI(web_ui_)));
}
return extension_uninstall_dialog_.get();
}
-void ExtensionsDOMHandler::HandleToggleDeveloperMode(const ListValue* args) {
- bool developer_mode = web_ui_->GetProfile()->GetPrefs()
- ->GetBoolean(prefs::kExtensionsUIDeveloperMode);
- web_ui_->GetProfile()->GetPrefs()->SetBoolean(
+void ExtensionSettingsHandler::HandleToggleDeveloperMode(
+ const ListValue* args) {
+ Profile* profile = Profile::FromWebUI(web_ui_);
+ bool developer_mode =
+ profile->GetPrefs()->GetBoolean(prefs::kExtensionsUIDeveloperMode);
+ profile->GetPrefs()->SetBoolean(
prefs::kExtensionsUIDeveloperMode, !developer_mode);
+ HandleRequestExtensionsData(NULL);
}
-void ExtensionsDOMHandler::HandleInspectMessage(const ListValue* args) {
+void ExtensionSettingsHandler::HandleInspectMessage(const ListValue* args) {
std::string render_process_id_str;
std::string render_view_id_str;
int render_process_id;
int render_view_id;
- CHECK(args->GetSize() == 2);
+ CHECK_EQ(2U, args->GetSize());
CHECK(args->GetString(0, &render_process_id_str));
CHECK(args->GetString(1, &render_view_id_str));
CHECK(base::StringToInt(render_process_id_str, &render_process_id));
@@ -466,24 +356,31 @@ void ExtensionsDOMHandler::HandleInspectMessage(const ListValue* args) {
DevToolsWindow::OpenDevToolsWindow(host);
}
-void ExtensionsDOMHandler::HandleReloadMessage(const ListValue* args) {
- std::string extension_id = WideToASCII(ExtractStringValue(args));
+void ExtensionSettingsHandler::HandleReloadMessage(const ListValue* args) {
+ std::string extension_id = UTF16ToUTF8(ExtractStringValue(args));
CHECK(!extension_id.empty());
extension_service_->ReloadExtension(extension_id);
}
-void ExtensionsDOMHandler::HandleEnableMessage(const ListValue* args) {
- CHECK(args->GetSize() == 2);
+void ExtensionSettingsHandler::HandleEnableMessage(const ListValue* args) {
+ CHECK_EQ(2U, args->GetSize());
std::string extension_id, enable_str;
CHECK(args->GetString(0, &extension_id));
CHECK(args->GetString(1, &enable_str));
+
+ const Extension* extension =
+ extension_service_->GetExtensionById(extension_id, true);
+ if (!Extension::UserMayDisable(extension->location())) {
+ LOG(ERROR) << "Attempt to enable an extension that is non-usermanagable was"
+ << "made. Extension id: " << extension->id();
+ return;
+ }
+
if (enable_str == "true") {
ExtensionPrefs* prefs = extension_service_->extension_prefs();
if (prefs->DidExtensionEscalatePermissions(extension_id)) {
- const Extension* extension =
- extension_service_->GetExtensionById(extension_id, true);
ShowExtensionDisabledDialog(extension_service_,
- web_ui_->GetProfile(), extension);
+ Profile::FromWebUI(web_ui_), extension);
} else {
extension_service_->EnableExtension(extension_id);
}
@@ -492,8 +389,9 @@ void ExtensionsDOMHandler::HandleEnableMessage(const ListValue* args) {
}
}
-void ExtensionsDOMHandler::HandleEnableIncognitoMessage(const ListValue* args) {
- CHECK(args->GetSize() == 2);
+void ExtensionSettingsHandler::HandleEnableIncognitoMessage(
+ const ListValue* args) {
+ CHECK_EQ(2U, args->GetSize());
std::string extension_id, enable_str;
CHECK(args->GetString(0, &extension_id));
CHECK(args->GetString(1, &enable_str));
@@ -513,12 +411,14 @@ void ExtensionsDOMHandler::HandleEnableIncognitoMessage(const ListValue* args) {
//
// Bug: http://crbug.com/41384
ignore_notifications_ = true;
- extension_service_->SetIsIncognitoEnabled(extension, enable_str == "true");
+ extension_service_->SetIsIncognitoEnabled(extension->id(),
+ enable_str == "true");
ignore_notifications_ = false;
}
-void ExtensionsDOMHandler::HandleAllowFileAccessMessage(const ListValue* args) {
- CHECK(args->GetSize() == 2);
+void ExtensionSettingsHandler::HandleAllowFileAccessMessage(
+ const ListValue* args) {
+ CHECK_EQ(2U, args->GetSize());
std::string extension_id, allow_str;
CHECK(args->GetString(0, &extension_id));
CHECK(args->GetString(1, &allow_str));
@@ -526,11 +426,18 @@ void ExtensionsDOMHandler::HandleAllowFileAccessMessage(const ListValue* args) {
extension_service_->GetExtensionById(extension_id, true);
DCHECK(extension);
+ if (!Extension::UserMayDisable(extension->location())) {
+ LOG(ERROR) << "Attempt to change allow file access of an extension that is "
+ << "non-usermanagable was made. Extension id : "
+ << extension->id();
+ return;
+ }
+
extension_service_->SetAllowFileAccess(extension, allow_str == "true");
}
-void ExtensionsDOMHandler::HandleUninstallMessage(const ListValue* args) {
- std::string extension_id = WideToASCII(ExtractStringValue(args));
+void ExtensionSettingsHandler::HandleUninstallMessage(const ListValue* args) {
+ std::string extension_id = UTF16ToUTF8(ExtractStringValue(args));
CHECK(!extension_id.empty());
const Extension* extension =
extension_service_->GetExtensionById(extension_id, true);
@@ -539,6 +446,12 @@ void ExtensionsDOMHandler::HandleUninstallMessage(const ListValue* args) {
if (!extension)
return;
+ if (!Extension::UserMayDisable(extension->location())) {
+ LOG(ERROR) << "Attempt to uninstall an extension that is non-usermanagable "
+ << "was made. Extension id : " << extension->id();
+ return;
+ }
+
if (!extension_id_prompting_.empty())
return; // Only one prompt at a time.
@@ -547,7 +460,7 @@ void ExtensionsDOMHandler::HandleUninstallMessage(const ListValue* args) {
GetExtensionUninstallDialog()->ConfirmUninstall(this, extension);
}
-void ExtensionsDOMHandler::ExtensionDialogAccepted() {
+void ExtensionSettingsHandler::ExtensionDialogAccepted() {
DCHECK(!extension_id_prompting_.empty());
bool was_terminated = false;
@@ -565,7 +478,8 @@ void ExtensionsDOMHandler::ExtensionDialogAccepted() {
return;
extension_service_->UninstallExtension(extension_id_prompting_,
- false /* external_uninstall */, NULL);
+ false, // External uninstall.
+ NULL); // Error.
extension_id_prompting_ = "";
// There will be no EXTENSION_UNLOADED notification for terminated
@@ -574,92 +488,47 @@ void ExtensionsDOMHandler::ExtensionDialogAccepted() {
HandleRequestExtensionsData(NULL);
}
-void ExtensionsDOMHandler::ExtensionDialogCanceled() {
+void ExtensionSettingsHandler::ExtensionDialogCanceled() {
extension_id_prompting_ = "";
}
-void ExtensionsDOMHandler::HandleOptionsMessage(const ListValue* args) {
+void ExtensionSettingsHandler::HandleOptionsMessage(const ListValue* args) {
const Extension* extension = GetExtension(args);
if (!extension || extension->options_url().is_empty())
return;
- web_ui_->GetProfile()->GetExtensionProcessManager()->OpenOptionsPage(
+ Profile::FromWebUI(web_ui_)->GetExtensionProcessManager()->OpenOptionsPage(
extension, NULL);
}
-void ExtensionsDOMHandler::HandleShowButtonMessage(const ListValue* args) {
+void ExtensionSettingsHandler::HandleShowButtonMessage(const ListValue* args) {
const Extension* extension = GetExtension(args);
extension_service_->SetBrowserActionVisibility(extension, true);
}
-void ExtensionsDOMHandler::HandleLoadMessage(const ListValue* args) {
+void ExtensionSettingsHandler::HandleLoadMessage(const ListValue* args) {
FilePath::StringType string_path;
- CHECK(args->GetSize() == 1) << args->GetSize();
+ CHECK_EQ(1U, args->GetSize()) << args->GetSize();
CHECK(args->GetString(0, &string_path));
extension_service_->LoadExtension(FilePath(string_path));
}
-void ExtensionsDOMHandler::ShowAlert(const std::string& message) {
+void ExtensionSettingsHandler::ShowAlert(const std::string& message) {
ListValue arguments;
arguments.Append(Value::CreateStringValue(message));
- web_ui_->CallJavascriptFunction(L"alert", arguments);
-}
-
-void ExtensionsDOMHandler::HandlePackMessage(const ListValue* args) {
- std::string extension_path;
- std::string private_key_path;
- CHECK(args->GetSize() == 2);
- CHECK(args->GetString(0, &extension_path));
- CHECK(args->GetString(1, &private_key_path));
-
- FilePath root_directory =
- FilePath::FromWStringHack(UTF8ToWide(extension_path));
- FilePath key_file = FilePath::FromWStringHack(UTF8ToWide(private_key_path));
-
- if (root_directory.empty()) {
- if (extension_path.empty()) {
- ShowAlert(l10n_util::GetStringUTF8(
- IDS_EXTENSION_PACK_DIALOG_ERROR_ROOT_REQUIRED));
- } else {
- ShowAlert(l10n_util::GetStringUTF8(
- IDS_EXTENSION_PACK_DIALOG_ERROR_ROOT_INVALID));
- }
-
- return;
- }
-
- if (!private_key_path.empty() && key_file.empty()) {
- ShowAlert(l10n_util::GetStringUTF8(
- IDS_EXTENSION_PACK_DIALOG_ERROR_KEY_INVALID));
- return;
- }
-
- pack_job_ = new PackExtensionJob(this, root_directory, key_file);
- pack_job_->Start();
+ web_ui_->CallJavascriptFunction("alert", arguments);
}
-void ExtensionsDOMHandler::OnPackSuccess(const FilePath& crx_file,
- const FilePath& pem_file) {
- ShowAlert(UTF16ToUTF8(PackExtensionJob::StandardSuccessMessage(crx_file,
- pem_file)));
-
- ListValue results;
- web_ui_->CallJavascriptFunction(L"hidePackDialog", results);
-}
-
-void ExtensionsDOMHandler::OnPackFailure(const std::string& error) {
- ShowAlert(error);
-}
-
-void ExtensionsDOMHandler::HandleAutoUpdateMessage(const ListValue* args) {
+void ExtensionSettingsHandler::HandleAutoUpdateMessage(const ListValue* args) {
ExtensionUpdater* updater = extension_service_->updater();
if (updater)
updater->CheckNow();
}
-void ExtensionsDOMHandler::HandleSelectFilePathMessage(const ListValue* args) {
+void ExtensionSettingsHandler::HandleSelectFilePathMessage(
+ const ListValue* args) {
std::string select_type;
std::string operation;
- CHECK(args->GetSize() == 2);
+ CHECK_EQ(2U, args->GetSize());
CHECK(args->GetString(0, &select_type));
CHECK(args->GetString(1, &operation));
@@ -697,22 +566,101 @@ void ExtensionsDOMHandler::HandleSelectFilePathMessage(const ListValue* args) {
}
-void ExtensionsDOMHandler::FileSelected(const FilePath& path, int index,
- void* params) {
+void ExtensionSettingsHandler::FileSelected(const FilePath& path, int index,
+ void* params) {
// Add the extensions to the results structure.
ListValue results;
results.Append(Value::CreateStringValue(path.value()));
- web_ui_->CallJavascriptFunction(L"window.handleFilePathSelected", results);
+ web_ui_->CallJavascriptFunction("window.handleFilePathSelected", results);
}
-void ExtensionsDOMHandler::MultiFilesSelected(
+void ExtensionSettingsHandler::MultiFilesSelected(
const std::vector<FilePath>& files, void* params) {
NOTREACHED();
}
-void ExtensionsDOMHandler::Observe(int type,
- const NotificationSource& source,
- const NotificationDetails& details) {
+void ExtensionSettingsHandler::GetLocalizedValues(
+ DictionaryValue* localized_strings) {
+ DCHECK(localized_strings);
+
+ RegisterTitle(localized_strings, "extensionSettings",
+ IDS_OPTIONS_GENERAL_TAB_LABEL);
+
+ localized_strings->SetString("extensionSettingsTitle",
+ l10n_util::GetStringUTF16(IDS_MANAGE_EXTENSIONS_SETTING_WINDOWS_TITLE));
+ localized_strings->SetString("extensionSettingsVisitWebsite",
+ l10n_util::GetStringUTF16(IDS_EXTENSIONS_VISIT_WEBSITE));
+
+ localized_strings->SetString("extensionSettingsDeveloperMode",
+ l10n_util::GetStringUTF16(IDS_EXTENSIONS_DEVELOPER_MODE_LINK));
+ localized_strings->SetString("extensionSettingsNoExtensions",
+ l10n_util::GetStringUTF16(IDS_EXTENSIONS_NONE_INSTALLED));
+ localized_strings->SetString("extensionSettingsSuggestGallery",
+ l10n_util::GetStringFUTF16(IDS_EXTENSIONS_NONE_INSTALLED_SUGGEST_GALLERY,
+ ASCIIToUTF16("<a href='") +
+ ASCIIToUTF16(google_util::AppendGoogleLocaleParam(
+ GURL(extension_urls::GetWebstoreLaunchURL())).spec()) +
+ ASCIIToUTF16("'>"),
+ ASCIIToUTF16("</a>")));
+ localized_strings->SetString("extensionSettingsGetMoreExtensions",
+ ASCIIToUTF16("<a href='") +
+ ASCIIToUTF16(google_util::AppendGoogleLocaleParam(
+ GURL(extension_urls::GetWebstoreLaunchURL())).spec()) +
+ ASCIIToUTF16("'>") +
+ l10n_util::GetStringUTF16(IDS_GET_MORE_EXTENSIONS) +
+ ASCIIToUTF16("</a>"));
+ localized_strings->SetString("extensionSettingsExtensionId",
+ l10n_util::GetStringUTF16(IDS_EXTENSIONS_ID));
+ localized_strings->SetString("extensionSettingsExtensionPath",
+ l10n_util::GetStringUTF16(IDS_EXTENSIONS_PATH));
+ localized_strings->SetString("extensionSettingsInspectViews",
+ l10n_util::GetStringUTF16(IDS_EXTENSIONS_INSPECT_VIEWS));
+ localized_strings->SetString("extensionSettingsEnable",
+ l10n_util::GetStringUTF16(IDS_EXTENSIONS_ENABLE));
+ localized_strings->SetString("extensionSettingsEnabled",
+ l10n_util::GetStringUTF16(IDS_EXTENSIONS_ENABLED));
+ localized_strings->SetString("extensionSettingsRemove",
+ l10n_util::GetStringUTF16(IDS_EXTENSIONS_REMOVE));
+ localized_strings->SetString("extensionSettingsEnableIncognito",
+ l10n_util::GetStringUTF16(IDS_EXTENSIONS_ENABLE_INCOGNITO));
+ localized_strings->SetString("extensionSettingsAllowFileAccess",
+ l10n_util::GetStringUTF16(IDS_EXTENSIONS_ALLOW_FILE_ACCESS));
+ localized_strings->SetString("extensionSettingsIncognitoWarning",
+ l10n_util::GetStringFUTF16(IDS_EXTENSIONS_INCOGNITO_WARNING,
+ l10n_util::GetStringUTF16(IDS_PRODUCT_NAME)));
+ localized_strings->SetString("extensionSettingsReload",
+ l10n_util::GetStringUTF16(IDS_EXTENSIONS_RELOAD));
+ localized_strings->SetString("extensionSettingsOptions",
+ l10n_util::GetStringUTF16(IDS_EXTENSIONS_OPTIONS));
+ localized_strings->SetString("extensionSettingsPolicyControlled",
+ l10n_util::GetStringUTF16(IDS_EXTENSIONS_POLICY_CONTROLLED));
+ localized_strings->SetString("extensionSettingsShowButton",
+ l10n_util::GetStringUTF16(IDS_EXTENSIONS_SHOW_BUTTON));
+ localized_strings->SetString("extensionSettingsLoadUnpackedButton",
+ l10n_util::GetStringUTF16(IDS_EXTENSIONS_LOAD_UNPACKED_BUTTON));
+ localized_strings->SetString("extensionSettingsPackButton",
+ l10n_util::GetStringUTF16(IDS_EXTENSIONS_PACK_BUTTON));
+ localized_strings->SetString("extensionSettingsUpdateButton",
+ l10n_util::GetStringUTF16(IDS_EXTENSIONS_UPDATE_BUTTON));
+}
+
+void ExtensionSettingsHandler::Initialize() {
+}
+
+WebUIMessageHandler* ExtensionSettingsHandler::Attach(WebUI* web_ui) {
+ // Call through to superclass.
+ WebUIMessageHandler* handler = OptionsPageUIHandler::Attach(web_ui);
+
+ extension_service_ = Profile::FromWebUI(web_ui_)
+ ->GetOriginalProfile()->GetExtensionService();
+
+ // Return result from the superclass.
+ return handler;
+}
+
+void ExtensionSettingsHandler::Observe(int type,
+ const NotificationSource& source,
+ const NotificationDetails& details) {
switch (type) {
// We listen for notifications that will result in the page being
// repopulated with data twice for the same event in certain cases.
@@ -728,22 +676,22 @@ void ExtensionsDOMHandler::Observe(int type,
//
// Doing it this way gets everything but causes the page to be rendered
// more than we need. It doesn't seem to result in any noticeable flicker.
- case chrome::RENDER_VIEW_HOST_DELETED:
- deleting_rvh_ = Details<RenderViewHost>(details).ptr();
+ case content::NOTIFICATION_RENDER_VIEW_HOST_DELETED:
+ deleting_rvh_ = Source<RenderViewHost>(source).ptr();
MaybeUpdateAfterNotification();
break;
- case chrome::BACKGROUND_CONTENTS_DELETED:
+ case chrome::NOTIFICATION_BACKGROUND_CONTENTS_DELETED:
deleting_rvh_ = Details<BackgroundContents>(details)->render_view_host();
MaybeUpdateAfterNotification();
break;
- case chrome::EXTENSION_LOADED:
- case chrome::EXTENSION_PROCESS_CREATED:
- case chrome::EXTENSION_UNLOADED:
- case chrome::EXTENSION_UPDATE_DISABLED:
- case chrome::RENDER_VIEW_HOST_CREATED:
- case chrome::NAV_ENTRY_COMMITTED:
- case chrome::BACKGROUND_CONTENTS_NAVIGATED:
- case chrome::EXTENSION_BROWSER_ACTION_VISIBILITY_CHANGED:
+ case chrome::NOTIFICATION_EXTENSION_LOADED:
+ case chrome::NOTIFICATION_EXTENSION_PROCESS_CREATED:
+ case chrome::NOTIFICATION_EXTENSION_UNLOADED:
+ case chrome::NOTIFICATION_EXTENSION_UPDATE_DISABLED:
+ case content::NOTIFICATION_RENDER_VIEW_HOST_CREATED:
+ case content::NOTIFICATION_NAV_ENTRY_COMMITTED:
+ case chrome::NOTIFICATION_BACKGROUND_CONTENTS_NAVIGATED:
+ case chrome::NOTIFICATION_EXTENSION_BROWSER_ACTION_VISIBILITY_CHANGED:
MaybeUpdateAfterNotification();
break;
default:
@@ -751,20 +699,20 @@ void ExtensionsDOMHandler::Observe(int type,
}
}
-const Extension* ExtensionsDOMHandler::GetExtension(const ListValue* args) {
- std::string extension_id = WideToASCII(ExtractStringValue(args));
+const Extension* ExtensionSettingsHandler::GetExtension(const ListValue* args) {
+ std::string extension_id = UTF16ToUTF8(ExtractStringValue(args));
CHECK(!extension_id.empty());
return extension_service_->GetExtensionById(extension_id, true);
}
-void ExtensionsDOMHandler::MaybeUpdateAfterNotification() {
+void ExtensionSettingsHandler::MaybeUpdateAfterNotification() {
if (!ignore_notifications_ && web_ui_->tab_contents())
HandleRequestExtensionsData(NULL);
deleting_rvh_ = NULL;
}
// Static
-DictionaryValue* ExtensionsDOMHandler::CreateExtensionDetailValue(
+DictionaryValue* ExtensionSettingsHandler::CreateExtensionDetailValue(
ExtensionService* service, const Extension* extension,
const std::vector<ExtensionPage>& pages, bool enabled, bool terminated) {
DictionaryValue* extension_data = new DictionaryValue();
@@ -772,11 +720,16 @@ DictionaryValue* ExtensionsDOMHandler::CreateExtensionDetailValue(
extension_data->SetString("id", extension->id());
extension_data->SetString("name", extension->name());
extension_data->SetString("description", extension->description());
+ extension_data->SetString("path", extension->path().value());
extension_data->SetString("version", extension->version()->GetString());
+ extension_data->SetBoolean("isUnpacked",
+ extension->location() == Extension::LOAD);
+ extension_data->SetBoolean("mayDisable",
+ Extension::UserMayDisable(extension->location()));
extension_data->SetBoolean("enabled", enabled);
extension_data->SetBoolean("terminated", terminated);
extension_data->SetBoolean("enabledIncognito",
- service ? service->IsIncognitoEnabled(extension) : false);
+ service ? service->IsIncognitoEnabled(extension->id()) : false);
extension_data->SetBoolean("wantsFileAccess", extension->wants_file_access());
extension_data->SetBoolean("allowFileAccess",
service ? service->AllowFileAccess(extension) : false);
@@ -791,7 +744,7 @@ DictionaryValue* ExtensionsDOMHandler::CreateExtensionDetailValue(
else
extension_data->SetInteger("order", 2);
- if (!extension->options_url().is_empty())
+ if (!extension->options_url().is_empty() && enabled)
extension_data->SetString("options_url", extension->options_url().spec());
if (service && !service->GetBrowserActionVisibility(extension))
@@ -822,7 +775,7 @@ DictionaryValue* ExtensionsDOMHandler::CreateExtensionDetailValue(
return extension_data;
}
-std::vector<ExtensionPage> ExtensionsDOMHandler::GetActivePagesForExtension(
+std::vector<ExtensionPage> ExtensionSettingsHandler::GetActivePagesForExtension(
const Extension* extension) {
std::vector<ExtensionPage> result;
@@ -847,7 +800,7 @@ std::vector<ExtensionPage> ExtensionsDOMHandler::GetActivePagesForExtension(
return result;
}
-void ExtensionsDOMHandler::GetActivePagesForExtensionProcess(
+void ExtensionSettingsHandler::GetActivePagesForExtensionProcess(
RenderProcessHost* process,
const Extension* extension,
std::vector<ExtensionPage> *result) {
@@ -875,49 +828,8 @@ void ExtensionsDOMHandler::GetActivePagesForExtensionProcess(
continue;
}
- result->push_back(ExtensionPage(url, process->id(), host->routing_id(),
- process->profile()->IsOffTheRecord()));
+ result->push_back(
+ ExtensionPage(url, process->id(), host->routing_id(),
+ process->browser_context()->IsOffTheRecord()));
}
}
-
-ExtensionsDOMHandler::~ExtensionsDOMHandler() {
- // There may be pending file dialogs, we need to tell them that we've gone
- // away so they don't try and call back to us.
- if (load_extension_dialog_.get())
- load_extension_dialog_->ListenerDestroyed();
-
- if (pack_job_.get())
- pack_job_->ClearClient();
-
- if (icon_loader_.get())
- icon_loader_->Cancel();
-}
-
-// ExtensionsDOMHandler, public: -----------------------------------------------
-
-ExtensionsUI::ExtensionsUI(TabContents* contents) : ChromeWebUI(contents) {
- ExtensionService *exstension_service =
- GetProfile()->GetOriginalProfile()->GetExtensionService();
-
- ExtensionsDOMHandler* handler = new ExtensionsDOMHandler(exstension_service);
- AddMessageHandler(handler);
- handler->Attach(this);
-
- ExtensionsUIHTMLSource* html_source = new ExtensionsUIHTMLSource();
-
- // Set up the chrome://extensions/ source.
- contents->profile()->GetChromeURLDataManager()->AddDataSource(html_source);
-}
-
-// static
-RefCountedMemory* ExtensionsUI::GetFaviconResourceBytes() {
- return ResourceBundle::GetSharedInstance().
- LoadDataResourceBytes(IDR_PLUGIN);
-}
-
-// static
-void ExtensionsUI::RegisterUserPrefs(PrefService* prefs) {
- prefs->RegisterBooleanPref(prefs::kExtensionsUIDeveloperMode,
- false,
- PrefService::SYNCABLE_PREF);
-}
diff --git a/chrome/browser/ui/webui/options/extension_settings_handler.h b/chrome/browser/ui/webui/options/extension_settings_handler.h
index 5ec4a14..2b5d6c0 100644
--- a/chrome/browser/ui/webui/options/extension_settings_handler.h
+++ b/chrome/browser/ui/webui/options/extension_settings_handler.h
@@ -9,11 +9,10 @@
#include <string>
#include <vector>
-#include "base/memory/scoped_ptr.h"
+#include "chrome/browser/extensions/extension_install_ui.h"
#include "chrome/browser/extensions/extension_uninstall_dialog.h"
-#include "chrome/browser/extensions/pack_extension_job.h"
#include "chrome/browser/ui/shell_dialogs.h"
-#include "chrome/browser/ui/webui/chrome_url_data_manager.h"
+#include "chrome/browser/ui/webui/options/options_ui.h"
#include "chrome/browser/ui/webui/chrome_web_ui.h"
#include "chrome/common/extensions/extension_resource.h"
#include "content/common/notification_observer.h"
@@ -47,31 +46,11 @@ struct ExtensionPage {
bool incognito;
};
-class ExtensionsUIHTMLSource : public ChromeURLDataManager::DataSource {
+// Extension Settings UI handler.
+class ExtensionSettingsHandler : public OptionsPageUIHandler,
+ public SelectFileDialog::Listener,
+ public ExtensionUninstallDialog::Delegate {
public:
- ExtensionsUIHTMLSource();
-
- // Called when the network layer has requested a resource underneath
- // the path we registered.
- virtual void StartDataRequest(const std::string& path,
- bool is_incognito,
- int request_id);
- virtual std::string GetMimeType(const std::string&) const;
-
- private:
- ~ExtensionsUIHTMLSource() {}
-
- DISALLOW_COPY_AND_ASSIGN(ExtensionsUIHTMLSource);
-};
-
-// The handler for JavaScript messages related to the "extensions" view.
-class ExtensionsDOMHandler : public WebUIMessageHandler,
- public NotificationObserver,
- public PackExtensionJob::Client,
- public SelectFileDialog::Listener,
- public ExtensionUninstallDialog::Delegate {
- public:
-
// Helper class that loads the icons for the extensions in the management UI.
// We do this with native code instead of just using chrome-extension:// URLs
// for two reasons:
@@ -82,7 +61,7 @@ class ExtensionsDOMHandler : public WebUIMessageHandler,
// look disabled.
class IconLoader : public base::RefCountedThreadSafe<IconLoader> {
public:
- explicit IconLoader(ExtensionsDOMHandler* handler);
+ explicit IconLoader(ExtensionSettingsHandler* handler);
// Load |icons|. Will call handler->OnIconsLoaded when complete. IconLoader
// takes ownership of both arguments.
@@ -103,14 +82,11 @@ class ExtensionsDOMHandler : public WebUIMessageHandler,
void ReportResultOnUIThread(base::DictionaryValue* json);
// The handler we will report back to.
- ExtensionsDOMHandler* handler_;
+ ExtensionSettingsHandler* handler_;
};
- explicit ExtensionsDOMHandler(ExtensionService* extension_service);
- virtual ~ExtensionsDOMHandler();
-
- // WebUIMessageHandler implementation.
- virtual void RegisterMessages();
+ ExtensionSettingsHandler();
+ virtual ~ExtensionSettingsHandler();
// Extension Detail JSON Struct for page. (static for ease of testing).
// Note: service can be NULL in unit tests.
@@ -126,17 +102,6 @@ class ExtensionsDOMHandler : public WebUIMessageHandler,
const UserScript& script,
const FilePath& extension_path);
- // ExtensionPackJob::Client
- virtual void OnPackSuccess(const FilePath& crx_file,
- const FilePath& key_file);
-
- virtual void OnPackFailure(const std::string& error);
-
- // ExtensionUninstallDialog::Delegate:
- virtual void ExtensionDialogAccepted();
- virtual void ExtensionDialogCanceled();
-
- private:
// Callback for "requestExtensionsData" message.
void HandleRequestExtensionsData(const base::ListValue* args);
@@ -190,16 +155,31 @@ class ExtensionsDOMHandler : public WebUIMessageHandler,
// SelectFileDialog::Listener
virtual void FileSelected(const FilePath& path,
- int index, void* params);
+ int index, void* params) OVERRIDE;
virtual void MultiFilesSelected(
- const std::vector<FilePath>& files, void* params);
- virtual void FileSelectionCanceled(void* params) {}
+ const std::vector<FilePath>& files, void* params) OVERRIDE;
+ virtual void FileSelectionCanceled(void* params) OVERRIDE {}
- // NotificationObserver
+ // WebUIMessageHandler implementation.
+ virtual void RegisterMessages() OVERRIDE;
+ virtual WebUIMessageHandler* Attach(WebUI* web_ui) OVERRIDE;
+
+ // OptionsUIHandler implementation.
+ virtual void GetLocalizedValues(
+ base::DictionaryValue* localized_strings) OVERRIDE;
+ virtual void Initialize() OVERRIDE;
+
+ // NotificationObserver implementation.
virtual void Observe(int type,
const NotificationSource& source,
- const NotificationDetails& details);
+ const NotificationDetails& details) OVERRIDE;
+
+ // ExtensionUninstallDialog::Delegate implementation, used for receiving
+ // notification about uninstall confirmation dialog selections.
+ virtual void ExtensionDialogAccepted() OVERRIDE;
+ virtual void ExtensionDialogCanceled() OVERRIDE;
+ private:
// Helper that lists the current active html pages for an extension.
std::vector<ExtensionPage> GetActivePagesForExtension(
const Extension* extension);
@@ -227,14 +207,11 @@ class ExtensionsDOMHandler : public WebUIMessageHandler,
ExtensionUninstallDialog* GetExtensionUninstallDialog();
// Our model. Outlives us since it's owned by our containing profile.
- ExtensionService* const extension_service_;
+ ExtensionService* extension_service_;
// Used to pick the directory when loading an extension.
scoped_refptr<SelectFileDialog> load_extension_dialog_;
- // Used to package the extension.
- scoped_refptr<PackExtensionJob> pack_job_;
-
// Used to load icons asynchronously on the file thread.
scoped_refptr<IconLoader> icon_loader_;
@@ -244,10 +221,6 @@ class ExtensionsDOMHandler : public WebUIMessageHandler,
// The id of the extension we are prompting the user about.
std::string extension_id_prompting_;
- // We monitor changes to the extension system so that we can reload when
- // necessary.
- NotificationRegistrar registrar_;
-
// If true, we will ignore notifications in ::Observe(). This is needed
// to prevent reloading the page when we were the cause of the
// notification.
@@ -260,19 +233,7 @@ class ExtensionsDOMHandler : public WebUIMessageHandler,
// it from the active views.
RenderViewHost* deleting_rvh_;
- DISALLOW_COPY_AND_ASSIGN(ExtensionsDOMHandler);
-};
-
-class ExtensionsUI : public ChromeWebUI {
- public:
- explicit ExtensionsUI(TabContents* contents);
-
- static RefCountedMemory* GetFaviconResourceBytes();
-
- static void RegisterUserPrefs(PrefService* prefs);
-
- private:
- DISALLOW_COPY_AND_ASSIGN(ExtensionsUI);
+ DISALLOW_COPY_AND_ASSIGN(ExtensionSettingsHandler);
};
#endif // CHROME_BROWSER_UI_WEBUI_OPTIONS_EXTENSION_SETTINGS_HANDLER_H_
diff --git a/chrome/browser/ui/webui/options/options_ui.cc b/chrome/browser/ui/webui/options/options_ui.cc
index 98e7d8b..5eb1865 100644
--- a/chrome/browser/ui/webui/options/options_ui.cc
+++ b/chrome/browser/ui/webui/options/options_ui.cc
@@ -26,12 +26,14 @@
#include "chrome/browser/ui/webui/options/handler_options_handler.h"
#include "chrome/browser/ui/webui/options/cookies_view_handler.h"
#include "chrome/browser/ui/webui/options/core_options_handler.h"
+#include "chrome/browser/ui/webui/options/extension_settings_handler.h"
#include "chrome/browser/ui/webui/options/font_settings_handler.h"
#include "chrome/browser/ui/webui/options/import_data_handler.h"
#include "chrome/browser/ui/webui/options/intents_settings_handler.h"
#include "chrome/browser/ui/webui/options/language_options_handler.h"
#include "chrome/browser/ui/webui/options/manage_profile_handler.h"
#include "chrome/browser/ui/webui/options/options_sync_setup_handler.h"
+#include "chrome/browser/ui/webui/options/pack_extension_handler.h"
#include "chrome/browser/ui/webui/options/password_manager_handler.h"
#include "chrome/browser/ui/webui/options/personal_options_handler.h"
#include "chrome/browser/ui/webui/options/search_engine_manager_handler.h"
@@ -210,6 +212,7 @@ OptionsUI::OptionsUI(TabContents* contents)
AddOptionsPageUIHandler(localized_strings, new ClearBrowserDataHandler());
AddOptionsPageUIHandler(localized_strings, new ContentSettingsHandler());
AddOptionsPageUIHandler(localized_strings, new CookiesViewHandler());
+ AddOptionsPageUIHandler(localized_strings, new ExtensionSettingsHandler());
AddOptionsPageUIHandler(localized_strings, new FontSettingsHandler());
AddOptionsPageUIHandler(localized_strings, new IntentsSettingsHandler());
#if defined(OS_CHROMEOS)
@@ -219,6 +222,7 @@ OptionsUI::OptionsUI(TabContents* contents)
AddOptionsPageUIHandler(localized_strings, new LanguageOptionsHandler());
#endif
AddOptionsPageUIHandler(localized_strings, new ManageProfileHandler());
+ AddOptionsPageUIHandler(localized_strings, new PackExtensionHandler());
AddOptionsPageUIHandler(localized_strings, new PasswordManagerHandler());
AddOptionsPageUIHandler(localized_strings, new PersonalOptionsHandler());
AddOptionsPageUIHandler(localized_strings, new SearchEngineManagerHandler());
diff --git a/chrome/browser/ui/webui/options/options_ui_uitest.cc b/chrome/browser/ui/webui/options/options_ui_uitest.cc
index 0330062..a1de2ea 100644
--- a/chrome/browser/ui/webui/options/options_ui_uitest.cc
+++ b/chrome/browser/ui/webui/options/options_ui_uitest.cc
@@ -149,14 +149,15 @@ TEST_F(OptionsUITest, NavBarCheck) {
ASSERT_EQ(true, navbar_exist);
// Check section headers in navbar.
- // For ChromeOS, there should be 1 + 6:
- // search, basics, personal, systerm, internet, under the hood and users
- // For other platforms, there should 1 + 3:
- // search, basics, personal and under the hood.
+ // For ChromeOS, there should be 1 + 7:
+ // Search, Basics, Personal, System, Internet, Under the Hood,
+ // Users and Extensions.
+ // For other platforms, there should 1 + 4:
+ // Search, Basics, Personal, Under the Hood and Extensions.
#if defined(OS_CHROMEOS)
- const int kExpectedSections = 1 + 6;
+ const int kExpectedSections = 1 + 7;
#else
- const int kExpectedSections = 1 + 3;
+ const int kExpectedSections = 1 + 4;
#endif
int num_of_sections = 0;
ASSERT_TRUE(tab->ExecuteAndExtractInt(L"",
diff --git a/chrome/browser/ui/webui/options/pack_extension_handler.cc b/chrome/browser/ui/webui/options/pack_extension_handler.cc
new file mode 100644
index 0000000..40a656d6
--- /dev/null
+++ b/chrome/browser/ui/webui/options/pack_extension_handler.cc
@@ -0,0 +1,99 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/ui/webui/options/pack_extension_handler.h"
+
+#include "base/utf_string_conversions.h"
+#include "grit/generated_resources.h"
+#include "ui/base/l10n/l10n_util.h"
+
+PackExtensionHandler::PackExtensionHandler() {
+}
+
+PackExtensionHandler::~PackExtensionHandler() {
+ if (pack_job_.get())
+ pack_job_->ClearClient();
+}
+
+void PackExtensionHandler::Initialize() {
+}
+
+void PackExtensionHandler::GetLocalizedValues(
+ DictionaryValue* localized_strings) {
+ DCHECK(localized_strings);
+ RegisterTitle(localized_strings, "clearBrowserDataOverlay",
+ IDS_CLEAR_BROWSING_DATA_TITLE);
+
+ localized_strings->SetString("packExtensionOverlay",
+ l10n_util::GetStringUTF16(IDS_EXTENSION_PACK_DIALOG_TITLE));
+ localized_strings->SetString("packExtensionHeading",
+ l10n_util::GetStringUTF16(IDS_EXTENSION_PACK_DIALOG_HEADING));
+ localized_strings->SetString("packExtensionCommit",
+ l10n_util::GetStringUTF16(IDS_EXTENSION_PACK_BUTTON));
+ localized_strings->SetString("packExtensionRootDir",
+ l10n_util::GetStringUTF16(
+ IDS_EXTENSION_PACK_DIALOG_ROOT_DIRECTORY_LABEL));
+ localized_strings->SetString("packExtensionPrivateKey",
+ l10n_util::GetStringUTF16(IDS_EXTENSION_PACK_DIALOG_PRIVATE_KEY_LABEL));
+ localized_strings->SetString("packExtensionBrowseButton",
+ l10n_util::GetStringUTF16(IDS_EXTENSION_PACK_DIALOG_BROWSE));
+}
+
+void PackExtensionHandler::RegisterMessages() {
+ // Setup handlers specific to this panel.
+ web_ui_->RegisterMessageCallback("pack",
+ NewCallback(this, &PackExtensionHandler::HandlePackMessage));
+}
+
+void PackExtensionHandler::OnPackSuccess(const FilePath& crx_file,
+ const FilePath& pem_file) {
+ ListValue results;
+ web_ui_->CallJavascriptFunction("OptionsPage.closeOverlay", results);
+
+ ShowAlert(UTF16ToUTF8(PackExtensionJob::StandardSuccessMessage(crx_file,
+ pem_file)));
+}
+
+void PackExtensionHandler::OnPackFailure(const std::string& error) {
+ ShowAlert(error);
+}
+
+void PackExtensionHandler::HandlePackMessage(const ListValue* args) {
+ std::string extension_path;
+ std::string private_key_path;
+ CHECK_EQ(2U, args->GetSize());
+ CHECK(args->GetString(0, &extension_path));
+ CHECK(args->GetString(1, &private_key_path));
+
+ FilePath root_directory =
+ FilePath::FromWStringHack(UTF8ToWide(extension_path));
+ FilePath key_file = FilePath::FromWStringHack(UTF8ToWide(private_key_path));
+
+ if (root_directory.empty()) {
+ if (extension_path.empty()) {
+ ShowAlert(l10n_util::GetStringUTF8(
+ IDS_EXTENSION_PACK_DIALOG_ERROR_ROOT_REQUIRED));
+ } else {
+ ShowAlert(l10n_util::GetStringUTF8(
+ IDS_EXTENSION_PACK_DIALOG_ERROR_ROOT_INVALID));
+ }
+
+ return;
+ }
+
+ if (!private_key_path.empty() && key_file.empty()) {
+ ShowAlert(l10n_util::GetStringUTF8(
+ IDS_EXTENSION_PACK_DIALOG_ERROR_KEY_INVALID));
+ return;
+ }
+
+ pack_job_ = new PackExtensionJob(this, root_directory, key_file);
+ pack_job_->Start();
+}
+
+void PackExtensionHandler::ShowAlert(const std::string& message) {
+ ListValue arguments;
+ arguments.Append(Value::CreateStringValue(message));
+ web_ui_->CallJavascriptFunction("alert", arguments);
+}
diff --git a/chrome/browser/ui/webui/options/pack_extension_handler.h b/chrome/browser/ui/webui/options/pack_extension_handler.h
new file mode 100644
index 0000000..1ef2d67
--- /dev/null
+++ b/chrome/browser/ui/webui/options/pack_extension_handler.h
@@ -0,0 +1,49 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_BROWSER_UI_WEBUI_OPTIONS_PACK_EXTENSION_HANDLER_H_
+#define CHROME_BROWSER_UI_WEBUI_OPTIONS_PACK_EXTENSION_HANDLER_H_
+#pragma once
+
+#include <string>
+
+#include "chrome/browser/browsing_data_remover.h"
+#include "chrome/browser/extensions/pack_extension_job.h"
+#include "chrome/browser/plugin_data_remover_helper.h"
+#include "chrome/browser/ui/webui/options/options_ui.h"
+
+// Clear browser data handler page UI handler.
+class PackExtensionHandler : public OptionsPageUIHandler,
+ public PackExtensionJob::Client {
+ public:
+ PackExtensionHandler();
+ virtual ~PackExtensionHandler();
+
+ // OptionsPageUIHandler implementation.
+ virtual void Initialize() OVERRIDE;
+ virtual void GetLocalizedValues(DictionaryValue* localized_strings) OVERRIDE;
+
+ // WebUIMessageHandler implementation.
+ virtual void RegisterMessages() OVERRIDE;
+
+ // ExtensionPackJob::Client
+ virtual void OnPackSuccess(const FilePath& crx_file,
+ const FilePath& key_file) OVERRIDE;
+
+ virtual void OnPackFailure(const std::string& error) OVERRIDE;
+
+ private:
+ // Javascript callback to start packing an extension.
+ void HandlePackMessage(const ListValue* args);
+
+ // A function to ask the webpage to show an alert.
+ void ShowAlert(const std::string& message);
+
+ // Used to package the extension.
+ scoped_refptr<PackExtensionJob> pack_job_;
+
+ DISALLOW_COPY_AND_ASSIGN(PackExtensionHandler);
+};
+
+#endif // CHROME_BROWSER_UI_WEBUI_OPTIONS_PACK_EXTENSION_HANDLER_H_
diff --git a/chrome/chrome_browser.gypi b/chrome/chrome_browser.gypi
index 15c04cd..f090a78 100644
--- a/chrome/chrome_browser.gypi
+++ b/chrome/chrome_browser.gypi
@@ -3647,6 +3647,8 @@
'browser/ui/webui/options/cookies_view_handler.h',
'browser/ui/webui/options/core_options_handler.cc',
'browser/ui/webui/options/core_options_handler.h',
+ 'browser/ui/webui/options/extension_settings_handler.h',
+ 'browser/ui/webui/options/extension_settings_handler.cc',
'browser/ui/webui/options/font_settings_handler.cc',
'browser/ui/webui/options/font_settings_handler.h',
'browser/ui/webui/options/font_settings_utils.h',
@@ -3671,6 +3673,8 @@
'browser/ui/webui/options/options_ui.h',
'browser/ui/webui/options/password_manager_handler.cc',
'browser/ui/webui/options/password_manager_handler.h',
+ 'browser/ui/webui/options/pack_extension_handler.h',
+ 'browser/ui/webui/options/pack_extension_handler.cc',
'browser/ui/webui/options/personal_options_handler.cc',
'browser/ui/webui/options/personal_options_handler.h',
'browser/ui/webui/options/search_engine_manager_handler.cc',