summaryrefslogtreecommitdiffstats
path: root/chrome
diff options
context:
space:
mode:
authorasargent@chromium.org <asargent@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2009-10-16 18:34:28 +0000
committerasargent@chromium.org <asargent@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2009-10-16 18:34:28 +0000
commit43919ac90f426c807da507d52c163972634c771e (patch)
tree29d4053f433b61e587fa532428cb3dc4b11823de /chrome
parent29f192ded5a521a42ff1f93880e0787f2500d5a0 (diff)
downloadchromium_src-43919ac90f426c807da507d52c163972634c771e.zip
chromium_src-43919ac90f426c807da507d52c163972634c771e.tar.gz
chromium_src-43919ac90f426c807da507d52c163972634c771e.tar.bz2
Add concept of an options page to Extensions.
BUG=23801 TEST=Create an extension with an "options_page" entry in its manifest with a value the name of a html file in the extension dir. Load that extension and go to chrome://extensions, there should be an "Options" button that takes you to the page specified in the manifest. Review URL: http://codereview.chromium.org/271114 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@29297 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'chrome')
-rw-r--r--chrome/browser/extensions/extension_browsertests_misc.cc38
-rw-r--r--chrome/browser/extensions/extensions_ui.cc22
-rw-r--r--chrome/browser/extensions/extensions_ui.h3
-rw-r--r--chrome/browser/resources/extensions_ui.html31
-rw-r--r--chrome/common/extensions/extension.cc10
-rw-r--r--chrome/common/extensions/extension.h4
-rw-r--r--chrome/common/extensions/extension_constants.cc5
-rw-r--r--chrome/common/extensions/extension_constants.h2
-rw-r--r--chrome/common/extensions/extension_unittest.cc13
-rw-r--r--chrome/test/data/extensions/options.crxbin0 -> 995 bytes
10 files changed, 118 insertions, 10 deletions
diff --git a/chrome/browser/extensions/extension_browsertests_misc.cc b/chrome/browser/extensions/extension_browsertests_misc.cc
index 63530b3..10d33c3 100644
--- a/chrome/browser/extensions/extension_browsertests_misc.cc
+++ b/chrome/browser/extensions/extension_browsertests_misc.cc
@@ -788,3 +788,41 @@ IN_PROC_BROWSER_TEST_F(ExtensionBrowserTest, AutoUpdate) {
ASSERT_EQ("2.0", extensions->at(0)->VersionString());
}
+// Used to simulate a click on the first button named 'Options'.
+static const wchar_t* jscript_click_option_button =
+ L"(function() { "
+ L" var button = document.evaluate(\"//button[text()='Options']\","
+ L" document, null, XPathResult.UNORDERED_NODE_SNAPSHOT_TYPE,"
+ L" null).snapshotItem(0);"
+ L" button.click();"
+ L" window.domAutomationController.send(0);"
+ L"})();";
+
+// Test that an extension with an options page makes an 'Options' button appear
+// on chrome://extensions, and that clicking the button opens a new tab with the
+// extension's options page.
+IN_PROC_BROWSER_TEST_F(ExtensionBrowserTest, OptionsPage) {
+ // Install an extension with an options page.
+ ASSERT_TRUE(InstallExtension(test_data_dir_.AppendASCII("options.crx"), 1));
+ ExtensionsService* service = browser()->profile()->GetExtensionsService();
+ const ExtensionList* extensions = service->extensions();
+ ASSERT_EQ(1u, extensions->size());
+ Extension* extension = extensions->at(0);
+
+ // Go to the chrome://extensions page and click the Options button.
+ ui_test_utils::NavigateToURL(browser(), GURL(chrome::kChromeUIExtensionsURL));
+ TabStripModel* tab_strip = browser()->tabstrip_model();
+ TabContents* extensions_tab = browser()->GetSelectedTabContents();
+ ui_test_utils::ExecuteJavaScript(extensions_tab->render_view_host(), L"",
+ jscript_click_option_button);
+
+ // If the options page hasn't already come up, wait for it.
+ if (tab_strip->count() == 1) {
+ ui_test_utils::WaitForNewTab(browser());
+ }
+ ASSERT_EQ(2, tab_strip->count());
+
+ EXPECT_EQ(extension->GetResourceURL("options.html"),
+ tab_strip->GetTabContentsAt(1)->GetURL());
+}
+
diff --git a/chrome/browser/extensions/extensions_ui.cc b/chrome/browser/extensions/extensions_ui.cc
index b77a751..752a47d 100644
--- a/chrome/browser/extensions/extensions_ui.cc
+++ b/chrome/browser/extensions/extensions_ui.cc
@@ -8,6 +8,7 @@
#include "app/resource_bundle.h"
#include "base/string_util.h"
#include "base/thread.h"
+#include "chrome/browser/browser.h"
#include "chrome/browser/browser_process.h"
#include "chrome/browser/chrome_thread.h"
#include "chrome/browser/debugger/devtools_manager.h"
@@ -95,6 +96,8 @@ void ExtensionsDOMHandler::RegisterMessages() {
NewCallback(this, &ExtensionsDOMHandler::HandleEnableMessage));
dom_ui_->RegisterMessageCallback("uninstall",
NewCallback(this, &ExtensionsDOMHandler::HandleUninstallMessage));
+ dom_ui_->RegisterMessageCallback("options",
+ NewCallback(this, &ExtensionsDOMHandler::HandleOptionsMessage));
dom_ui_->RegisterMessageCallback("load",
NewCallback(this, &ExtensionsDOMHandler::HandleLoadMessage));
dom_ui_->RegisterMessageCallback("pack",
@@ -198,6 +201,22 @@ void ExtensionsDOMHandler::HandleUninstallMessage(const Value* value) {
extensions_service_->UninstallExtension(extension_id, false);
}
+void ExtensionsDOMHandler::HandleOptionsMessage(const Value* value) {
+ CHECK(value->IsType(Value::TYPE_LIST));
+ const ListValue* list = static_cast<const ListValue*>(value);
+ CHECK(list->GetSize() == 1);
+ std::string extension_id;
+ CHECK(list->GetString(0, &extension_id));
+ Extension *extension = extensions_service_->GetExtensionById(extension_id);
+ if (!extension || extension->options_url().is_empty()) {
+ return;
+ }
+ Browser* browser = Browser::GetOrCreateTabbedBrowser(dom_ui_->GetProfile());
+ CHECK(browser);
+ browser->OpenURL(extension->options_url(), GURL(), NEW_FOREGROUND_TAB,
+ PageTransition::LINK);
+}
+
void ExtensionsDOMHandler::HandleLoadMessage(const Value* value) {
std::string string_path;
CHECK(value->IsType(Value::TYPE_LIST));
@@ -399,6 +418,9 @@ DictionaryValue* ExtensionsDOMHandler::CreateExtensionDetailValue(
extension_data->SetString(L"description", extension->description());
extension_data->SetString(L"version", extension->version()->GetString());
extension_data->SetBoolean(L"enabled", enabled);
+ if (!extension->options_url().is_empty()) {
+ extension_data->SetString(L"options_url", extension->options_url().spec());
+ }
// Add list of content_script detail DictionaryValues
ListValue *content_script_list = new ListValue();
diff --git a/chrome/browser/extensions/extensions_ui.h b/chrome/browser/extensions/extensions_ui.h
index 908c9f3..90c0e92 100644
--- a/chrome/browser/extensions/extensions_ui.h
+++ b/chrome/browser/extensions/extensions_ui.h
@@ -95,6 +95,9 @@ class ExtensionsDOMHandler
// Callback for "uninstall" message.
void HandleUninstallMessage(const Value* value);
+ // Callback for "options" message.
+ void HandleOptionsMessage(const Value* value);
+
// Callback for "load" message.
void HandleLoadMessage(const Value* value);
diff --git a/chrome/browser/resources/extensions_ui.html b/chrome/browser/resources/extensions_ui.html
index 99076f8..a228457 100644
--- a/chrome/browser/resources/extensions_ui.html
+++ b/chrome/browser/resources/extensions_ui.html
@@ -206,6 +206,7 @@ var extensionDataFormat = {
"description": "Extension long format description",
"version": "1.0.231",
"enabled": "true",
+ "options_url": "options.html",
"content_scripts": [
{
"js": ["script1_file1.js", "script1_file2.js"],
@@ -345,12 +346,19 @@ function handleUninstallExtension(node) {
}
/**
- * 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.
+ * Handles an 'options' button getting clicked.
*/
+function handleOptions(node) {
+ chrome.send('options', [node.extensionId]);
+}
+
+/**
+* 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.
+*/
function showFileDialog(selectType, operation, callback) {
handleFilePathSelected = function(filePath) {
callback(filePath);
@@ -387,7 +395,7 @@ function showPackDialog() {
/**
* Hides the pack dialog.
- */
+ */
function hidePackDialog() {
document.getElementById('dialogBackground').style.display="none"
}
@@ -438,7 +446,7 @@ function autoUpdate() {
<input type="text" id="extensionPathText">
</div>
<div>
- <input type="button" value="BROWSE"
+ <input type="button" value="BROWSE"
i18n-values="value:packDialogBrowse"
onclick="selectExtensionPath();">
</div>
@@ -451,7 +459,7 @@ function autoUpdate() {
<input type="text" id="privateKeyPath">
</div>
<div>
- <input type="button" value="BROWSE"
+ <input type="button" value="BROWSE"
i18n-values="value:packDialogBrowse"
onclick="selectPrivateKeyPath();">
</div>
@@ -463,7 +471,7 @@ function autoUpdate() {
<div>
<input type="button" value="Cancel" onclick="hidePackDialog();">
</div>
- </div>
+ </div>
</div>
</div>
</div>
@@ -524,6 +532,11 @@ function autoUpdate() {
jsvalues=".extensionId:id"
onclick="handleUninstallExtension(this)"
>Uninstall</button>
+ <button
+ jsdisplay="options_url"
+ jsvalues=".extensionId:id"
+ onclick="handleOptions(this)"
+ >Options</button>
</div>
</div>
</div>
diff --git a/chrome/common/extensions/extension.cc b/chrome/common/extensions/extension.cc
index 506c390..fee0e89 100644
--- a/chrome/common/extensions/extension.cc
+++ b/chrome/common/extensions/extension.cc
@@ -830,6 +830,16 @@ bool Extension::InitFromValue(const DictionaryValue& source, bool require_id,
background_url_ = GetResourceURL(background_str);
}
+ // Initialize options page url (optional).
+ if (source.HasKey(keys::kOptionsPage)) {
+ std::string options_str;
+ if (!source.GetString(keys::kOptionsPage, &options_str)) {
+ *error = errors::kInvalidOptionsPage;
+ return false;
+ }
+ options_url_ = GetResourceURL(options_str);
+ }
+
// Initialize toolstrips (optional).
if (source.HasKey(keys::kToolstrips)) {
ListValue* list_value;
diff --git a/chrome/common/extensions/extension.h b/chrome/common/extensions/extension.h
index 0cb120b..c96ec0a 100644
--- a/chrome/common/extensions/extension.h
+++ b/chrome/common/extensions/extension.h
@@ -195,6 +195,7 @@ class Extension {
}
const std::vector<PluginInfo>& plugins() const { return plugins_; }
const GURL& background_url() const { return background_url_; }
+ const GURL& options_url() const { return options_url_; }
const std::vector<ToolstripInfo>& toolstrips() const { return toolstrips_; }
const std::vector<std::string>& api_permissions() const {
return api_permissions_;
@@ -334,6 +335,9 @@ class Extension {
// loaded in the background.
GURL background_url_;
+ // Optional URL to a page for setting options/preferences.
+ GURL options_url_;
+
// Optional list of toolstrips_ and associated properties.
std::vector<ToolstripInfo> toolstrips_;
diff --git a/chrome/common/extensions/extension_constants.cc b/chrome/common/extensions/extension_constants.cc
index 13d0547..db7c8b7 100644
--- a/chrome/common/extensions/extension_constants.cc
+++ b/chrome/common/extensions/extension_constants.cc
@@ -46,6 +46,7 @@ const wchar_t* kToolstrips = L"toolstrips";
const wchar_t* kType = L"type";
const wchar_t* kVersion = L"version";
const wchar_t* kUpdateURL = L"update_url";
+const wchar_t* kOptionsPage = L"options_page";
} // namespace extension_manifest_keys
namespace extension_manifest_values {
@@ -133,7 +134,7 @@ const char* kInvalidPrivacyBlacklists =
const char* kInvalidPrivacyBlacklistsPath =
"Invalid value for 'privacy_blacklists[*]'.";
const char* kInvalidBackground =
- "Invalid value for 'background'.";
+ "Invalid value for 'background_page'.";
const char* kInvalidRunAt =
"Invalid value for 'content_scripts[*].run_at'.";
const char* kInvalidSignature =
@@ -175,4 +176,6 @@ const char* kLocalesNoDefaultLocaleSpecified =
"Localization used, but default_locale wasn't specified in the manifest.";
const char* kLocalesNoValidLocaleNamesListed =
"No valid locale name could be found in _locales directory.";
+const char* kInvalidOptionsPage =
+ "Invalid value for 'options_page'.";
} // namespace extension_manifest_errors
diff --git a/chrome/common/extensions/extension_constants.h b/chrome/common/extensions/extension_constants.h
index ec8dbe4..5c8a087 100644
--- a/chrome/common/extensions/extension_constants.h
+++ b/chrome/common/extensions/extension_constants.h
@@ -47,6 +47,7 @@ namespace extension_manifest_keys {
extern const wchar_t* kType;
extern const wchar_t* kVersion;
extern const wchar_t* kUpdateURL;
+ extern const wchar_t* kOptionsPage;
} // namespace extension_manifest_keys
// Some values expected in manifests.
@@ -116,6 +117,7 @@ namespace extension_manifest_errors {
extern const char* kInvalidDefaultLocale;
extern const char* kLocalesNoDefaultLocaleSpecified;
extern const char* kLocalesNoValidLocaleNamesListed;
+ extern const char* kInvalidOptionsPage;
} // namespace extension_manifest_errors
#endif // CHROME_COMMON_EXTENSIONS_EXTENSION_CONSTANTS_H_
diff --git a/chrome/common/extensions/extension_unittest.cc b/chrome/common/extensions/extension_unittest.cc
index 104ce7a..eeb4499 100644
--- a/chrome/common/extensions/extension_unittest.cc
+++ b/chrome/common/extensions/extension_unittest.cc
@@ -231,6 +231,12 @@ TEST(ExtensionTest, InitFromValueInvalid) {
input_value->Set(keys::kBrowserAction, action);
EXPECT_FALSE(extension.InitFromValue(*input_value, true, &error));
EXPECT_STREQ(error.c_str(), errors::kOneUISurfaceOnly);
+
+ // Test invalid options page url.
+ input_value.reset(static_cast<DictionaryValue*>(valid_value->DeepCopy()));
+ input_value->Set(keys::kOptionsPage, Value::CreateNullValue());
+ EXPECT_FALSE(extension.InitFromValue(*input_value, true, &error));
+ EXPECT_TRUE(MatchPattern(error, errors::kInvalidOptionsPage));
}
TEST(ExtensionTest, InitFromValueValid) {
@@ -254,6 +260,13 @@ TEST(ExtensionTest, InitFromValueValid) {
EXPECT_EQ("my extension", extension.name());
EXPECT_EQ(extension.id(), extension.url().host());
EXPECT_EQ(path.value(), extension.path().value());
+
+ // Test with an options page.
+ input_value.SetString(keys::kOptionsPage, "options.html");
+ EXPECT_TRUE(extension.InitFromValue(input_value, false, &error));
+ EXPECT_EQ("", error);
+ EXPECT_EQ("chrome-extension", extension.options_url().scheme());
+ EXPECT_EQ("/options.html", extension.options_url().path());
}
TEST(ExtensionTest, GetResourceURLAndPath) {
diff --git a/chrome/test/data/extensions/options.crx b/chrome/test/data/extensions/options.crx
new file mode 100644
index 0000000..f286e19
--- /dev/null
+++ b/chrome/test/data/extensions/options.crx
Binary files differ