diff options
18 files changed, 346 insertions, 371 deletions
diff --git a/chrome/browser/extensions/api/developer_private/developer_private_api.cc b/chrome/browser/extensions/api/developer_private/developer_private_api.cc index 67c2add..8807294 100644 --- a/chrome/browser/extensions/api/developer_private/developer_private_api.cc +++ b/chrome/browser/extensions/api/developer_private/developer_private_api.cc @@ -12,6 +12,7 @@ #include "base/strings/stringprintf.h" #include "base/strings/utf_string_conversions.h" #include "chrome/browser/devtools/devtools_window.h" +#include "chrome/browser/extensions/api/commands/command_service.h" #include "chrome/browser/extensions/api/developer_private/developer_private_mangle.h" #include "chrome/browser/extensions/api/developer_private/entry_picker.h" #include "chrome/browser/extensions/api/developer_private/extension_info_generator.h" @@ -19,6 +20,7 @@ #include "chrome/browser/extensions/api/extension_action/extension_action_api.h" #include "chrome/browser/extensions/api/file_handlers/app_file_handler_util.h" #include "chrome/browser/extensions/devtools_util.h" +#include "chrome/browser/extensions/extension_commands_global_registry.h" #include "chrome/browser/extensions/extension_service.h" #include "chrome/browser/extensions/extension_tab_util.h" #include "chrome/browser/extensions/extension_ui_util.h" @@ -235,6 +237,12 @@ void DeveloperPrivateEventRouter::RemoveExtensionId( extension_ids_.erase(extension_id); } +void DeveloperPrivateEventRouter::NotifyExtensionCommandUpdated( + const std::string& extension_id) { + BroadcastItemStateChanged(developer::EVENT_TYPE_PREFS_CHANGED, + extension_id); +} + void DeveloperPrivateEventRouter::OnExtensionLoaded( content::BrowserContext* browser_context, const Extension* extension) { @@ -1379,6 +1387,48 @@ ExtensionFunction::ResponseAction DeveloperPrivateShowPathFunction::Run() { return RespondNow(NoArguments()); } +DeveloperPrivateSetShortcutHandlingSuspendedFunction:: +~DeveloperPrivateSetShortcutHandlingSuspendedFunction() {} + +ExtensionFunction::ResponseAction +DeveloperPrivateSetShortcutHandlingSuspendedFunction::Run() { + scoped_ptr<developer::SetShortcutHandlingSuspended::Params> params( + developer::SetShortcutHandlingSuspended::Params::Create(*args_)); + EXTENSION_FUNCTION_VALIDATE(params); + ExtensionCommandsGlobalRegistry::Get(GetProfile())-> + SetShortcutHandlingSuspended(params->is_suspended); + return RespondNow(NoArguments()); +} + +DeveloperPrivateUpdateExtensionCommandFunction:: +~DeveloperPrivateUpdateExtensionCommandFunction() {} + +ExtensionFunction::ResponseAction +DeveloperPrivateUpdateExtensionCommandFunction::Run() { + scoped_ptr<developer::UpdateExtensionCommand::Params> params( + developer::UpdateExtensionCommand::Params::Create(*args_)); + EXTENSION_FUNCTION_VALIDATE(params); + const developer::ExtensionCommandUpdate& update = params->update; + + CommandService* command_service = CommandService::Get(GetProfile()); + + if (update.scope != developer::COMMAND_SCOPE_NONE) { + command_service->SetScope(update.extension_id, update.command_name, + update.scope == developer::COMMAND_SCOPE_GLOBAL); + } + + if (update.keybinding) { + command_service->UpdateKeybindingPrefs( + update.extension_id, update.command_name, *update.keybinding); + } + + DeveloperPrivateAPI::Get(browser_context())-> + developer_private_event_router()-> + NotifyExtensionCommandUpdated(update.extension_id); + return RespondNow(NoArguments()); +} + + } // namespace api } // namespace extensions diff --git a/chrome/browser/extensions/api/developer_private/developer_private_api.h b/chrome/browser/extensions/api/developer_private/developer_private_api.h index ad2227f..3127f0f 100644 --- a/chrome/browser/extensions/api/developer_private/developer_private_api.h +++ b/chrome/browser/extensions/api/developer_private/developer_private_api.h @@ -67,6 +67,11 @@ class DeveloperPrivateEventRouter : public ExtensionRegistryObserver, void AddExtensionId(const std::string& extension_id); void RemoveExtensionId(const std::string& extension_id); + // Notifies the event router that an extension's command has been updated. + // Since this presently only happens through this API, this doesn't need to + // be an observer method. If that changes, we should revisit it. + void NotifyExtensionCommandUpdated(const std::string& extension_id); + private: // ExtensionRegistryObserver: void OnExtensionLoaded(content::BrowserContext* browser_context, @@ -181,6 +186,10 @@ class DeveloperPrivateAPI : public BrowserContextKeyedAPI, void OnListenerAdded(const EventListenerInfo& details) override; void OnListenerRemoved(const EventListenerInfo& details) override; + DeveloperPrivateEventRouter* developer_private_event_router() { + return developer_private_event_router_.get(); + } + private: friend class BrowserContextKeyedAPIFactory<DeveloperPrivateAPI>; @@ -571,6 +580,28 @@ class DeveloperPrivateShowPathFunction : public DeveloperPrivateAPIFunction { ResponseAction Run() override; }; +class DeveloperPrivateSetShortcutHandlingSuspendedFunction + : public DeveloperPrivateAPIFunction { + public: + DECLARE_EXTENSION_FUNCTION("developerPrivate.setShortcutHandlingSuspended", + DEVELOPERPRIVATE_SETSHORTCUTHANDLINGSUSPENDED); + + protected: + ~DeveloperPrivateSetShortcutHandlingSuspendedFunction() override; + ResponseAction Run() override; +}; + +class DeveloperPrivateUpdateExtensionCommandFunction + : public DeveloperPrivateAPIFunction { + public: + DECLARE_EXTENSION_FUNCTION("developerPrivate.updateExtensionCommand", + DEVELOPERPRIVATE_UPDATEEXTENSIONCOMMAND); + + protected: + ~DeveloperPrivateUpdateExtensionCommandFunction() override; + ResponseAction Run() override; +}; + } // namespace api } // namespace extensions diff --git a/chrome/browser/extensions/api/developer_private/extension_info_generator.cc b/chrome/browser/extensions/api/developer_private/extension_info_generator.cc index 17048f5..97738c0 100644 --- a/chrome/browser/extensions/api/developer_private/extension_info_generator.cc +++ b/chrome/browser/extensions/api/developer_private/extension_info_generator.cc @@ -6,6 +6,7 @@ #include "base/base64.h" #include "base/strings/utf_string_conversions.h" +#include "chrome/browser/extensions/api/commands/command_service.h" #include "chrome/browser/extensions/api/developer_private/inspectable_views_finder.h" #include "chrome/browser/extensions/api/extension_action/extension_action_api.h" #include "chrome/browser/extensions/error_console/error_console.h" @@ -16,6 +17,7 @@ #include "chrome/browser/extensions/shared_module_service.h" #include "chrome/browser/profiles/profile.h" #include "chrome/browser/ui/webui/extensions/extension_icon_source.h" +#include "chrome/common/extensions/command.h" #include "chrome/common/extensions/manifest_handlers/app_launch_info.h" #include "chrome/grit/generated_resources.h" #include "content/public/browser/render_view_host.h" @@ -143,11 +145,66 @@ linked_ptr<developer::RuntimeError> ConstructRuntimeError( return result; } +// Constructs any commands for the extension with the given |id|, and adds them +// to the list of |commands|. +void ConstructCommands(CommandService* command_service, + const std::string& extension_id, + std::vector<linked_ptr<developer::Command>>* commands) { + auto construct_command = [](const Command& command, + bool active, + bool is_extension_action) { + developer::Command* command_value = new developer::Command(); + command_value->description = is_extension_action ? + l10n_util::GetStringUTF8(IDS_EXTENSION_COMMANDS_GENERIC_ACTIVATE) : + base::UTF16ToUTF8(command.description()); + command_value->keybinding = + base::UTF16ToUTF8(command.accelerator().GetShortcutText()); + command_value->name = command.command_name(); + command_value->is_active = active; + command_value->scope = command.global() ? developer::COMMAND_SCOPE_GLOBAL : + developer::COMMAND_SCOPE_CHROME; + command_value->is_extension_action = is_extension_action; + return command_value; + }; + bool active = false; + Command browser_action; + if (command_service->GetBrowserActionCommand(extension_id, + CommandService::ALL, + &browser_action, + &active)) { + commands->push_back( + make_linked_ptr(construct_command(browser_action, active, true))); + } + + Command page_action; + if (command_service->GetPageActionCommand(extension_id, + CommandService::ALL, + &page_action, + &active)) { + commands->push_back( + make_linked_ptr(construct_command(page_action, active, true))); + } + + CommandMap named_commands; + if (command_service->GetNamedCommands(extension_id, + CommandService::ALL, + CommandService::ANY_SCOPE, + &named_commands)) { + for (const auto& pair : named_commands) { + const Command& command = pair.second; + bool active = command.accelerator().key_code() != ui::VKEY_UNKNOWN; + commands->push_back( + make_linked_ptr(construct_command(command, active, false))); + } + } +} + } // namespace ExtensionInfoGenerator::ExtensionInfoGenerator( content::BrowserContext* browser_context) : browser_context_(browser_context), + command_service_(CommandService::Get(browser_context)), extension_system_(ExtensionSystem::Get(browser_context)), extension_prefs_(ExtensionPrefs::Get(browser_context)), extension_action_api_(ExtensionActionAPI::Get(browser_context)), @@ -259,6 +316,7 @@ void ExtensionInfoGenerator::CreateExtensionInfoHelper( Profile* profile = Profile::FromBrowserContext(browser_context_); + // ControlledInfo. bool is_policy_location = Manifest::IsPolicyLocation(extension.location()); if (is_policy_location || util::IsExtensionSupervised(&extension, profile)) { info->controlled_info.reset(new developer::ControlledInfo()); @@ -278,6 +336,12 @@ void ExtensionInfoGenerator::CreateExtensionInfoHelper( } } + bool is_enabled = state == developer::EXTENSION_STATE_ENABLED; + + // Commands. + if (is_enabled) + ConstructCommands(command_service_, extension.id(), &info->commands); + // Dependent extensions. if (extension.is_shared_module()) { scoped_ptr<ExtensionSet> dependent_extensions = @@ -436,7 +500,6 @@ void ExtensionInfoGenerator::CreateExtensionInfoHelper( info->version = extension.GetVersionForDisplay(); - bool is_enabled = state == developer::EXTENSION_STATE_ENABLED; if (state != developer::EXTENSION_STATE_TERMINATED) { info->views = InspectableViewsFinder(profile). GetViewsForExtension(extension, is_enabled); diff --git a/chrome/browser/extensions/api/developer_private/extension_info_generator.h b/chrome/browser/extensions/api/developer_private/extension_info_generator.h index 626e56a..51d8c91 100644 --- a/chrome/browser/extensions/api/developer_private/extension_info_generator.h +++ b/chrome/browser/extensions/api/developer_private/extension_info_generator.h @@ -19,6 +19,7 @@ class Image; } namespace extensions { +class CommandService; class ErrorConsole; class Extension; class ExtensionActionAPI; @@ -70,6 +71,7 @@ class ExtensionInfoGenerator { // Various systems, cached for convenience. content::BrowserContext* browser_context_; + CommandService* command_service_; ExtensionSystem* extension_system_; ExtensionPrefs* extension_prefs_; ExtensionActionAPI* extension_action_api_; diff --git a/chrome/browser/resources/extensions/extension_command_list.js b/chrome/browser/resources/extensions/extension_command_list.js index 0a184dc..aa0a3cc 100644 --- a/chrome/browser/resources/extensions/extension_command_list.js +++ b/chrome/browser/resources/extensions/extension_command_list.js @@ -15,14 +15,6 @@ var ExtensionCommand; cr.define('options', function() { 'use strict'; - /** - * Creates a new list of extension commands. - * @param {Object=} opt_propertyBag Optional properties. - * @constructor - * @extends {HTMLDivElement} - */ - var ExtensionCommandList = cr.ui.define('div'); - /** @const */ var keyComma = 188; /** @const */ var keyDel = 46; /** @const */ var keyDown = 40; @@ -184,6 +176,17 @@ cr.define('options', function() { (countShiftAsModifier && event.shiftKey); } + /** + * Creates a new list of extension commands. + * @param {HTMLDivElement} div + * @constructor + * @extends {HTMLDivElement} + */ + function ExtensionCommandList(div) { + div.__proto__ = ExtensionCommandList.prototype; + return div; + } + ExtensionCommandList.prototype = { __proto__: HTMLDivElement.prototype, @@ -212,20 +215,30 @@ cr.define('options', function() { */ capturingElement_: null, - decorate: function() { + /** + * Updates the extensions data for the overlay. + * @param {!Array<ExtensionInfo>} data The extension data. + */ + setData: function(data) { + /** @private {!Array<ExtensionInfo>} */ + this.data_ = data; + this.textContent = ''; // Iterate over the extension data and add each item to the list. - this.data_.commands.forEach(this.createNodeForExtension_.bind(this)); + this.data_.forEach(this.createNodeForExtension_.bind(this)); }, /** * Synthesizes and initializes an HTML element for the extension command * metadata given in |extension|. - * @param {Object} extension A dictionary of extension metadata. + * @param {ExtensionInfo} extension A dictionary of extension metadata. * @private */ createNodeForExtension_: function(extension) { + if (extension.commands.length == 0) + return; + var template = $('template-collection-extension-commands').querySelector( '.extension-command-list-extension-item-wrapper'); var node = template.cloneNode(true); @@ -237,22 +250,22 @@ cr.define('options', function() { // Iterate over the commands data within the extension and add each item // to the list. - extension.commands.forEach(this.createNodeForCommand_.bind(this)); + extension.commands.forEach( + this.createNodeForCommand_.bind(this, extension.id)); }, /** * Synthesizes and initializes an HTML element for the extension command * metadata given in |command|. - * @param {ExtensionCommand} command A dictionary of extension command - * metadata. + * @param {string} extensionId The associated extension's id. + * @param {Command} command A dictionary of extension command metadata. * @private */ - createNodeForCommand_: function(command) { + createNodeForCommand_: function(extensionId, command) { var template = $('template-collection-extension-commands').querySelector( '.extension-command-list-command-item-wrapper'); var node = template.cloneNode(true); - node.id = this.createElementId_( - 'command', command.extension_id, command.command_name); + node.id = this.createElementId_('command', extensionId, command.name); var description = node.querySelector('.command-description'); description.textContent = command.description; @@ -264,7 +277,7 @@ cr.define('options', function() { shortcutNode.addEventListener('blur', this.handleBlur_.bind(this)); shortcutNode.addEventListener('keydown', this.handleKeyDown_.bind(this)); shortcutNode.addEventListener('keyup', this.handleKeyUp_.bind(this)); - if (!command.active) { + if (!command.isActive) { shortcutNode.textContent = loadTimeData.getString('extensionCommandsInactive'); @@ -276,19 +289,19 @@ cr.define('options', function() { var commandClear = node.querySelector('.command-clear'); commandClear.id = this.createElementId_( - 'clear', command.extension_id, command.command_name); + 'clear', extensionId, command.name); commandClear.title = loadTimeData.getString('extensionCommandsDelete'); commandClear.addEventListener('click', this.handleClear_.bind(this)); var select = node.querySelector('.command-scope'); select.id = this.createElementId_( - 'setCommandScope', command.extension_id, command.command_name); + 'setCommandScope', extensionId, command.name); select.hidden = false; // Add the 'In Chrome' option. var option = document.createElement('option'); option.textContent = loadTimeData.getString('extensionCommandsRegular'); select.appendChild(option); - if (command.extension_action) { + if (command.isExtensionAction) { // Extension actions cannot be global, so we might as well disable the // combo box, to signify that. select.disabled = true; @@ -297,7 +310,7 @@ cr.define('options', function() { option = document.createElement('option'); option.textContent = loadTimeData.getString('extensionCommandsGlobal'); select.appendChild(option); - select.selectedIndex = command.global ? 1 : 0; + select.selectedIndex = command.isGlobal ? 1 : 0; select.addEventListener( 'change', this.handleSetCommandScope_.bind(this)); @@ -316,7 +329,7 @@ cr.define('options', function() { if (this.capturingElement_) return; // Already capturing. - chrome.send('setShortcutHandlingSuspended', [true]); + chrome.developerPrivate.setShortcutHandlingSuspended(true); var shortcutNode = event.target; this.oldValue_ = shortcutNode.textContent; @@ -341,7 +354,7 @@ cr.define('options', function() { if (!this.capturingElement_) return; // Not capturing. - chrome.send('setShortcutHandlingSuspended', [false]); + chrome.developerPrivate.setShortcutHandlingSuspended(false); var shortcutNode = this.capturingElement_; var commandShortcut = shortcutNode.parentElement; @@ -406,8 +419,11 @@ cr.define('options', function() { this.endCapture_(event); var parsed = this.parseElementId_('clear', event.target.parentElement.querySelector('.command-clear').id); - chrome.send('setExtensionCommandShortcut', - [parsed.extensionId, parsed.commandName, '']); + chrome.developerPrivate.updateExtensionCommand({ + extensionId: parsed.extensionId, + commandName: parsed.commandName, + keybinding: '' + }); event.preventDefault(); event.stopPropagation(); return; @@ -496,8 +512,10 @@ cr.define('options', function() { // Ending the capture must occur before calling // setExtensionCommandShortcut to ensure the shortcut is set. this.endCapture_(event); - chrome.send('setExtensionCommandShortcut', - [parsed.extensionId, parsed.commandName, keystroke]); + chrome.developerPrivate.updateExtensionCommand( + {extensionId: parsed.extensionId, + commandName: parsed.commandName, + keybinding: keystroke}); } }, @@ -508,8 +526,10 @@ cr.define('options', function() { */ handleClear_: function(event) { var parsed = this.parseElementId_('clear', event.target.id); - chrome.send('setExtensionCommandShortcut', - [parsed.extensionId, parsed.commandName, '']); + chrome.developerPrivate.updateExtensionCommand( + {extensionId: parsed.extensionId, + commandName: parsed.commandName, + keybinding: ''}); }, /** @@ -521,8 +541,13 @@ cr.define('options', function() { var parsed = this.parseElementId_('setCommandScope', event.target.id); var element = document.getElementById( 'setCommandScope-' + parsed.extensionId + '-' + parsed.commandName); - chrome.send('setCommandScope', - [parsed.extensionId, parsed.commandName, element.selectedIndex == 1]); + var scope = element.selectedIndex == 1 ? + chrome.developerPrivate.CommandScope.GLOBAL : + chrome.developerPrivate.CommandScope.CHROME; + chrome.developerPrivate.updateExtensionCommand( + {extensionId: parsed.extensionId, + commandName: parsed.commandName, + scope: scope}); }, /** diff --git a/chrome/browser/resources/extensions/extension_commands_overlay.js b/chrome/browser/resources/extensions/extension_commands_overlay.js index a96ef44..ab56eb4 100644 --- a/chrome/browser/resources/extensions/extension_commands_overlay.js +++ b/chrome/browser/resources/extensions/extension_commands_overlay.js @@ -31,12 +31,14 @@ cr.define('extensions', function() { cr.ui.overlay.globalInitialization(); overlay.addEventListener('cancelOverlay', this.handleDismiss_.bind(this)); + this.extensionCommandList_ = new ExtensionCommandList( + /**@type {HTMLDivElement} */($('extension-command-list'))); + $('extension-commands-dismiss').addEventListener('click', this.handleDismiss_.bind(this)); - // This will request the data to show on the page and will get a response - // back in returnExtensionsData. - chrome.send('extensionCommandsRequestExtensionsData'); + // The ExtensionList will update us with its data, so we don't need to + // handle that here. }, /** @@ -51,25 +53,28 @@ cr.define('extensions', function() { /** * Called by the dom_ui_ to re-populate the page with data representing * the current state of extension commands. - * @param {!{commands: Array<{name: string, id: string, commands: ?Array}>}} - * extensionsData + * @param {!Array<ExtensionInfo>} extensionsData */ - ExtensionCommandsOverlay.returnExtensionsData = function(extensionsData) { - ExtensionCommandList.prototype.data_ = extensionsData; - var extensionCommandList = $('extension-command-list'); - ExtensionCommandList.decorate(extensionCommandList); + ExtensionCommandsOverlay.updateExtensionsData = function(extensionsData) { + var overlay = ExtensionCommandsOverlay.getInstance(); + overlay.extensionCommandList_.setData(extensionsData); + + var hasAnyCommands = false; + for (var i = 0; i < extensionsData.length; ++i) { + if (extensionsData[i].commands.length > 0) { + hasAnyCommands = true; + break; + } + } // Make sure the config link is visible, since there are commands to show // and potentially configure. document.querySelector('.extension-commands-config').hidden = - extensionsData.commands.length == 0; + !hasAnyCommands; - $('no-commands').hidden = extensionsData.commands.length > 0; - var list = $('extension-command-list'); - if (extensionsData.commands.length == 0) - list.classList.add('empty-extension-commands-list'); - else - list.classList.remove('empty-extension-commands-list'); + $('no-commands').hidden = hasAnyCommands; + overlay.extensionCommandList_.classList.toggle( + 'empty-extension-commands-list', !hasAnyCommands); }; // Export diff --git a/chrome/browser/resources/extensions/extension_list.js b/chrome/browser/resources/extensions/extension_list.js index 7fa99909..c9f866b 100644 --- a/chrome/browser/resources/extensions/extension_list.js +++ b/chrome/browser/resources/extensions/extension_list.js @@ -147,6 +147,8 @@ ExtensionFocusRow.prototype = { cr.define('extensions', function() { 'use strict'; + var ExtensionCommandsOverlay = extensions.ExtensionCommandsOverlay; + /** * Compares two extensions for the order they should appear in the list. * @param {ExtensionInfo} a The first extension. @@ -294,6 +296,14 @@ cr.define('extensions', function() { eventData.event_type == EventType.UNINSTALLED) { this.delegate_.onExtensionCountChanged(); } + + if (eventData.event_type == EventType.INSTALLED || + eventData.event_type == EventType.UNINSTALLED || + eventData.event_type == EventType.PREFS_CHANGED) { + // We update the commands overlay whenever an extension is added or + // removed (other updates wouldn't affect command-ly things). + ExtensionCommandsOverlay.updateExtensionsData(this.extensions_); + } }.bind(this)); }, @@ -320,6 +330,11 @@ cr.define('extensions', function() { extensions.sort(compareExtensions); this.extensions_ = extensions; this.showExtensionNodes_(); + + // We keep the commands overlay's extension info in sync, so that we + // don't duplicate the same querying logic there. + ExtensionCommandsOverlay.updateExtensionsData(this.extensions_); + resolve(); // |resolve| is async so it's necessary to use |then| here in order to diff --git a/chrome/browser/ui/webui/extensions/command_handler.cc b/chrome/browser/ui/webui/extensions/command_handler.cc deleted file mode 100644 index 79f942a..0000000 --- a/chrome/browser/ui/webui/extensions/command_handler.cc +++ /dev/null @@ -1,200 +0,0 @@ -// Copyright (c) 2012 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/extensions/command_handler.h" - -#include "base/bind.h" -#include "base/values.h" -#include "chrome/browser/extensions/api/commands/command_service.h" -#include "chrome/browser/extensions/extension_commands_global_registry.h" -#include "chrome/browser/extensions/extension_keybinding_registry.h" -#include "chrome/browser/profiles/profile.h" -#include "chrome/grit/generated_resources.h" -#include "content/public/browser/web_ui.h" -#include "content/public/browser/web_ui_data_source.h" -#include "extensions/browser/extension_registry.h" -#include "extensions/browser/extension_system.h" -#include "extensions/common/extension_set.h" -#include "ui/base/l10n/l10n_util.h" - -namespace extensions { - -CommandHandler::CommandHandler(Profile* profile) - : profile_(profile), - extension_registry_observer_(this) { -} - -CommandHandler::~CommandHandler() { -} - -void CommandHandler::GetLocalizedValues(content::WebUIDataSource* source) { - source->AddString("extensionCommandsOverlay", - l10n_util::GetStringUTF16(IDS_EXTENSION_COMMANDS_DIALOG_TITLE)); - source->AddString("extensionCommandsEmpty", - l10n_util::GetStringUTF16(IDS_EXTENSION_COMMANDS_EMPTY)); - source->AddString("extensionCommandsInactive", - l10n_util::GetStringUTF16(IDS_EXTENSION_COMMANDS_INACTIVE)); - source->AddString("extensionCommandsStartTyping", - l10n_util::GetStringUTF16(IDS_EXTENSION_TYPE_SHORTCUT)); - source->AddString("extensionCommandsDelete", - l10n_util::GetStringUTF16(IDS_EXTENSION_DELETE_SHORTCUT)); - source->AddString("extensionCommandsGlobal", - l10n_util::GetStringUTF16(IDS_EXTENSION_COMMANDS_GLOBAL)); - source->AddString("extensionCommandsRegular", - l10n_util::GetStringUTF16(IDS_EXTENSION_COMMANDS_NOT_GLOBAL)); - source->AddString("ok", l10n_util::GetStringUTF16(IDS_OK)); -} - -void CommandHandler::RegisterMessages() { - extension_registry_observer_.Add(ExtensionRegistry::Get(profile_)); - - web_ui()->RegisterMessageCallback("extensionCommandsRequestExtensionsData", - base::Bind(&CommandHandler::HandleRequestExtensionsData, - base::Unretained(this))); - web_ui()->RegisterMessageCallback("setShortcutHandlingSuspended", - base::Bind(&CommandHandler::HandleSetShortcutHandlingSuspended, - base::Unretained(this))); - web_ui()->RegisterMessageCallback("setExtensionCommandShortcut", - base::Bind(&CommandHandler::HandleSetExtensionCommandShortcut, - base::Unretained(this))); - web_ui()->RegisterMessageCallback("setCommandScope", - base::Bind(&CommandHandler::HandleSetCommandScope, - base::Unretained(this))); -} - -void CommandHandler::OnExtensionLoaded(content::BrowserContext* browser_context, - const Extension* extension) { - UpdateCommandDataOnPage(); -} - -void CommandHandler::OnExtensionUnloaded( - content::BrowserContext* browser_context, - const Extension* extension, - UnloadedExtensionInfo::Reason reason) { - UpdateCommandDataOnPage(); -} - -void CommandHandler::UpdateCommandDataOnPage() { - base::DictionaryValue results; - GetAllCommands(&results); - web_ui()->CallJavascriptFunction( - "extensions.ExtensionCommandsOverlay.returnExtensionsData", results); -} - -void CommandHandler::HandleRequestExtensionsData(const base::ListValue* args) { - UpdateCommandDataOnPage(); -} - -void CommandHandler::HandleSetExtensionCommandShortcut( - const base::ListValue* args) { - std::string extension_id; - std::string command_name; - std::string keystroke; - if (!args->GetString(0, &extension_id) || - !args->GetString(1, &command_name) || - !args->GetString(2, &keystroke)) { - NOTREACHED(); - return; - } - - Profile* profile = Profile::FromWebUI(web_ui()); - CommandService* command_service = CommandService::Get(profile); - command_service->UpdateKeybindingPrefs(extension_id, command_name, keystroke); - - UpdateCommandDataOnPage(); -} - -void CommandHandler::HandleSetCommandScope( - const base::ListValue* args) { - std::string extension_id; - std::string command_name; - bool global; - if (!args->GetString(0, &extension_id) || - !args->GetString(1, &command_name) || - !args->GetBoolean(2, &global)) { - NOTREACHED(); - return; - } - - Profile* profile = Profile::FromWebUI(web_ui()); - CommandService* command_service = CommandService::Get(profile); - if (command_service->SetScope(extension_id, command_name, global)) - UpdateCommandDataOnPage(); -} - -void CommandHandler::HandleSetShortcutHandlingSuspended( - const base::ListValue* args) { - bool suspended; - if (args->GetBoolean(0, &suspended)) { - ExtensionCommandsGlobalRegistry::Get(Profile::FromWebUI(web_ui()))-> - SetShortcutHandlingSuspended(suspended); - } -} - -void CommandHandler::GetAllCommands(base::DictionaryValue* commands) { - base::ListValue* results = new base::ListValue; - - Profile* profile = Profile::FromWebUI(web_ui()); - CommandService* command_service = CommandService::Get(profile); - - const ExtensionSet& extensions = - ExtensionRegistry::Get(profile)->enabled_extensions(); - for (ExtensionSet::const_iterator extension = extensions.begin(); - extension != extensions.end(); - ++extension) { - scoped_ptr<base::DictionaryValue> extension_dict(new base::DictionaryValue); - extension_dict->SetString("name", (*extension)->name()); - extension_dict->SetString("id", (*extension)->id()); - - // Add the keybindings to a list structure. - scoped_ptr<base::ListValue> extensions_list(new base::ListValue()); - - bool active = false; - - Command browser_action; - if (command_service->GetBrowserActionCommand((*extension)->id(), - CommandService::ALL, - &browser_action, - &active)) { - extensions_list->Append( - browser_action.ToValue((extension->get()), active)); - } - - Command page_action; - if (command_service->GetPageActionCommand((*extension)->id(), - CommandService::ALL, - &page_action, - &active)) { - extensions_list->Append(page_action.ToValue((extension->get()), active)); - } - - CommandMap named_commands; - if (command_service->GetNamedCommands((*extension)->id(), - CommandService::ALL, - CommandService::ANY_SCOPE, - &named_commands)) { - for (CommandMap::const_iterator iter = named_commands.begin(); - iter != named_commands.end(); - ++iter) { - Command command = command_service->FindCommandByName( - (*extension)->id(), iter->second.command_name()); - ui::Accelerator shortcut_assigned = command.accelerator(); - - active = (shortcut_assigned.key_code() != ui::VKEY_UNKNOWN); - - extensions_list->Append( - iter->second.ToValue((extension->get()), active)); - } - } - - if (!extensions_list->empty()) { - extension_dict->Set("commands", extensions_list.release()); - results->Append(extension_dict.release()); - } - } - - commands->Set("commands", results); -} - -} // namespace extensions diff --git a/chrome/browser/ui/webui/extensions/command_handler.h b/chrome/browser/ui/webui/extensions/command_handler.h deleted file mode 100644 index 7bc62d7..0000000 --- a/chrome/browser/ui/webui/extensions/command_handler.h +++ /dev/null @@ -1,85 +0,0 @@ -// Copyright (c) 2012 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_EXTENSIONS_COMMAND_HANDLER_H_ -#define CHROME_BROWSER_UI_WEBUI_EXTENSIONS_COMMAND_HANDLER_H_ - -#include "base/compiler_specific.h" -#include "base/scoped_observer.h" -#include "content/public/browser/web_ui_message_handler.h" -#include "extensions/browser/extension_registry_observer.h" - -class Profile; - -namespace base { -class DictionaryValue; -class ListValue; -} - -namespace content { -class WebUIDataSource; -} - -namespace extensions { -class Command; -class CommandService; -class Extension; -class ExtensionRegistry; - -// The handler page for the Extension Commands UI overlay. -class CommandHandler : public content::WebUIMessageHandler, - public ExtensionRegistryObserver { - public: - explicit CommandHandler(Profile* profile); - ~CommandHandler() override; - - // Fetches the localized values for the page and deposits them into |source|. - void GetLocalizedValues(content::WebUIDataSource* source); - - // WebUIMessageHandler implementation. - void RegisterMessages() override; - - private: - // ExtensionRegistryObserver implementation. - void OnExtensionLoaded(content::BrowserContext* browser_context, - const Extension* extension) override; - void OnExtensionUnloaded(content::BrowserContext* browser_context, - const Extension* extension, - UnloadedExtensionInfo::Reason reason) override; - - // Update the list of extension commands in the config UI. - void UpdateCommandDataOnPage(); - - // Handles requests from javascript to fetch the extensions data, including - // the commands it contains. - // Replies back through: ExtensionCommandsOverlay.returnExtensionsData. - void HandleRequestExtensionsData(const base::ListValue* args); - - // Handles requests from javascript to set a particular keyboard shortcut - // for a given extension command. - void HandleSetExtensionCommandShortcut(const base::ListValue* args); - - // Handles requests from javascript to change the scope of a particular - // keyboard shortcut for a given extension command. - void HandleSetCommandScope(const base::ListValue* args); - - // Handles requests from javascript to temporarily disable general Chrome - // shortcut handling while the web page is capturing which shortcut to use. - void HandleSetShortcutHandlingSuspended(const base::ListValue* args); - - // Fetches all known commands, active and inactive and returns them through - // |commands|. - void GetAllCommands(base::DictionaryValue* commands); - - Profile* profile_; - - ScopedObserver<ExtensionRegistry, ExtensionRegistryObserver> - extension_registry_observer_; - - DISALLOW_COPY_AND_ASSIGN(CommandHandler); -}; - -} // namespace extensions - -#endif // CHROME_BROWSER_UI_WEBUI_EXTENSIONS_COMMAND_HANDLER_H_ diff --git a/chrome/browser/ui/webui/extensions/extension_settings_handler.cc b/chrome/browser/ui/webui/extensions/extension_settings_handler.cc index be76abb..f6bfc5d 100644 --- a/chrome/browser/ui/webui/extensions/extension_settings_handler.cc +++ b/chrome/browser/ui/webui/extensions/extension_settings_handler.cc @@ -238,6 +238,23 @@ void ExtensionSettingsHandler::GetLocalizedValues( source->AddString( "extensionErrorOverlayNoCodeToDisplay", l10n_util::GetStringUTF16(IDS_EXTENSIONS_ERROR_NO_CODE_TO_DISPLAY)); + + // Extension Commands Overlay: + source->AddString("extensionCommandsOverlay", + l10n_util::GetStringUTF16(IDS_EXTENSION_COMMANDS_DIALOG_TITLE)); + source->AddString("extensionCommandsEmpty", + l10n_util::GetStringUTF16(IDS_EXTENSION_COMMANDS_EMPTY)); + source->AddString("extensionCommandsInactive", + l10n_util::GetStringUTF16(IDS_EXTENSION_COMMANDS_INACTIVE)); + source->AddString("extensionCommandsStartTyping", + l10n_util::GetStringUTF16(IDS_EXTENSION_TYPE_SHORTCUT)); + source->AddString("extensionCommandsDelete", + l10n_util::GetStringUTF16(IDS_EXTENSION_DELETE_SHORTCUT)); + source->AddString("extensionCommandsGlobal", + l10n_util::GetStringUTF16(IDS_EXTENSION_COMMANDS_GLOBAL)); + source->AddString("extensionCommandsRegular", + l10n_util::GetStringUTF16(IDS_EXTENSION_COMMANDS_NOT_GLOBAL)); + source->AddString("ok", l10n_util::GetStringUTF16(IDS_OK)); } void ExtensionSettingsHandler::DidStartNavigationToPendingEntry( diff --git a/chrome/browser/ui/webui/extensions/extensions_ui.cc b/chrome/browser/ui/webui/extensions/extensions_ui.cc index 681fd3f..1c6acb2 100644 --- a/chrome/browser/ui/webui/extensions/extensions_ui.cc +++ b/chrome/browser/ui/webui/extensions/extensions_ui.cc @@ -5,7 +5,6 @@ #include "chrome/browser/ui/webui/extensions/extensions_ui.h" #include "chrome/browser/profiles/profile.h" -#include "chrome/browser/ui/webui/extensions/command_handler.h" #include "chrome/browser/ui/webui/extensions/extension_loader_handler.h" #include "chrome/browser/ui/webui/extensions/extension_settings_handler.h" #include "chrome/browser/ui/webui/extensions/install_extension_handler.h" @@ -50,10 +49,6 @@ ExtensionsUI::ExtensionsUI(content::WebUI* web_ui) : WebUIController(web_ui) { handler->GetLocalizedValues(source); web_ui->AddMessageHandler(handler); - CommandHandler* commands_handler = new CommandHandler(profile); - commands_handler->GetLocalizedValues(source); - web_ui->AddMessageHandler(commands_handler); - ExtensionLoaderHandler* extension_loader_handler = new ExtensionLoaderHandler(profile); extension_loader_handler->GetLocalizedValues(source); diff --git a/chrome/chrome_browser_ui.gypi b/chrome/chrome_browser_ui.gypi index f8dd2e7..a9c41bd 100644 --- a/chrome/chrome_browser_ui.gypi +++ b/chrome/chrome_browser_ui.gypi @@ -1751,8 +1751,6 @@ 'browser/ui/webui/downloads_dom_handler.h', 'browser/ui/webui/downloads_ui.cc', 'browser/ui/webui/downloads_ui.h', - 'browser/ui/webui/extensions/command_handler.cc', - 'browser/ui/webui/extensions/command_handler.h', 'browser/ui/webui/extensions/extension_loader_handler.cc', 'browser/ui/webui/extensions/extension_loader_handler.h', 'browser/ui/webui/extensions/extension_settings_handler.cc', diff --git a/chrome/common/extensions/api/developer_private.idl b/chrome/common/extensions/api/developer_private.idl index 539bd6a..0990f26 100644 --- a/chrome/common/extensions/api/developer_private.idl +++ b/chrome/common/extensions/api/developer_private.idl @@ -87,6 +87,11 @@ namespace developerPrivate { TERMINATED }; + enum CommandScope { + GLOBAL, + CHROME + }; + dictionary AccessModifier { boolean isEnabled; boolean isActive; @@ -161,9 +166,19 @@ namespace developerPrivate { DOMString text; }; + dictionary Command { + DOMString description; + DOMString keybinding; + DOMString name; + boolean isActive; + CommandScope scope; + boolean isExtensionAction; + }; + dictionary ExtensionInfo { boolean actionButtonHidden; DOMString? blacklistText; + Command[] commands; ControlledInfo? controlledInfo; DOMString[] dependentExtensions; DOMString description; @@ -259,6 +274,13 @@ namespace developerPrivate { boolean? inDeveloperMode; }; + dictionary ExtensionCommandUpdate { + DOMString extensionId; + DOMString commandName; + CommandScope? scope; + DOMString? keybinding; + }; + dictionary ReloadOptions { // If false, an alert dialog will show in the event of a reload error. // Defaults to false. @@ -527,6 +549,16 @@ namespace developerPrivate { // |extensionId| : The id of the extension to show the path for. static void showPath(DOMString extensionId, optional VoidCallback callback); + // (Un)suspends global shortcut handling. + // |isSuspended| : Whether or not shortcut handling should be suspended. + static void setShortcutHandlingSuspended(boolean isSuspended, + optional VoidCallback callback); + + // Updates an extension command. + // |update| : The parameters for updating the extension command. + static void updateExtensionCommand(ExtensionCommandUpdate update, + optional VoidCallback callback); + [nocompile, deprecated="Use management.setEnabled"] static void enable(DOMString id, boolean enabled, diff --git a/chrome/common/extensions/command.cc b/chrome/common/extensions/command.cc index 10ee539..ba42e1c 100644 --- a/chrome/common/extensions/command.cc +++ b/chrome/common/extensions/command.cc @@ -552,28 +552,4 @@ bool Command::Parse(const base::DictionaryValue* command, return true; } -base::DictionaryValue* Command::ToValue(const Extension* extension, - bool active) const { - base::DictionaryValue* extension_data = new base::DictionaryValue(); - - base::string16 command_description; - bool extension_action = false; - if (command_name() == values::kBrowserActionCommandEvent || - command_name() == values::kPageActionCommandEvent) { - command_description = - l10n_util::GetStringUTF16(IDS_EXTENSION_COMMANDS_GENERIC_ACTIVATE); - extension_action = true; - } else { - command_description = description(); - } - extension_data->SetString("description", command_description); - extension_data->SetBoolean("active", active); - extension_data->SetString("keybinding", accelerator().GetShortcutText()); - extension_data->SetString("command_name", command_name()); - extension_data->SetString("extension_id", extension->id()); - extension_data->SetBoolean("global", global()); - extension_data->SetBoolean("extension_action", extension_action); - return extension_data; -} - } // namespace extensions diff --git a/chrome/common/extensions/command.h b/chrome/common/extensions/command.h index 41ec35a..7541cde 100644 --- a/chrome/common/extensions/command.h +++ b/chrome/common/extensions/command.h @@ -53,11 +53,6 @@ class Command { int index, base::string16* error); - // Convert a Command object from |extension| to a DictionaryValue. - // |active| specifies whether the command is active or not. - base::DictionaryValue* ToValue( - const Extension* extension, bool active) const; - // Accessors: const std::string& command_name() const { return command_name_; } const ui::Accelerator& accelerator() const { return accelerator_; } diff --git a/extensions/browser/extension_function_histogram_value.h b/extensions/browser/extension_function_histogram_value.h index e183baf..be63214 100644 --- a/extensions/browser/extension_function_histogram_value.h +++ b/extensions/browser/extension_function_histogram_value.h @@ -1100,6 +1100,8 @@ enum HistogramValue { PASSWORDSPRIVATE_GETPLAINTEXTPASSWORD, LAUNCHERPAGE_HIDE, PLATFORMKEYS_VERIFYTLSSERVERCERTIFICATE, + DEVELOPERPRIVATE_SETSHORTCUTHANDLINGSUSPENDED, + DEVELOPERPRIVATE_UPDATEEXTENSIONCOMMAND, // Last entry: Add new entries above and ensure to update // tools/metrics/histograms/histograms.xml. ENUM_BOUNDARY diff --git a/third_party/closure_compiler/externs/developer_private.js b/third_party/closure_compiler/externs/developer_private.js index 338120f..c4a94f3 100644 --- a/third_party/closure_compiler/externs/developer_private.js +++ b/third_party/closure_compiler/externs/developer_private.js @@ -122,6 +122,15 @@ chrome.developerPrivate.ExtensionState = { }; /** + * @enum {string} + * @see https://developer.chrome.com/extensions/developerPrivate#type-CommandScope + */ +chrome.developerPrivate.CommandScope = { + GLOBAL: 'GLOBAL', + CHROME: 'CHROME', +}; + +/** * @typedef {{ * isEnabled: boolean, * isActive: boolean @@ -235,8 +244,22 @@ var ControlledInfo; /** * @typedef {{ + * description: string, + * keybinding: string, + * name: string, + * isActive: boolean, + * scope: !chrome.developerPrivate.CommandScope, + * isExtensionAction: boolean + * }} + * @see https://developer.chrome.com/extensions/developerPrivate#type-Command + */ +var Command; + +/** + * @typedef {{ * actionButtonHidden: boolean, * blacklistText: (string|undefined), + * commands: !Array<Command>, * controlledInfo: (ControlledInfo|undefined), * dependentExtensions: !Array<string>, * description: string, @@ -350,6 +373,17 @@ var ProfileConfigurationUpdate; /** * @typedef {{ + * extensionId: string, + * commandName: string, + * scope: (!chrome.developerPrivate.CommandScope|undefined), + * keybinding: (string|undefined) + * }} + * @see https://developer.chrome.com/extensions/developerPrivate#type-ExtensionCommandUpdate + */ +var ExtensionCommandUpdate; + +/** + * @typedef {{ * failQuietly: (boolean|undefined) * }} * @see https://developer.chrome.com/extensions/developerPrivate#type-ReloadOptions @@ -666,6 +700,24 @@ chrome.developerPrivate.showOptions = function(extensionId, callback) {}; chrome.developerPrivate.showPath = function(extensionId, callback) {}; /** + * (Un)suspends global shortcut handling. + * @param {boolean} isSuspended Whether or not shortcut handling should be + * suspended. + * @param {function():void=} callback + * @see https://developer.chrome.com/extensions/developerPrivate#method-setShortcutHandlingSuspended + */ +chrome.developerPrivate.setShortcutHandlingSuspended = function(isSuspended, callback) {}; + +/** + * Updates an extension command. + * @param {ExtensionCommandUpdate} update The parameters for updating the + * extension command. + * @param {function():void=} callback + * @see https://developer.chrome.com/extensions/developerPrivate#method-updateExtensionCommand + */ +chrome.developerPrivate.updateExtensionCommand = function(update, callback) {}; + +/** * @param {string} id * @param {boolean} enabled * @param {function():void=} callback @@ -712,4 +764,4 @@ chrome.developerPrivate.onItemStateChanged; * @type {!ChromeEvent} * @see https://developer.chrome.com/extensions/developerPrivate#event-onProfileStateChanged */ -chrome.developerPrivate.onProfileStateChanged;
\ No newline at end of file +chrome.developerPrivate.onProfileStateChanged; diff --git a/tools/metrics/histograms/histograms.xml b/tools/metrics/histograms/histograms.xml index b1c92da..7f036b4 100644 --- a/tools/metrics/histograms/histograms.xml +++ b/tools/metrics/histograms/histograms.xml @@ -52892,6 +52892,8 @@ Therefore, the affected-histogram name has to have at least one dot in it. <int value="1039" label="PASSWORDSPRIVATE_GETPLAINTEXTPASSWORD"/> <int value="1040" label="LAUNCHERPAGE_HIDE"/> <int value="1041" label="PLATFORMKEYS_VERIFYTLSSERVERCERTIFICATE"/> + <int value="1042" label="DEVELOPERPRIVATE_SETSHORTCUTHANDLINGSUSPENDED"/> + <int value="1043" label="DEVELOPERPRIVATE_UPDATEEXTENSIONCOMMAND"/> </enum> <enum name="ExtensionInstallCause" type="int"> |