diff options
author | rafaelw@chromium.org <rafaelw@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2009-03-09 01:47:37 +0000 |
---|---|---|
committer | rafaelw@chromium.org <rafaelw@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2009-03-09 01:47:37 +0000 |
commit | 829f8e2906fa3251da47e61bbbe002f2c704e60f (patch) | |
tree | dc139d54c9594ce76c28099fcce39640bc689687 /chrome/browser | |
parent | 71167c0906304846a86280830c91109a080f9fd6 (diff) | |
download | chromium_src-829f8e2906fa3251da47e61bbbe002f2c704e60f.zip chromium_src-829f8e2906fa3251da47e61bbbe002f2c704e60f.tar.gz chromium_src-829f8e2906fa3251da47e61bbbe002f2c704e60f.tar.bz2 |
chrome-ui://extensions/ is now populated with data collected from the ExtensionsService and ExtensionErrorReporter
Review URL: http://codereview.chromium.org/39026
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@11233 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'chrome/browser')
-rw-r--r-- | chrome/browser/extensions/extension_ui_unittest.cc | 106 | ||||
-rw-r--r-- | chrome/browser/extensions/extensions_service_unittest.cc | 6 | ||||
-rw-r--r-- | chrome/browser/extensions/extensions_ui.cc | 95 | ||||
-rw-r--r-- | chrome/browser/extensions/extensions_ui.h | 20 | ||||
-rw-r--r-- | chrome/browser/resources/extensions.html | 247 |
5 files changed, 414 insertions, 60 deletions
diff --git a/chrome/browser/extensions/extension_ui_unittest.cc b/chrome/browser/extensions/extension_ui_unittest.cc new file mode 100644 index 0000000..3915e74 --- /dev/null +++ b/chrome/browser/extensions/extension_ui_unittest.cc @@ -0,0 +1,106 @@ +// Copyright (c) 2006-2009 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 "base/path_service.h" +#include "base/string_util.h" +#include "chrome/browser/extensions/extension.h" +#include "chrome/browser/extensions/extensions_ui.h" +#include "chrome/common/chrome_paths.h" +#include "chrome/common/json_value_serializer.h" +#include "testing/gtest/include/gtest/gtest.h" + +namespace { + static DictionaryValue* DeserializeJSONTestData(const FilePath& path, + std::string *error) { + Value* value; + + JSONFileValueSerializer serializer(path.ToWStringHack()); + value = serializer.Deserialize(error); + + return static_cast<DictionaryValue*>(value); + } + + static bool CompareExpectedAndActualOutput(const FilePath& extension_path, + const FilePath& expected_output_path) { + // TODO(rafaelw): Using the extension_path passed in above, causes this + // unit test to fail on linux. The Values come back valid, but the + // UserScript.path() values return "". +#if defined(OS_WIN) + FilePath path(FILE_PATH_LITERAL("c:\\foo")); +#elif defined(OS_POSIX) + FilePath path(FILE_PATH_LITERAL("/foo")); +#endif + Extension extension(path); + std::string error; + + FilePath manifest_path = extension_path.AppendASCII( + Extension::kManifestFilename); + scoped_ptr<DictionaryValue> extension_data(DeserializeJSONTestData( + manifest_path, &error)); + EXPECT_EQ("", error); + EXPECT_TRUE(extension.InitFromValue(*extension_data, &error)); + EXPECT_EQ("", error); + + scoped_ptr<DictionaryValue>expected_output_data(DeserializeJSONTestData( + expected_output_path, &error)); + EXPECT_EQ("", error); + + // Produce test output. + scoped_ptr<DictionaryValue> actual_output_data( + ExtensionsDOMHandler::CreateExtensionDetailValue(&extension)); + + // Compare the outputs. + return expected_output_data->Equals(actual_output_data.get()); + } +} // namespace + +class ExtensionUITest : public testing::Test { +}; + +TEST(ExtensionUITest, GenerateExtensionsJSONData) { + FilePath data_test_dir_path, extension_path, expected_output_path; + EXPECT_TRUE(PathService::Get(chrome::DIR_TEST_DATA, &data_test_dir_path)); + + // Test Extension1 + extension_path = data_test_dir_path.AppendASCII("extensions") + .AppendASCII("good") + .AppendASCII("extension1") + .AppendASCII("1"); + + expected_output_path = data_test_dir_path.AppendASCII("extensions") + .AppendASCII("ui") + .AppendASCII("create_extension_detail_value_expected_output") + .AppendASCII("good-extension1.json"); + + EXPECT_TRUE(CompareExpectedAndActualOutput(extension_path, + expected_output_path)) << extension_path.value(); + + // Test Extension2 + extension_path = data_test_dir_path.AppendASCII("extensions") + .AppendASCII("good") + .AppendASCII("extension2") + .AppendASCII("2"); + + expected_output_path = data_test_dir_path.AppendASCII("extensions") + .AppendASCII("ui") + .AppendASCII("create_extension_detail_value_expected_output") + .AppendASCII("good-extension2.json"); + + EXPECT_TRUE(CompareExpectedAndActualOutput(extension_path, + expected_output_path)) << extension_path.value(); + + // Test Extension3 + extension_path = data_test_dir_path.AppendASCII("extensions") + .AppendASCII("good") + .AppendASCII("extension3") + .AppendASCII("1.0"); + + expected_output_path = data_test_dir_path.AppendASCII("extensions") + .AppendASCII("ui") + .AppendASCII("create_extension_detail_value_expected_output") + .AppendASCII("good-extension3.json"); + + EXPECT_TRUE(CompareExpectedAndActualOutput(extension_path, + expected_output_path)) << extension_path.value(); +} diff --git a/chrome/browser/extensions/extensions_service_unittest.cc b/chrome/browser/extensions/extensions_service_unittest.cc index d74c060..304aba4 100644 --- a/chrome/browser/extensions/extensions_service_unittest.cc +++ b/chrome/browser/extensions/extensions_service_unittest.cc @@ -169,7 +169,7 @@ TEST_F(ExtensionsServiceTest, LoadAllExtensionsFromDirectorySuccess) { Extension* extension = frontend->extensions()->at(0); const UserScriptList& scripts = extension->content_scripts(); - ASSERT_EQ(2u, scripts.size()); + ASSERT_EQ(3u, scripts.size()); EXPECT_EQ(2u, scripts[0].url_patterns().size()); EXPECT_EQ("http://*.google.com/*", scripts[0].url_patterns()[0].GetAsString()); @@ -181,6 +181,10 @@ TEST_F(ExtensionsServiceTest, LoadAllExtensionsFromDirectorySuccess) { EXPECT_EQ("http://*.yahoo.com/*", scripts[1].url_patterns()[0].GetAsString()); EXPECT_EQ(extension->path().AppendASCII("script2.js").value(), scripts[1].path().value()); + EXPECT_EQ(1u, scripts[2].url_patterns().size()); + EXPECT_EQ("http://*.news.com/*", scripts[2].url_patterns()[0].GetAsString()); + EXPECT_EQ(extension->path().AppendASCII("js_files").AppendASCII("script3.js") + .value(), scripts[2].path().value()); EXPECT_EQ(std::string("10123456789abcdef0123456789abcdef0123456"), frontend->extensions()->at(1)->id()); diff --git a/chrome/browser/extensions/extensions_ui.cc b/chrome/browser/extensions/extensions_ui.cc index c4d2344..776676b 100644 --- a/chrome/browser/extensions/extensions_ui.cc +++ b/chrome/browser/extensions/extensions_ui.cc @@ -6,10 +6,14 @@ #include "base/thread.h" #include "chrome/browser/browser_process.h" +#include "chrome/browser/extensions/extensions_service.h" +#include "chrome/browser/extensions/extension_error_reporter.h" +#include "chrome/browser/profile.h" #include "chrome/common/jstemplate_builder.h" #include "chrome/common/l10n_util.h" #include "chrome/common/resource_bundle.h" #include "chrome/common/url_constants.h" +#include "net/base/net_util.h" #include "grit/browser_resources.h" #include "grit/generated_resources.h" @@ -52,8 +56,90 @@ void ExtensionsUIHTMLSource::StartDataRequest(const std::string& path, // /////////////////////////////////////////////////////////////////////////////// -ExtensionsDOMHandler::ExtensionsDOMHandler(DOMUI* dom_ui) - : DOMMessageHandler(dom_ui) { +ExtensionsDOMHandler::ExtensionsDOMHandler(DOMUI* dom_ui, + ExtensionsService* extension_service) + : DOMMessageHandler(dom_ui), extensions_service_(extension_service) { + dom_ui_->RegisterMessageCallback("requestExtensionsData", + NewCallback(this, &ExtensionsDOMHandler::HandleRequestExtensionsData)); +} + +void ExtensionsDOMHandler::HandleRequestExtensionsData(const Value* value) { + DictionaryValue results; + + // Add the extensions to the results structure. + ListValue *extensions_list = new ListValue(); + const ExtensionList* extensions = extensions_service_->extensions(); + for (ExtensionList::const_iterator extension = extensions->begin(); + extension != extensions->end(); ++extension) { + extensions_list->Append(CreateExtensionDetailValue(*extension)); + } + results.Set(L"extensions", extensions_list); + + // Add any error log lines to the result structure. + ListValue *errors_list = new ListValue(); + const std::vector<std::string>* errors = + ExtensionErrorReporter::GetInstance()->GetErrors(); + for (std::vector<std::string>::const_iterator error = errors->begin(); + error != errors->end(); ++error) { + errors_list->Append(Value::CreateStringValue(*error)); + } + results.Set(L"errors", errors_list); + + dom_ui_->CallJavascriptFunction(L"returnExtensionsData", results); +} + +// Static +DictionaryValue* ExtensionsDOMHandler::CreateContentScriptDetailValue( + const UserScript& script, const FilePath& extension_path) { + DictionaryValue* script_data = new DictionaryValue(); + + // TODO(rafaelw): When UserScript supports multiple js, this will have to + // put them all in this list; + ListValue *js_list = new ListValue(); + // We are passing through GURLs to canonicalize the output to a valid + // URL path fragment. + GURL script_url = net::FilePathToFileURL(script.path()); + GURL extension_url = net::FilePathToFileURL(extension_path); + std::string relative_js_path = + script_url.spec().substr(extension_url.spec().length() + 1); + + js_list->Append(new StringValue(relative_js_path)); + script_data->Set(L"js", js_list); + + // Get list of glob "matches" strings + ListValue *url_pattern_list = new ListValue(); + const std::vector<URLPattern>& url_patterns = script.url_patterns(); + for (std::vector<URLPattern>::const_iterator url_pattern = + url_patterns.begin(); + url_pattern != url_patterns.end(); ++url_pattern) { + url_pattern_list->Append(new StringValue(url_pattern->GetAsString())); + } + + script_data->Set(L"matches", url_pattern_list); + + return script_data; +} + +// Static +DictionaryValue* ExtensionsDOMHandler::CreateExtensionDetailValue( + const Extension *extension) { + DictionaryValue* extension_data = new DictionaryValue(); + + extension_data->SetString(L"name", extension->name()); + extension_data->SetString(L"description", extension->description()); + extension_data->SetString(L"version", extension->version()->GetString()); + + // Add list of content_script detail DictionaryValues + ListValue *content_script_list = new ListValue(); + UserScriptList content_scripts = extension->content_scripts(); + for (UserScriptList::const_iterator script = content_scripts.begin(); + script != content_scripts.end(); ++script) { + content_script_list->Append(CreateContentScriptDetailValue(*script, + extension->path())); + } + extension_data->Set(L"content_scripts", content_script_list); + + return extension_data; } ExtensionsDOMHandler::~ExtensionsDOMHandler() { @@ -68,7 +154,10 @@ ExtensionsUI::ExtensionsUI(DOMUIContents* contents) : DOMUI(contents) { } void ExtensionsUI::Init() { - ExtensionsDOMHandler* handler = new ExtensionsDOMHandler(this); + ExtensionsService *exstension_service = get_profile()->GetExtensionsService(); + + ExtensionsDOMHandler* handler = new ExtensionsDOMHandler(this, + exstension_service); AddMessageHandler(handler); handler->Init(); diff --git a/chrome/browser/extensions/extensions_ui.h b/chrome/browser/extensions/extensions_ui.h index 1298289..3252ddc 100644 --- a/chrome/browser/extensions/extensions_ui.h +++ b/chrome/browser/extensions/extensions_ui.h @@ -9,6 +9,7 @@ #include "chrome/browser/dom_ui/dom_ui.h" #include "chrome/browser/dom_ui/dom_ui_contents.h" +#include "chrome/browser/extensions/extensions_service.h" class GURL; @@ -30,11 +31,28 @@ class ExtensionsUIHTMLSource : public ChromeURLDataManager::DataSource { // The handler for Javascript messages related to the "extensions" view. class ExtensionsDOMHandler : public DOMMessageHandler { public: - explicit ExtensionsDOMHandler(DOMUI* dom_ui); + ExtensionsDOMHandler(DOMUI* dom_ui, + ExtensionsService* extension_service); + virtual ~ExtensionsDOMHandler(); void Init(); + // Extension Detail JSON Struct for page. (static for ease of testing). + static DictionaryValue* + CreateExtensionDetailValue(const Extension *extension); + + // ContentScript JSON Struct for page. (static for ease of testing). + static DictionaryValue* + CreateContentScriptDetailValue(const UserScript& script, + const FilePath& extension_path); + private: + // Callback for "requestExtensionsData" message. + void HandleRequestExtensionsData(const Value* value); + + // Our model. + scoped_refptr<ExtensionsService> extensions_service_; + DISALLOW_COPY_AND_ASSIGN(ExtensionsDOMHandler); }; diff --git a/chrome/browser/resources/extensions.html b/chrome/browser/resources/extensions.html index 2428e14..e719f91 100644 --- a/chrome/browser/resources/extensions.html +++ b/chrome/browser/resources/extensions.html @@ -4,43 +4,53 @@ <meta charset="utf-8"> <title jscontent="title"></title> <script type="text/javascript"> - -// TODO(rafaelw): Remove. This is stub data. The idea is that the C++ will -// populate a similar json structure and hand it to this page with real data -// from the extensions system -var testExtensionData = [ - { - "name": "Dummy Extension", - "description": "Does some extremely cool stuff that I won't ever bother " + - "explaining, because it's just that cool.", - "version": "1.0.231", - "content_scripts": [ - { - "js": ["file1.js", "file2.js"], - "matches": ["http://*/*", "http://other.com/*"] - }, - { - "js": ["file1.js", "file2.js"], - "matches": ["http://*/*", "http://other.com/*"] - }, - { - "js": ["file1.js", "file2.js"], - "matches": ["http://*/*", "http://other.com/*"] - }, - ], - }, - { - "name": "PlaceHolder Extension", - "description": "", - "version": "1.0.231", - "content_scripts": [], - } -]; +/** + * This variable structure is here to document the structure that the template + * expects to correctly populate the page. + */ +var extensionDataFormat = { + "extensions": [ + { + "name": "Extension Name", + "description": "Extension long format description", + "version": "1.0.231", + "content_scripts": [ + { + "js": ["script1_file1.js", "script1_file2.js"], + "matches": ["http://*/*", "http://other.com/*"] + }, + { + "js": ["script2_file1.js", "script2_file2.js"], + "matches": ["http://*/*", "http://other.com/*"] + } + ] + }, + { + "name": "Extension Name", + "description": "Extension long format description", + "version": "1.0.231", + "content_scripts": [ + { + "js": ["script1_file1.js", "script1_file2.js"], + "matches": ["http://*/*", "http://other.com/*"] + }, + { + "js": ["script2_file1.js", "script2_file2.js"], + "matches": ["http://*/*", "http://other.com/*"] + } + ] + } + ], + "errors": [ + "something failed to happen", + "something else failed to happen" + ] +}; /** * Takes the |extensionsData| input argument which represents data about the * currently installed/running extensions and populates the html jstemplate with - * that data + * that data. It expects an object structure like the above. * @param {Object} extensionsData Detailed info about installed extensions */ function showExtensionsData(extensionsData) { @@ -49,37 +59,164 @@ function showExtensionsData(extensionsData) { var output = document.getElementById('extensionTemplate'); jstProcess(input, output); } + +/* + * Asks the C++ ExtensionDOMHandler to inspect the installed extensions and + * return detailed data about the configuration. The ExtensionDOMHandler + * should reply to returnExtensionsData() (below). + */ +function requestExtensionsData() { + chrome.send("requestExtensionsData", []); +} +function returnExtensionsData(extensionsData) { + showExtensionsData(extensionsData); + + // We are currently hiding the body because the first call to jstProcess() to + // insert localized strings happens prior to this call which runs during the + // body.onload event, causes a flickering. + document.getElementById('body-container').style.display = "inline"; +} </script> <style type="text/css"> -h1 { +body { + background-color: Window; + color: WindowText; + font: message-box; +} + +div#outside { + margin-left: 5%; + margin-right: 5%; + text-align: justify; + width: 90%; +} + +div#installed-extensions { + font-size: xx-large; + font-weight: bold; + text-align: center; +} + +div.extension-name { + font-size: large; + font-weight: bold; + margin-top: 2em; + margin-bottom: 1em; + text-align: left; +} + +dl { + margin: 0px 0px 3px 0px; +} + +table { + background-color: Window; + border: 1px solid ThreeDShadow; + border-spacing: 0px; + color: WindowText; + font: message-box; + margin-bottom: 20px; + text-align: left; + width: 100%; +} + +th { + background-color: Highlight; + color: HighlightText; text-align: center; } -.extension{ - padding: 8px; + +th + th, +td + td { + border-left: 1px dotted ThreeDShadow; +} + +td { + border-top: 1px dotted ThreeDShadow; + text-align: left; +} + +th, td { + padding: 3px; +} + +th.type, th.suff { + width: 20%; +} + +th.desc { + width: 50%; +} + +th.enabled { + width: 10%; +} + +#error-box { + background-color:#D8D8D8; + margin-top: 8px; + padding: 8px; + width: 100%; +} +#error-log { + color: #B00000; + font-weight: bold; } -.scriptMatches { - padding: 4px; - font-size: 12px; +.error { + font-style:italic; } </style> </head> -<body onload="showExtensionsData(testExtensionData);"> - <h1>Installed Extensions</h1> - <div id="extensionTemplate"> - <div class="extension" jsselect="$this"> - <div jscontent="name">Extension Name</div> - <div jscontent="description">Extension Description</div> - <div>Version: <span jscontent="version">x.x.x.x</span></div> - <div class="scriptMatches" jsselect="content_scripts"> - <div> - <span jsselect="js" - jscontent="(($index > 0) ? ' ' : '') + $this"> - </span> +<body onload="requestExtensionsData();"> + <div id="body-container" style="display:none;"> + <div id="outside"> + <div id="installed-extensions">Installed Extensions</div> + <div id="extensionTemplate"> + + <div id="error-box" jsdisplay="errors.length > 0"> + <div id="error-log">Errors</div> + <div class="error" jsselect="errors" jscontent="$this"> + Error Detail</div> </div> - <div> - <span jsselect="matches" - jscontent="(($index > 0) ? ' ' : '') + $this"> - </span> + + <div class="extension-name" jsdisplay="extensions.length === 0"> + No Extensions Installed</div> + + <div jsdisplay="extensions.length > 0"> + <div class="extension" jsselect="extensions"> + <div class="extension-name" jscontent="name"> + sExtension Name</div> + <dl> + <dd> + <span jscontent="description">Extension Description</span> + </dd> + <dd>Version: <span jscontent="version">x.x.x.x</span></dd> + </dl> + + <table jsselect="content_scripts"> + <thead> + <tr><th colspan="2">Content Script</th></tr> + </thead> + <tbody> + <tr> + <td>JavaScript Files</td> + <td> + <span jsselect="js" + jscontent="(($index > 0) ? ', ' : '') + $this"> + </span> + </td> + </tr> + <tr> + <td>URL Match Patterns</td> + <td> + <span jsselect="matches" + jscontent="(($index > 0) ? ', ' : '') + $this"> + </span> + </td> + </tr> + </tbody> + </table> + </div> </div> </div> </div> |