summaryrefslogtreecommitdiffstats
path: root/chrome/browser
diff options
context:
space:
mode:
authorrafaelw@chromium.org <rafaelw@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2009-03-09 01:47:37 +0000
committerrafaelw@chromium.org <rafaelw@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2009-03-09 01:47:37 +0000
commit829f8e2906fa3251da47e61bbbe002f2c704e60f (patch)
treedc139d54c9594ce76c28099fcce39640bc689687 /chrome/browser
parent71167c0906304846a86280830c91109a080f9fd6 (diff)
downloadchromium_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.cc106
-rw-r--r--chrome/browser/extensions/extensions_service_unittest.cc6
-rw-r--r--chrome/browser/extensions/extensions_ui.cc95
-rw-r--r--chrome/browser/extensions/extensions_ui.h20
-rw-r--r--chrome/browser/resources/extensions.html247
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>