summaryrefslogtreecommitdiffstats
path: root/chrome/browser
diff options
context:
space:
mode:
authorglen@chromium.org <glen@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2008-12-07 23:48:03 +0000
committerglen@chromium.org <glen@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2008-12-07 23:48:03 +0000
commit76a010b47593d41d1d443dacc51bc906689c2e53 (patch)
tree28f61efd20f447d21bb5ca3e8582b29994c79eba /chrome/browser
parent85ad84eba6540630a33ab7bfa37c2d37c4a9554d (diff)
downloadchromium_src-76a010b47593d41d1d443dacc51bc906689c2e53.zip
chromium_src-76a010b47593d41d1d443dacc51bc906689c2e53.tar.gz
chromium_src-76a010b47593d41d1d443dacc51bc906689c2e53.tar.bz2
Reupload of 12418
Review URL: http://codereview.chromium.org/13183 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@6497 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'chrome/browser')
-rw-r--r--chrome/browser/browser.vcproj24
-rw-r--r--chrome/browser/browser_about_handler.cc2
-rw-r--r--chrome/browser/browser_main.cc2
-rw-r--r--chrome/browser/browser_resources.h3
-rw-r--r--chrome/browser/browser_resources.rc3
-rw-r--r--chrome/browser/browser_url_handler.cc5
-rw-r--r--chrome/browser/browsing_instance.cc2
-rw-r--r--chrome/browser/debugger/debugger_contents.cc6
-rw-r--r--chrome/browser/debugger/debugger_view.cc7
-rw-r--r--chrome/browser/dom_ui/chrome_url_data_manager.cc6
-rw-r--r--chrome/browser/dom_ui/chrome_url_data_manager.h2
-rw-r--r--chrome/browser/dom_ui/dom_ui.cc124
-rw-r--r--chrome/browser/dom_ui/dom_ui.h86
-rw-r--r--chrome/browser/dom_ui/dom_ui_contents.cc207
-rw-r--r--chrome/browser/dom_ui/dom_ui_contents.h123
-rw-r--r--chrome/browser/dom_ui/history_ui.cc303
-rw-r--r--chrome/browser/dom_ui/history_ui.h83
-rw-r--r--chrome/browser/dom_ui/new_tab_ui.cc104
-rw-r--r--chrome/browser/dom_ui/new_tab_ui.h71
-rw-r--r--chrome/browser/history/history.cc2
-rw-r--r--chrome/browser/native_ui_contents.h2
-rw-r--r--chrome/browser/render_view_context_menu_controller.cc2
-rw-r--r--chrome/browser/renderer_security_policy.cc10
-rw-r--r--chrome/browser/renderer_security_policy_unittest.cc12
-rw-r--r--chrome/browser/resources/browser_resources.vcproj4
-rw-r--r--chrome/browser/resources/history.html789
-rw-r--r--chrome/browser/resources/new_tab.html18
-rw-r--r--chrome/browser/site_instance.cc2
-rw-r--r--chrome/browser/tab_contents_factory.cc7
-rw-r--r--chrome/browser/tab_contents_type.h1
30 files changed, 1801 insertions, 211 deletions
diff --git a/chrome/browser/browser.vcproj b/chrome/browser/browser.vcproj
index 7c91fe1..e853e3a 100644
--- a/chrome/browser/browser.vcproj
+++ b/chrome/browser/browser.vcproj
@@ -1866,6 +1866,22 @@
>
</File>
<File
+ RelativePath=".\dom_ui\dom_ui.cc"
+ >
+ </File>
+ <File
+ RelativePath=".\dom_ui\dom_ui.h"
+ >
+ </File>
+ <File
+ RelativePath=".\dom_ui\dom_ui_contents.cc"
+ >
+ </File>
+ <File
+ RelativePath=".\dom_ui\dom_ui_contents.h"
+ >
+ </File>
+ <File
RelativePath=".\dom_ui\dom_ui_host.cc"
>
</File>
@@ -1874,6 +1890,14 @@
>
</File>
<File
+ RelativePath=".\dom_ui\history_ui.cc"
+ >
+ </File>
+ <File
+ RelativePath=".\dom_ui\history_ui.h"
+ >
+ </File>
+ <File
RelativePath=".\dom_ui\html_dialog_contents.cc"
>
</File>
diff --git a/chrome/browser/browser_about_handler.cc b/chrome/browser/browser_about_handler.cc
index 4922118..6b0e025 100644
--- a/chrome/browser/browser_about_handler.cc
+++ b/chrome/browser/browser_about_handler.cc
@@ -199,7 +199,7 @@ bool BrowserAboutHandler::MaybeHandle(GURL* url,
return false;
*result_type = TAB_CONTENTS_ABOUT_UI;
- std::string about_url = "chrome-resource://about/";
+ std::string about_url = "chrome://about/";
about_url.append(url->path());
*url = GURL(about_url);
return true;
diff --git a/chrome/browser/browser_main.cc b/chrome/browser/browser_main.cc
index 66c5f7f..9e9b258 100644
--- a/chrome/browser/browser_main.cc
+++ b/chrome/browser/browser_main.cc
@@ -536,7 +536,7 @@ int BrowserMain(CommandLine &parsed_command_line,
// Config the network module so it has access to resources.
net::NetModule::SetResourceProvider(NetResourceProvider);
- // Register our global network handler for chrome-resource:// URLs.
+ // Register our global network handler for chrome:// URLs.
RegisterURLRequestChromeJob();
browser_process->InitBrokerServices(broker_services);
diff --git a/chrome/browser/browser_resources.h b/chrome/browser/browser_resources.h
index e4a31af..dd1fdd1 100644
--- a/chrome/browser/browser_resources.h
+++ b/chrome/browser/browser_resources.h
@@ -10,4 +10,5 @@
#define IDR_SAFE_BROWSING_MALWARE_BLOCK 209
#define IDR_SAFE_BROWSING_PHISHING_BLOCK 210
#define IDR_INCOGNITO_TAB_HTML 211
-#define IDR_CREDITS_HTML 212
+#define IDR_CREDITS_HTML 212
+#define IDR_HISTORY_HTML 213
diff --git a/chrome/browser/browser_resources.rc b/chrome/browser/browser_resources.rc
index 206bf4a..8ce4e17 100644
--- a/chrome/browser/browser_resources.rc
+++ b/chrome/browser/browser_resources.rc
@@ -28,4 +28,5 @@ IDR_NEW_TAB_HTML BINDATA "browser_resources\\new_tab_flat.html"
IDR_SAFE_BROWSING_MALWARE_BLOCK BINDATA "browser_resources\\safe_browsing_malware_block_flat.html"
IDR_SAFE_BROWSING_PHISHING_BLOCK BINDATA "browser_resources\\safe_browsing_phishing_block_flat.html"
IDR_INCOGNITO_TAB_HTML BINDATA "browser_resources\\incognito_tab_flat.html"
-IDR_CREDITS_HTML BINDATA "browser_resources\\about_credits_flat.html" \ No newline at end of file
+IDR_CREDITS_HTML BINDATA "browser_resources\\about_credits_flat.html"
+IDR_HISTORY_HTML BINDATA "browser_resources\\history_flat.html" \ No newline at end of file
diff --git a/chrome/browser/browser_url_handler.cc b/chrome/browser/browser_url_handler.cc
index 1b82105..555d065 100644
--- a/chrome/browser/browser_url_handler.cc
+++ b/chrome/browser/browser_url_handler.cc
@@ -6,6 +6,7 @@
#include "chrome/browser/browser_about_handler.h"
#include "chrome/browser/dom_ui/new_tab_ui.h"
+#include "chrome/browser/dom_ui/dom_ui_contents.h"
std::vector<BrowserURLHandler::URLHandler> BrowserURLHandler::url_handlers_;
@@ -17,8 +18,10 @@ void BrowserURLHandler::InitURLHandlers() {
// Here is where we initialize the global list of handlers for special URLs.
// about:*
url_handlers_.push_back(&BrowserAboutHandler::MaybeHandle);
- // chrome:*
+ // chrome-internal:*
url_handlers_.push_back(&NewTabUIHandleURL);
+ // chrome:*
+ url_handlers_.push_back(&DOMUIContentsCanHandleURL);
}
// static
diff --git a/chrome/browser/browsing_instance.cc b/chrome/browser/browsing_instance.cc
index 88c4088..542b4c0 100644
--- a/chrome/browser/browsing_instance.cc
+++ b/chrome/browser/browsing_instance.cc
@@ -27,7 +27,7 @@ bool BrowsingInstance::ShouldUseProcessPerSite(const GURL& url) {
// Note that --single-process may have been specified, but that affects the
// process creation logic in RenderProcessHost, so we do not need to worry
// about it here.
- if (url.SchemeIs("chrome-resource"))
+ if (url.SchemeIs("chrome"))
// Always consolidate instances of the new tab page (and instances of any
// other internal resource urls).
return true;
diff --git a/chrome/browser/debugger/debugger_contents.cc b/chrome/browser/debugger/debugger_contents.cc
index 37cb1d0..a6dd254 100644
--- a/chrome/browser/debugger/debugger_contents.cc
+++ b/chrome/browser/debugger/debugger_contents.cc
@@ -20,7 +20,7 @@ class DebuggerHTMLSource : public ChromeURLDataManager::DataSource {
public:
// Creates our datasource and sets our user message to a specific message
// from our string bundle.
- DebuggerHTMLSource()
+ DebuggerHTMLSource()
: DataSource("debugger", MessageLoop::current()) { }
// Called when the network layer has requested a resource underneath
@@ -38,7 +38,7 @@ class DebuggerHTMLSource : public ChromeURLDataManager::DataSource {
SendResponse(request_id, NULL);
return;
}
-
+
std::wstring debugger_path =
CommandLine().GetSwitchValue(switches::kJavaScriptDebuggerPath);
std::string data_str;
@@ -126,6 +126,6 @@ void DebuggerContents::AttachMessageHandlers() {
// static
bool DebuggerContents::IsDebuggerUrl(const GURL& url) {
- return (url.SchemeIs("chrome-resource") && url.host() == "inspector");
+ return (url.SchemeIs("chrome") && url.host() == "inspector");
}
diff --git a/chrome/browser/debugger/debugger_view.cc b/chrome/browser/debugger/debugger_view.cc
index 5fd62f1..530ffbf 100644
--- a/chrome/browser/debugger/debugger_view.cc
+++ b/chrome/browser/debugger/debugger_view.cc
@@ -105,8 +105,7 @@ void DebuggerView::OnInit() {
web_container_->SetTabContents(web_contents_);
web_contents_->render_view_host()->AllowDOMUIBindings();
- GURL contents("chrome-resource://inspector/debugger.html");
-
+ GURL contents("chrome://inspector/debugger.html");
web_contents_->controller()->LoadURL(contents, GURL(),
PageTransition::START_PAGE);
}
@@ -130,7 +129,7 @@ void DebuggerView::OpenURLFromTab(TabContents* source,
}
-void DebuggerView::SendEventToPage(const std::wstring& name,
+void DebuggerView::SendEventToPage(const std::wstring& name,
Value* body) {
DictionaryValue msg;
msg.SetString(L"type", L"event");
@@ -150,7 +149,7 @@ void DebuggerView::SendEventToPage(const std::wstring& name,
}
void DebuggerView::ExecuteJavascript(const std::string& js) {
- web_contents_->render_view_host()->ExecuteJavascriptInWebFrame(L"",
+ web_contents_->render_view_host()->ExecuteJavascriptInWebFrame(L"",
UTF8ToWide(js));
}
diff --git a/chrome/browser/dom_ui/chrome_url_data_manager.cc b/chrome/browser/dom_ui/chrome_url_data_manager.cc
index b82506a..623ad8d 100644
--- a/chrome/browser/dom_ui/chrome_url_data_manager.cc
+++ b/chrome/browser/dom_ui/chrome_url_data_manager.cc
@@ -24,8 +24,8 @@
#endif
// The URL scheme used for internal chrome resources.
-// This URL scheme is never needed by code external to this module.
-static const char kChromeURLScheme[] = "chrome-resource";
+// TODO(glen): Choose a better location for this.
+static const char kChromeURLScheme[] = "chrome";
// The single global instance of ChromeURLDataManager.
ChromeURLDataManager chrome_url_data_manager;
@@ -123,7 +123,7 @@ void ChromeURLDataManager::URLToRequest(const GURL& url,
return;
}
- // Our input looks like: chrome-resource://source_name/extra_bits?foo .
+ // Our input looks like: chrome://source_name/extra_bits?foo .
// So the url's "host" is our source, and everything after the host is
// the path.
source_name->assign(url.host());
diff --git a/chrome/browser/dom_ui/chrome_url_data_manager.h b/chrome/browser/dom_ui/chrome_url_data_manager.h
index 895ff46..102ab99 100644
--- a/chrome/browser/dom_ui/chrome_url_data_manager.h
+++ b/chrome/browser/dom_ui/chrome_url_data_manager.h
@@ -16,7 +16,7 @@ class MessageLoop;
class URLRequest;
class URLRequestJob;
-// To serve dynamic data off of chrome-resource: URLs, implement the
+// To serve dynamic data off of chrome: URLs, implement the
// ChromeURLDataManager::DataSource interface and register your handler
// with AddDataSource.
diff --git a/chrome/browser/dom_ui/dom_ui.cc b/chrome/browser/dom_ui/dom_ui.cc
new file mode 100644
index 0000000..4fe9070
--- /dev/null
+++ b/chrome/browser/dom_ui/dom_ui.cc
@@ -0,0 +1,124 @@
+// Copyright (c) 2006-2008 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/dom_ui/dom_ui.h"
+
+#include "base/json_reader.h"
+#include "base/json_writer.h"
+#include "chrome/common/l10n_util.h"
+
+///////////////////////////////////////////////////////////////////////////////
+// DOMMessageHandler
+
+DOMUI::DOMUI(DOMUIContents* contents) : contents_(contents) {
+}
+
+DOMUI::~DOMUI() {
+ STLDeleteContainerPairSecondPointers(message_callbacks_.begin(),
+ message_callbacks_.end());
+ STLDeleteContainerPointers(handlers_.begin(), handlers_.end());
+}
+
+// DOMUI, public: -------------------------------------------------------------
+
+void DOMUI::ProcessDOMUIMessage(const std::string& message,
+ const std::string& content) {
+ // Look up the callback for this message.
+ MessageCallbackMap::const_iterator callback =
+ message_callbacks_.find(message);
+ if (callback == message_callbacks_.end())
+ return;
+
+ // Convert the content JSON into a Value.
+ Value* value = NULL;
+ if (!content.empty()) {
+ if (!JSONReader::Read(content, &value, false)) {
+ // The page sent us something that we didn't understand.
+ // This probably indicates a programming error.
+ NOTREACHED();
+ return;
+ }
+ }
+
+ // Forward this message and content on.
+ callback->second->Run(value);
+ delete value;
+}
+
+void DOMUI::CallJavascriptFunction(const std::wstring& function_name,
+ const Value& arg) {
+ std::string json;
+ JSONWriter::Write(&arg, false, &json);
+ std::wstring javascript = function_name + L"(" + UTF8ToWide(json) + L");";
+
+ ExecuteJavascript(javascript);
+}
+
+void DOMUI::CallJavascriptFunction(
+ const std::wstring& function_name,
+ const Value& arg1, const Value& arg2) {
+ std::string json;
+ JSONWriter::Write(&arg1, false, &json);
+ std::wstring javascript = function_name + L"(" + UTF8ToWide(json);
+ JSONWriter::Write(&arg2, false, &json);
+ javascript += L"," + UTF8ToWide(json) + L");";
+
+ ExecuteJavascript(javascript);
+}
+
+void DOMUI::RegisterMessageCallback(const std::string &message,
+ MessageCallback *callback) {
+ message_callbacks_.insert(std::make_pair(message, callback));
+}
+
+// DOMUI, protected: ----------------------------------------------------------
+
+void DOMUI::AddMessageHandler(DOMMessageHandler* handler) {
+ handlers_.push_back(handler);
+}
+
+// DOMUI, private: ------------------------------------------------------------
+
+void DOMUI::ExecuteJavascript(const std::wstring& javascript) {
+ DCHECK(contents_);
+ contents_->render_view_host()->ExecuteJavascriptInWebFrame(std::wstring(),
+ javascript);
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// DOMMessageHandler
+
+DOMMessageHandler::DOMMessageHandler(DOMUI *dom_ui) : dom_ui_(dom_ui) {
+}
+
+// DOMMessageHandler, protected: ----------------------------------------------
+
+void DOMMessageHandler::SetURLAndTitle(DictionaryValue* dictionary,
+ std::wstring title,
+ const GURL& gurl) {
+ std::wstring wstring_url = UTF8ToWide(gurl.spec());
+ dictionary->SetString(L"url", wstring_url);
+
+ bool using_url_as_the_title = false;
+ if (title.empty()) {
+ using_url_as_the_title = true;
+ title = wstring_url;
+ }
+
+ // Since the title can contain BiDi text, we need to mark the text as either
+ // RTL or LTR, depending on the characters in the string. If we use the URL
+ // as the title, we mark the title as LTR since URLs are always treated as
+ // left to right strings.
+ std::wstring title_to_set(title);
+ if (l10n_util::GetTextDirection() == l10n_util::RIGHT_TO_LEFT) {
+ if (using_url_as_the_title) {
+ l10n_util::WrapStringWithLTRFormatting(&title_to_set);
+ } else {
+ bool success =
+ l10n_util::AdjustStringForLocaleDirection(title, &title_to_set);
+ DCHECK(success ? (title != title_to_set) : (title == title_to_set));
+ }
+ }
+ dictionary->SetString(L"title", title_to_set);
+} \ No newline at end of file
diff --git a/chrome/browser/dom_ui/dom_ui.h b/chrome/browser/dom_ui/dom_ui.h
new file mode 100644
index 0000000..7b0b446
--- /dev/null
+++ b/chrome/browser/dom_ui/dom_ui.h
@@ -0,0 +1,86 @@
+// Copyright (c) 2006-2008 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_DOM_UI_H__
+#define CHROME_BROWSER_DOM_UI_H__
+
+#include "base/task.h"
+#include "chrome/browser/dom_ui/dom_ui_contents.h"
+
+class Value;
+class DOMMessageHandler;
+
+// A DOMUI sets up the datasources and message handlers for a given HTML-based
+// UI. It is contained by a DOMUIContents.
+class DOMUI {
+ public:
+ DOMUI(DOMUIContents* contents);
+
+ virtual ~DOMUI();
+ virtual void Init() = 0;
+
+ // Called from DOMUIContents.
+ void ProcessDOMUIMessage(const std::string& message,
+ const std::string& content);
+
+ // Used by DOMMessageHandlers.
+ typedef Callback1<const Value*>::Type MessageCallback;
+ void RegisterMessageCallback (const std::string& message,
+ MessageCallback* callback);
+
+ // Call a Javascript function by sending its name and arguments down to
+ // the renderer. This is asynchronous; there's no way to get the result
+ // of the call, and should be thought of more like sending a message to
+ // the page.
+ // There are two function variants for one-arg and two-arg calls.
+ void CallJavascriptFunction(const std::wstring& function_name,
+ const Value& arg);
+ void CallJavascriptFunction(const std::wstring& function_name,
+ const Value& arg1,
+ const Value& arg2);
+
+ Profile* get_profile() { return contents_->profile(); }
+
+ protected:
+ void AddMessageHandler(DOMMessageHandler* handler);
+
+ DOMUIContents* contents_;
+
+ private:
+ // Execute a string of raw Javascript on the page.
+ void ExecuteJavascript(const std::wstring& javascript);
+
+ // The DOMMessageHandlers we own.
+ std::vector<DOMMessageHandler*> handlers_;
+
+ // A map of message name -> message handling callback.
+ typedef std::map<std::string, MessageCallback*> MessageCallbackMap;
+ MessageCallbackMap message_callbacks_;
+
+ DISALLOW_COPY_AND_ASSIGN(DOMUI);
+};
+
+// Messages sent from the DOM are forwarded via the DOMUIContents to handler
+// classes. These objects are owned by DOMUIHost and destroyed when the
+// host is destroyed.
+class DOMMessageHandler {
+ public:
+ explicit DOMMessageHandler(DOMUI* dom_ui);
+ virtual ~DOMMessageHandler();
+
+ protected:
+ // Adds "url" and "title" keys on incoming dictionary, setting title
+ // as the url as a fallback on empty title.
+ static void SetURLAndTitle(DictionaryValue* dictionary,
+ std::wstring title,
+ const GURL& gurl);
+
+ DOMUI* const dom_ui_;
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(DOMMessageHandler);
+};
+
+
+#endif // CHROME_BROWSER_DOM_UI_H__ \ No newline at end of file
diff --git a/chrome/browser/dom_ui/dom_ui_contents.cc b/chrome/browser/dom_ui/dom_ui_contents.cc
new file mode 100644
index 0000000..260c68f
--- /dev/null
+++ b/chrome/browser/dom_ui/dom_ui_contents.cc
@@ -0,0 +1,207 @@
+// Copyright (c) 2006-2008 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/dom_ui/dom_ui_contents.h"
+
+#include "chrome/browser/dom_ui/dom_ui.h"
+#include "chrome/browser/dom_ui/history_ui.h"
+#include "chrome/browser/navigation_entry.h"
+#include "chrome/browser/render_view_host.h"
+#include "chrome/common/resource_bundle.h"
+
+// The scheme used for DOMUIContentses
+// TODO(glen): Merge this with the scheme in chrome_url_data_manager
+static const char kURLScheme[] = "chrome";
+
+// The path used in internal URLs to thumbnail data.
+static const char kThumbnailPath[] = "thumb";
+
+// The path used in internal URLs to favicon data.
+static const char kFavIconPath[] = "favicon";
+
+///////////////////////////////////////////////////////////////////////////////
+// FavIconSource
+
+FavIconSource::FavIconSource(Profile* profile)
+ : DataSource(kFavIconPath, MessageLoop::current()), profile_(profile) {}
+
+void FavIconSource::StartDataRequest(const std::string& path, int request_id) {
+ HistoryService* hs = profile_->GetHistoryService(Profile::EXPLICIT_ACCESS);
+ if (hs) {
+ HistoryService::Handle handle;
+ if (path.size() > 8 && path.substr(0, 8) == "iconurl/") {
+ handle = hs->GetFavIcon(
+ GURL(path.substr(8)),
+ &cancelable_consumer_,
+ NewCallback(this, &FavIconSource::OnFavIconDataAvailable));
+ } else {
+ handle = hs->GetFavIconForURL(
+ GURL(path),
+ &cancelable_consumer_,
+ NewCallback(this, &FavIconSource::OnFavIconDataAvailable));
+ }
+ // Attach the ChromeURLDataManager request ID to the history request.
+ cancelable_consumer_.SetClientData(hs, handle, request_id);
+ } else {
+ SendResponse(request_id, NULL);
+ }
+}
+
+void FavIconSource::OnFavIconDataAvailable(
+ HistoryService::Handle request_handle,
+ bool know_favicon,
+ scoped_refptr<RefCountedBytes> data,
+ bool expired,
+ GURL icon_url) {
+ HistoryService* hs =
+ profile_->GetHistoryService(Profile::EXPLICIT_ACCESS);
+ int request_id = cancelable_consumer_.GetClientData(hs, request_handle);
+
+ if (know_favicon && data.get() && !data->data.empty()) {
+ // Forward the data along to the networking system.
+ SendResponse(request_id, data);
+ } else {
+ if (!default_favicon_.get()) {
+ default_favicon_ = new RefCountedBytes;
+ ResourceBundle::GetSharedInstance().LoadImageResourceBytes(
+ IDR_DEFAULT_FAVICON, &default_favicon_->data);
+ }
+
+ SendResponse(request_id, default_favicon_);
+ }
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// ThumbnailSource
+
+ThumbnailSource::ThumbnailSource(Profile* profile)
+ : DataSource(kThumbnailPath, MessageLoop::current()), profile_(profile) {}
+
+void ThumbnailSource::StartDataRequest(const std::string& path,
+ int request_id) {
+ HistoryService* hs = profile_->GetHistoryService(Profile::EXPLICIT_ACCESS);
+ if (hs) {
+ HistoryService::Handle handle = hs->GetPageThumbnail(
+ GURL(path),
+ &cancelable_consumer_,
+ NewCallback(this, &ThumbnailSource::OnThumbnailDataAvailable));
+ // Attach the ChromeURLDataManager request ID to the history request.
+ cancelable_consumer_.SetClientData(hs, handle, request_id);
+ } else {
+ // Tell the caller that no thumbnail is available.
+ SendResponse(request_id, NULL);
+ }
+}
+
+void ThumbnailSource::OnThumbnailDataAvailable(
+ HistoryService::Handle request_handle,
+ scoped_refptr<RefCountedBytes> data) {
+ HistoryService* hs =
+ profile_->GetHistoryService(Profile::EXPLICIT_ACCESS);
+ int request_id = cancelable_consumer_.GetClientData(hs, request_handle);
+ // Forward the data along to the networking system.
+ if (data.get() && !data->data.empty()) {
+ SendResponse(request_id, data);
+ } else {
+ if (!default_thumbnail_.get()) {
+ default_thumbnail_ = new RefCountedBytes;
+ ResourceBundle::GetSharedInstance().LoadImageResourceBytes(
+ IDR_DEFAULT_THUMBNAIL, &default_thumbnail_->data);
+ }
+
+ SendResponse(request_id, default_thumbnail_);
+ }
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// DOMUIContents
+
+// This is the top-level URL handler for chrome: URLs, and exposed in
+// our header file. The individual DOMUIs provide a chrome:
+// HTML source at the same host/path.
+bool DOMUIContentsCanHandleURL(GURL* url,
+ TabContentsType* result_type) {
+ if (!url->SchemeIs(kURLScheme))
+ return false;
+
+ // TODO: remove once the debugger is using DOMContentsUI
+ if (url->host().compare("debugger") == 0)
+ return false;
+
+ *result_type = TAB_CONTENTS_DOM_UI;
+ return true;
+}
+
+DOMUIContents::DOMUIContents(Profile* profile,
+ SiteInstance* instance,
+ RenderViewHostFactory* render_view_factory)
+ : WebContents(profile,
+ instance,
+ render_view_factory,
+ MSG_ROUTING_NONE,
+ NULL),
+ current_ui_(NULL) {
+ set_type(TAB_CONTENTS_DOM_UI);
+}
+
+DOMUIContents::~DOMUIContents() {
+ if (current_ui_)
+ delete current_ui_;
+}
+
+bool DOMUIContents::CreateRenderViewForRenderManager(
+ RenderViewHost* render_view_host) {
+ // Be sure to enable DOM UI bindings on the RenderViewHost before
+ // CreateRenderView is called. Since a cross-site transition may be
+ // involved, this may or may not be the same RenderViewHost that we had when
+ // we were created.
+ render_view_host->AllowDOMUIBindings();
+ return WebContents::CreateRenderViewForRenderManager(render_view_host);
+}
+
+WebPreferences DOMUIContents::GetWebkitPrefs() {
+ // Get the users preferences then force image loading to always be on.
+ WebPreferences web_prefs = WebContents::GetWebkitPrefs();
+ web_prefs.loads_images_automatically = true;
+ web_prefs.javascript_enabled = true;
+
+ return web_prefs;
+}
+
+bool DOMUIContents::NavigateToPendingEntry(bool reload) {
+ if (current_ui_) {
+ // Shut down our existing DOMUI.
+ delete current_ui_;
+ current_ui_ = NULL;
+ }
+
+ // Set up a new DOMUI.
+ NavigationEntry* pending_entry = controller()->GetPendingEntry();
+ current_ui_ = GetDOMUIForURL(pending_entry->url());
+ if (current_ui_)
+ current_ui_->Init();
+ else
+ return false;
+
+ // Let WebContents do whatever it's meant to do.
+ return WebContents::NavigateToPendingEntry(reload);
+}
+
+DOMUI* DOMUIContents::GetDOMUIForURL(const GURL &url) {
+ if (url.host() == HistoryUI::GetBaseURL().host())
+ return new HistoryUI(this);
+
+ return NULL;
+}
+
+void DOMUIContents::ProcessDOMUIMessage(const std::string& message,
+ const std::string& content) {
+ DCHECK(current_ui_);
+ current_ui_->ProcessDOMUIMessage(message, content);
+}
+
+// static
+const std::string DOMUIContents::GetScheme() {
+ return kURLScheme;
+} \ No newline at end of file
diff --git a/chrome/browser/dom_ui/dom_ui_contents.h b/chrome/browser/dom_ui/dom_ui_contents.h
new file mode 100644
index 0000000..c347c07
--- /dev/null
+++ b/chrome/browser/dom_ui/dom_ui_contents.h
@@ -0,0 +1,123 @@
+// Copyright (c) 2006-2008 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.
+
+// Contains code for managing local HTML UI at chrome:// URLs.
+
+#ifndef CHROME_BROWSER_DOM_UI_CONTENTS_H__
+#define CHROME_BROWSER_DOM_UI_CONTENTS_H__
+
+#include "chrome/browser/dom_ui/chrome_url_data_manager.h"
+#include "chrome/browser/web_contents.h"
+#include "webkit/glue/webpreferences.h"
+
+class DOMUI;
+class render_view_host;
+
+// FavIconSource is the gateway between network-level chrome:
+// requests for favicons and the history backend that serves these.
+class FavIconSource : public ChromeURLDataManager::DataSource {
+ public:
+ explicit FavIconSource(Profile* profile);
+
+ // Called when the network layer has requested a resource underneath
+ // the path we registered.
+ virtual void StartDataRequest(const std::string& path, int request_id);
+
+ virtual std::string GetMimeType(const std::string&) const {
+ // Rely on image decoder inferring the correct type.
+ return std::string();
+ }
+
+ // Called when favicon data is available from the history backend.
+ void OnFavIconDataAvailable(
+ HistoryService::Handle request_handle,
+ bool know_favicon,
+ scoped_refptr<RefCountedBytes> data,
+ bool expired,
+ GURL url);
+
+ private:
+ Profile* const profile_;
+ CancelableRequestConsumerT<int, 0> cancelable_consumer_;
+
+ // Raw PNG representation of the favicon to show when the favicon
+ // database doesn't have a favicon for a webpage.
+ scoped_refptr<RefCountedBytes> default_favicon_;
+
+ DISALLOW_COPY_AND_ASSIGN(FavIconSource);
+};
+
+// ThumbnailSource is the gateway between network-level chrome:
+// requests for thumbnails and the history backend that serves these.
+class ThumbnailSource : public ChromeURLDataManager::DataSource {
+ public:
+ explicit ThumbnailSource(Profile* profile);
+
+ // Called when the network layer has requested a resource underneath
+ // the path we registered.
+ virtual void StartDataRequest(const std::string& path, int request_id);
+
+ virtual std::string GetMimeType(const std::string&) const {
+ // Rely on image decoder inferring the correct type.
+ return std::string();
+ }
+
+ // Called when thumbnail data is available from the history backend.
+ void OnThumbnailDataAvailable(
+ HistoryService::Handle request_handle,
+ scoped_refptr<RefCountedBytes> data);
+
+ private:
+ Profile* const profile_;
+ CancelableRequestConsumerT<int, 0> cancelable_consumer_;
+
+ // Raw PNG representation of the thumbnail to show when the thumbnail
+ // database doesn't have a thumbnail for a webpage.
+ scoped_refptr<RefCountedBytes> default_thumbnail_;
+
+ DISALLOW_COPY_AND_ASSIGN(ThumbnailSource);
+};
+
+// Exposed for use by BrowserURLHandler.
+bool DOMUIContentsCanHandleURL(GURL* url, TabContentsType* result_type);
+
+class DOMUIContents : public WebContents {
+ public:
+ DOMUIContents(Profile* profile,
+ SiteInstance* instance,
+ RenderViewHostFactory* render_view_factory);
+ ~DOMUIContents();
+
+ //
+ // WebContents overrides
+ //
+ virtual void ProcessDOMUIMessage(const std::string& message,
+ const std::string& content);
+ virtual bool CreateRenderViewForRenderManager(
+ RenderViewHost* render_view_host);
+ // Override this method so we can ensure that javascript and image loading
+ // are always on even for DOMUIHost tabs.
+ virtual WebPreferences GetWebkitPrefs();
+
+ //
+ // TabContents overrides
+ //
+ virtual void UpdateHistoryForNavigation(const GURL& url,
+ const ViewHostMsg_FrameNavigate_Params& params) { }
+ virtual bool NavigateToPendingEntry(bool reload);
+
+ // Return the scheme used. We currently use chrome:
+ static const std::string GetScheme();
+
+ private:
+ // Return a DOM UI for the provided URL.
+ DOMUI* GetDOMUIForURL(const GURL& url);
+
+ // The DOMUI we own and show.
+ DOMUI* current_ui_;
+
+ DISALLOW_COPY_AND_ASSIGN(DOMUIContents);
+};
+
+#endif // CHROME_BROWSER_DOM_UI_CONTENTS_H__ \ No newline at end of file
diff --git a/chrome/browser/dom_ui/history_ui.cc b/chrome/browser/dom_ui/history_ui.cc
new file mode 100644
index 0000000..370417d
--- /dev/null
+++ b/chrome/browser/dom_ui/history_ui.cc
@@ -0,0 +1,303 @@
+// Copyright (c) 2006-2008 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/dom_ui/history_ui.h"
+
+#include "base/message_loop.h"
+#include "base/string_piece.h"
+#include "base/thread.h"
+#include "base/time.h"
+#include "base/time_format.h"
+#include "chrome/browser/browser_process.h"
+#include "chrome/browser/browser_resources.h"
+#include "chrome/browser/history/history_types.h"
+#include "chrome/browser/profile.h"
+#include "chrome/browser/user_metrics.h"
+#include "chrome/common/jstemplate_builder.h"
+#include "chrome/common/l10n_util.h"
+#include "chrome/common/resource_bundle.h"
+#include "chrome/common/time_format.h"
+
+#include "chromium_strings.h"
+#include "generated_resources.h"
+
+using base::Time;
+
+// HistoryUI is accessible from chrome://history, and the raw HTML is
+// accessed from chrome://history.
+static const std::string kHistoryHost = "history";
+
+// Maximum number of search results to return in a given search. We should
+// eventually remove this.
+static const int kMaxSearchResults = 100;
+
+////////////////////////////////////////////////////////////////////////////////
+//
+// HistoryHTMLSource
+//
+////////////////////////////////////////////////////////////////////////////////
+
+HistoryUIHTMLSource::HistoryUIHTMLSource()
+ : DataSource(kHistoryHost, MessageLoop::current()) {
+}
+
+void HistoryUIHTMLSource::StartDataRequest(const std::string& path,
+ int request_id) {
+ DictionaryValue localized_strings;
+ localized_strings.SetString(L"title",
+ l10n_util::GetString(IDS_HISTORY_TITLE));
+ localized_strings.SetString(L"loading",
+ l10n_util::GetString(IDS_HISTORY_LOADING));
+ localized_strings.SetString(L"newest",
+ l10n_util::GetString(IDS_HISTORY_NEWEST));
+ localized_strings.SetString(L"newer",
+ l10n_util::GetString(IDS_HISTORY_NEWER));
+ localized_strings.SetString(L"older",
+ l10n_util::GetString(IDS_HISTORY_OLDER));
+ localized_strings.SetString(L"searchresultsfor",
+ l10n_util::GetString(IDS_HISTORY_SEARCHRESULTSFOR));
+ localized_strings.SetString(L"history",
+ l10n_util::GetString(IDS_HISTORY_BROWSERESULTS));
+ localized_strings.SetString(L"cont",
+ l10n_util::GetString(IDS_HISTORY_CONTINUED));
+ localized_strings.SetString(L"searchbutton",
+ l10n_util::GetString(IDS_HISTORY_SEARCH_BUTTON));
+ localized_strings.SetString(L"noresults",
+ l10n_util::GetString(IDS_HISTORY_NO_RESULTS));
+ localized_strings.SetString(L"noitems",
+ l10n_util::GetString(IDS_HISTORY_NO_ITEMS));
+ localized_strings.SetString(L"delete",
+ l10n_util::GetString(IDS_HISTORY_DELETE));
+
+ static const StringPiece history_html(
+ ResourceBundle::GetSharedInstance().GetRawDataResource(
+ IDR_HISTORY_HTML));
+ const std::string full_html = jstemplate_builder::GetTemplateHtml(
+ history_html, &localized_strings, "t");
+
+ scoped_refptr<RefCountedBytes> html_bytes(new RefCountedBytes);
+ html_bytes->data.resize(full_html.size());
+ std::copy(full_html.begin(), full_html.end(), html_bytes->data.begin());
+
+ SendResponse(request_id, html_bytes);
+}
+
+////////////////////////////////////////////////////////////////////////////////
+//
+// HistoryHandler
+//
+////////////////////////////////////////////////////////////////////////////////
+BrowsingHistoryHandler::BrowsingHistoryHandler(DOMUI* dom_ui)
+ : DOMMessageHandler(dom_ui),
+ search_text_() {
+ dom_ui_->RegisterMessageCallback("getHistory",
+ NewCallback(this, &BrowsingHistoryHandler::HandleGetHistory));
+
+ // Create our favicon data source.
+ g_browser_process->io_thread()->message_loop()->PostTask(FROM_HERE,
+ NewRunnableMethod(&chrome_url_data_manager,
+ &ChromeURLDataManager::AddDataSource,
+ new FavIconSource(dom_ui_->get_profile())));
+
+ // Get notifications when history is cleared.
+ NotificationService* service = NotificationService::current();
+ service->AddObserver(this, NOTIFY_HISTORY_URLS_DELETED,
+ Source<Profile>(dom_ui_->get_profile()));
+}
+
+BrowsingHistoryHandler::~BrowsingHistoryHandler() {
+ NotificationService* service = NotificationService::current();
+ service->RemoveObserver(this, NOTIFY_HISTORY_URLS_DELETED,
+ Source<Profile>(dom_ui_->get_profile()));
+}
+
+void BrowsingHistoryHandler::HandleGetHistory(const Value* value) {
+ // Anything in-flight is invalid.
+ cancelable_consumer_.CancelAllRequests();
+
+ // Get arguments (if any).
+ int month;
+ std::wstring query;
+ ExtractGetHistoryArguments(value, &month, &query);
+
+ // Set our query options.
+ history::QueryOptions options = CreateQueryOptions(month, query);
+
+ // Need to remember the query string for our results.
+ search_text_ = query;
+ HistoryService* hs =
+ dom_ui_->get_profile()->GetHistoryService(Profile::EXPLICIT_ACCESS);
+ hs->QueryHistory(search_text_,
+ options,
+ &cancelable_consumer_,
+ NewCallback(this, &BrowsingHistoryHandler::QueryComplete));
+}
+
+void BrowsingHistoryHandler::QueryComplete(
+ HistoryService::Handle request_handle,
+ history::QueryResults* results) {
+
+ ListValue results_value;
+ Time midnight_today = Time::Now().LocalMidnight();
+
+ for (size_t i = 0; i < results->size(); ++i) {
+ history::URLResult const &page = (*results)[i];
+ DictionaryValue* page_value = new DictionaryValue();
+ SetURLAndTitle(page_value, page.title(), page.url());
+
+ // Need to pass the time in epoch time (fastest JS conversion).
+ page_value->SetInteger(L"time",
+ static_cast<int>(page.visit_time().ToTimeT()));
+
+ // Until we get some JS i18n infrastructure, we also need to
+ // pass the dates in as strings. This could use some
+ // optimization.
+
+ // Only pass in the strings we need (search results need a shortdate
+ // and snippet, browse results need day and time information).
+ if (search_text_.empty()) {
+ // Figure out the relative date string.
+ std::wstring date_str = TimeFormat::RelativeDate(page.visit_time(),
+ &midnight_today);
+ if (date_str.empty()) {
+ date_str = base::TimeFormatFriendlyDate(page.visit_time());
+ } else {
+ date_str = l10n_util::GetStringF(
+ IDS_HISTORY_DATE_WITH_RELATIVE_TIME,
+ date_str, base::TimeFormatFriendlyDate(page.visit_time()));
+ }
+ page_value->SetString(L"dateRelativeDay", date_str);
+ page_value->SetString(L"dateTimeOfDay",
+ base::TimeFormatTimeOfDay(page.visit_time()));
+ } else {
+ page_value->SetString(L"dateShort",
+ base::TimeFormatShortDate(page.visit_time()));
+ page_value->SetString(L"snippet", page.snippet().text());
+ }
+
+ results_value.Append(page_value);
+ }
+
+ dom_ui_->CallJavascriptFunction(L"historyResult",
+ StringValue(search_text_), results_value);
+}
+
+void BrowsingHistoryHandler::ExtractGetHistoryArguments(const Value* value,
+ int* month, std::wstring* query) {
+ *month = 0;
+
+ if (value && value->GetType() == Value::TYPE_LIST) {
+ const ListValue* list_value = static_cast<const ListValue*>(value);
+ Value* list_member;
+
+ // Get search string.
+ if (list_value->Get(0, &list_member) &&
+ list_member->GetType() == Value::TYPE_STRING) {
+ const StringValue* string_value =
+ static_cast<const StringValue*>(list_member);
+ string_value->GetAsString(query);
+ }
+
+ // Get search month.
+ if (list_value->Get(1, &list_member) &&
+ list_member->GetType() == Value::TYPE_STRING) {
+ const StringValue* string_value =
+ static_cast<const StringValue*>(list_member);
+ std::wstring wstring_value;
+ string_value->GetAsString(&wstring_value);
+ *month = _wtoi(wstring_value.c_str());
+ }
+ }
+}
+
+history::QueryOptions BrowsingHistoryHandler::CreateQueryOptions(int month,
+ const std::wstring& query) {
+ history::QueryOptions options;
+
+ // Configure the begin point of the search to the start of the
+ // current month.
+ Time::Exploded exploded;
+ Time::Now().LocalMidnight().LocalExplode(&exploded);
+ exploded.day_of_month = 1;
+
+ if (month == 0) {
+ options.begin_time = Time::FromLocalExploded(exploded);
+
+ // Set the end time of this first search to null (which will
+ // show results from the future, should the user's clock have
+ // been set incorrectly).
+ options.end_time = Time();
+ } else {
+ // Set the end-time of this search to the end of the month that is
+ // |depth| months before the search end point. The end time is not
+ // inclusive, so we should feel free to set it to midnight on the
+ // first day of the following month.
+ exploded.month -= month - 1;
+ while (exploded.month < 1) {
+ exploded.month += 12;
+ exploded.year--;
+ }
+ options.end_time = Time::FromLocalExploded(exploded);
+
+ // Set the begin-time of the search to the start of the month
+ // that is |depth| months prior to search_start_.
+ if (exploded.month > 1) {
+ exploded.month--;
+ } else {
+ exploded.month = 12;
+ exploded.year--;
+ }
+ options.begin_time = Time::FromLocalExploded(exploded);
+ }
+
+ // If searching, only show the most recent entry and limit the number of
+ // results returned.
+ if (!query.empty()) {
+ options.max_count = kMaxSearchResults;
+ options.most_recent_visit_only = true;
+ }
+
+ return options;
+}
+
+void BrowsingHistoryHandler::Observe(NotificationType type,
+ const NotificationSource& source,
+ const NotificationDetails& details) {
+ if (type != NOTIFY_HISTORY_URLS_DELETED) {
+ NOTREACHED();
+ return;
+ }
+
+ // Some URLs were deleted from history. Reload the most visited list.
+ HandleGetHistory(NULL);
+}
+
+////////////////////////////////////////////////////////////////////////////////
+//
+// HistoryUIContents
+//
+////////////////////////////////////////////////////////////////////////////////
+
+HistoryUI::HistoryUI(DOMUIContents* contents) : DOMUI(contents) {
+}
+
+void HistoryUI::Init() {
+ AddMessageHandler(new BrowsingHistoryHandler(this));
+
+ HistoryUIHTMLSource* html_source = new HistoryUIHTMLSource();
+
+ // Set up the chrome://history/ source.
+ g_browser_process->io_thread()->message_loop()->PostTask(FROM_HERE,
+ NewRunnableMethod(&chrome_url_data_manager,
+ &ChromeURLDataManager::AddDataSource,
+ html_source));
+}
+
+// static
+GURL HistoryUI::GetBaseURL() {
+ std::string url = DOMUIContents::GetScheme();
+ url += "://";
+ url += kHistoryHost;
+ return GURL(url);
+} \ No newline at end of file
diff --git a/chrome/browser/dom_ui/history_ui.h b/chrome/browser/dom_ui/history_ui.h
new file mode 100644
index 0000000..742cf81
--- /dev/null
+++ b/chrome/browser/dom_ui/history_ui.h
@@ -0,0 +1,83 @@
+// Copyright (c) 2006-2008 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_DOM_UI_HISTORY_UI_H__
+#define CHROME_BROWSER_DOM_UI_HISTORY_UI_H__
+
+#include "chrome/browser/dom_ui/chrome_url_data_manager.h"
+#include "chrome/browser/dom_ui/dom_ui.h"
+#include "chrome/browser/dom_ui/dom_ui_contents.h"
+
+class GURL;
+
+class HistoryUIHTMLSource : public ChromeURLDataManager::DataSource {
+ public:
+ HistoryUIHTMLSource();
+
+ // Called when the network layer has requested a resource underneath
+ // the path we registered.
+ virtual void StartDataRequest(const std::string& path, int request_id);
+ virtual std::string GetMimeType(const std::string&) const {
+ return "text/html";
+ }
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(HistoryUIHTMLSource);
+};
+
+// The handler for Javascript messages related to the "history" view.
+class BrowsingHistoryHandler : public DOMMessageHandler,
+ public NotificationObserver {
+ public:
+ explicit BrowsingHistoryHandler(DOMUI* dom_ui_);
+ virtual ~BrowsingHistoryHandler();
+
+ // Callback for the "getHistory" message.
+ void HandleGetHistory(const Value* value);
+
+ // NotificationObserver implementation.
+ virtual void Observe(NotificationType type,
+ const NotificationSource& source,
+ const NotificationDetails& details);
+
+ private:
+ // Callback from the history system when the most visited list is available.
+ void QueryComplete(HistoryService::Handle request_handle,
+ history::QueryResults* results);
+
+ // Extract the arguments from the call to HandleGetHistory.
+ void ExtractGetHistoryArguments(const Value* value,
+ int* month,
+ std::wstring* query);
+
+ // Get the query options for a given month and query.
+ history::QueryOptions CreateQueryOptions(int month,
+ const std::wstring& query);
+
+ // Current search text.
+ std::wstring search_text_;
+
+ // Our consumer for the history service.
+ CancelableRequestConsumerT<PageUsageData*, NULL> cancelable_consumer_;
+
+ DISALLOW_COPY_AND_ASSIGN(BrowsingHistoryHandler);
+};
+
+class HistoryUI : public DOMUI {
+ public:
+ explicit HistoryUI(DOMUIContents* contents);
+
+ // Return the URL for the front page of this UI.
+ static GURL GetBaseURL();
+
+ // DOMUI Implementation
+ virtual void Init();
+
+ private:
+ DOMUIContents* contents_;
+
+ DISALLOW_COPY_AND_ASSIGN(HistoryUI);
+};
+
+#endif // CHROME_BROWSER_DOM_UI_HISTORY_UI_H__ \ No newline at end of file
diff --git a/chrome/browser/dom_ui/new_tab_ui.cc b/chrome/browser/dom_ui/new_tab_ui.cc
index 1775e1e..7d1aa82 100644
--- a/chrome/browser/dom_ui/new_tab_ui.cc
+++ b/chrome/browser/dom_ui/new_tab_ui.cc
@@ -10,6 +10,7 @@
#include "chrome/browser/browser.h"
#include "chrome/browser/browser_process.h"
#include "chrome/browser/browser_resources.h"
+#include "chrome/browser/dom_ui/dom_ui_contents.h"
#include "chrome/browser/history_tab_ui.h"
#include "chrome/browser/history/page_usage_data.h"
#include "chrome/browser/navigation_entry.h"
@@ -36,12 +37,6 @@ using base::TimeTicks;
// The URL scheme used for the new tab.
static const char kNewTabUIScheme[] = "chrome-internal";
-// The path used in internal URLs to thumbnail data.
-static const char kThumbnailPath[] = "thumb";
-
-// The path used in internal URLs to favicon data.
-static const char kFavIconPath[] = "favicon";
-
// The number of most visited pages we show.
const int kMostVisitedPages = 9;
@@ -263,101 +258,6 @@ void IncognitoTabHTMLSource::StartDataRequest(const std::string& path,
}
///////////////////////////////////////////////////////////////////////////////
-// ThumbnailSource
-
-ThumbnailSource::ThumbnailSource(Profile* profile)
- : DataSource(kThumbnailPath, MessageLoop::current()), profile_(profile) {}
-
-void ThumbnailSource::StartDataRequest(const std::string& path,
- int request_id) {
- HistoryService* hs = profile_->GetHistoryService(Profile::EXPLICIT_ACCESS);
- if (hs) {
- HistoryService::Handle handle = hs->GetPageThumbnail(
- GURL(path),
- &cancelable_consumer_,
- NewCallback(this, &ThumbnailSource::OnThumbnailDataAvailable));
- // Attach the ChromeURLDataManager request ID to the history request.
- cancelable_consumer_.SetClientData(hs, handle, request_id);
- } else {
- // Tell the caller that no thumbnail is available.
- SendResponse(request_id, NULL);
- }
-}
-
-void ThumbnailSource::OnThumbnailDataAvailable(
- HistoryService::Handle request_handle,
- scoped_refptr<RefCountedBytes> data) {
- HistoryService* hs =
- profile_->GetHistoryService(Profile::EXPLICIT_ACCESS);
- int request_id = cancelable_consumer_.GetClientData(hs, request_handle);
- // Forward the data along to the networking system.
- if (data.get() && !data->data.empty()) {
- SendResponse(request_id, data);
- } else {
- if (!default_thumbnail_.get()) {
- default_thumbnail_ = new RefCountedBytes;
- ResourceBundle::GetSharedInstance().LoadImageResourceBytes(
- IDR_DEFAULT_THUMBNAIL, &default_thumbnail_->data);
- }
-
- SendResponse(request_id, default_thumbnail_);
- }
-}
-
-///////////////////////////////////////////////////////////////////////////////
-// FavIconSource
-
-FavIconSource::FavIconSource(Profile* profile)
- : DataSource(kFavIconPath, MessageLoop::current()), profile_(profile) {}
-
-void FavIconSource::StartDataRequest(const std::string& path, int request_id) {
- HistoryService* hs = profile_->GetHistoryService(Profile::EXPLICIT_ACCESS);
- if (hs) {
- HistoryService::Handle handle;
- if (path.size() > 8 && path.substr(0, 8) == "iconurl/") {
- handle = hs->GetFavIcon(
- GURL(path.substr(8)),
- &cancelable_consumer_,
- NewCallback(this, &FavIconSource::OnFavIconDataAvailable));
- } else {
- handle = hs->GetFavIconForURL(
- GURL(path),
- &cancelable_consumer_,
- NewCallback(this, &FavIconSource::OnFavIconDataAvailable));
- }
- // Attach the ChromeURLDataManager request ID to the history request.
- cancelable_consumer_.SetClientData(hs, handle, request_id);
- } else {
- SendResponse(request_id, NULL);
- }
-}
-
-void FavIconSource::OnFavIconDataAvailable(
- HistoryService::Handle request_handle,
- bool know_favicon,
- scoped_refptr<RefCountedBytes> data,
- bool expired,
- GURL icon_url) {
- HistoryService* hs =
- profile_->GetHistoryService(Profile::EXPLICIT_ACCESS);
- int request_id = cancelable_consumer_.GetClientData(hs, request_handle);
-
- if (know_favicon && data.get() && !data->data.empty()) {
- // Forward the data along to the networking system.
- SendResponse(request_id, data);
- } else {
- if (!default_favicon_.get()) {
- default_favicon_ = new RefCountedBytes;
- ResourceBundle::GetSharedInstance().LoadImageResourceBytes(
- IDR_DEFAULT_FAVICON, &default_favicon_->data);
- }
-
- SendResponse(request_id, default_favicon_);
- }
-}
-
-
-///////////////////////////////////////////////////////////////////////////////
// MostVisitedHandler
MostVisitedHandler::MostVisitedHandler(DOMUIHost* dom_ui_host)
@@ -847,7 +747,7 @@ bool NewTabUIHandleURL(GURL* url,
return false;
*result_type = TAB_CONTENTS_NEW_TAB_UI;
- *url = GURL("chrome-resource://new-tab/");
+ *url = GURL(DOMUIContents::GetScheme() + "://new-tab/");
return true;
}
diff --git a/chrome/browser/dom_ui/new_tab_ui.h b/chrome/browser/dom_ui/new_tab_ui.h
index 4995b4d..8f700b2 100644
--- a/chrome/browser/dom_ui/new_tab_ui.h
+++ b/chrome/browser/dom_ui/new_tab_ui.h
@@ -20,9 +20,9 @@ enum TabContentsType;
// Return the URL for the new tab page.
GURL NewTabUIURL();
-// If a |url| is a chrome: URL, this method sets up |url|, and |result_type|
-// to the appropriate values for displaying the new tab page and returns true.
-// Exposed for use by BrowserURLHandler.
+// If a |url| is a chrome-internal: URL, this method sets up |url|, and
+// |result_type| to the appropriate values for displaying the new tab page
+// and returns true. Exposed for use by BrowserURLHandler.
bool NewTabUIHandleURL(GURL* url, TabContentsType* result_type);
// The following classes aren't used outside of new_tab_ui.cc but are
@@ -69,71 +69,6 @@ class IncognitoTabHTMLSource : public ChromeURLDataManager::DataSource {
DISALLOW_EVIL_CONSTRUCTORS(IncognitoTabHTMLSource);
};
-// ThumbnailSource is the gateway between network-level chrome-resource:
-// requests for thumbnails and the history backend that serves these.
-class ThumbnailSource : public ChromeURLDataManager::DataSource {
- public:
- explicit ThumbnailSource(Profile* profile);
-
- // Called when the network layer has requested a resource underneath
- // the path we registered.
- virtual void StartDataRequest(const std::string& path, int request_id);
-
- virtual std::string GetMimeType(const std::string&) const {
- // Rely on image decoder inferring the correct type.
- return std::string();
- }
-
- // Called when thumbnail data is available from the history backend.
- void OnThumbnailDataAvailable(
- HistoryService::Handle request_handle,
- scoped_refptr<RefCountedBytes> data);
-
- private:
- Profile* profile_;
- CancelableRequestConsumerT<int, 0> cancelable_consumer_;
-
- // Raw PNG representation of the thumbnail to show when the thumbnail
- // database doesn't have a thumbnail for a webpage.
- scoped_refptr<RefCountedBytes> default_thumbnail_;
-
- DISALLOW_EVIL_CONSTRUCTORS(ThumbnailSource);
-};
-
-// ThumbnailSource is the gateway between network-level chrome-resource:
-// requests for favicons and the history backend that serves these.
-class FavIconSource : public ChromeURLDataManager::DataSource {
- public:
- explicit FavIconSource(Profile* profile);
-
- // Called when the network layer has requested a resource underneath
- // the path we registered.
- virtual void StartDataRequest(const std::string& path, int request_id);
-
- virtual std::string GetMimeType(const std::string&) const {
- // Rely on image decoder inferring the correct type.
- return std::string();
- }
-
- // Called when favicon data is available from the history backend.
- void OnFavIconDataAvailable(
- HistoryService::Handle request_handle,
- bool know_favicon,
- scoped_refptr<RefCountedBytes> data,
- bool expired,
- GURL url);
-
- private:
- Profile* profile_;
- CancelableRequestConsumerT<int, 0> cancelable_consumer_;
-
- // Raw PNG representation of the favicon to show when the favicon
- // database doesn't have a favicon for a webpage.
- scoped_refptr<RefCountedBytes> default_favicon_;
-
- DISALLOW_EVIL_CONSTRUCTORS(FavIconSource);
-};
-
// The handler for Javascript messages related to the "most visited" view.
class MostVisitedHandler : public DOMMessageHandler,
public NotificationObserver {
diff --git a/chrome/browser/history/history.cc b/chrome/browser/history/history.cc
index 4e64b55..99838a1 100644
--- a/chrome/browser/history/history.cc
+++ b/chrome/browser/history/history.cc
@@ -569,7 +569,7 @@ bool HistoryService::CanAddURL(const GURL& url) const {
return false;
if (url.SchemeIs("javascript") ||
- url.SchemeIs("chrome-resource") ||
+ url.SchemeIs("chrome") ||
url.SchemeIs("view-source"))
return false;
diff --git a/chrome/browser/native_ui_contents.h b/chrome/browser/native_ui_contents.h
index 54319b7..6f194f7 100644
--- a/chrome/browser/native_ui_contents.h
+++ b/chrome/browser/native_ui_contents.h
@@ -74,7 +74,7 @@ class NativeUIContents : public TabContents,
views::View** focus_traversable_view);
virtual views::RootView* GetContentsRootView() { return GetRootView(); }
- // Return the scheme used. We currently use nativeui:
+ // Return the scheme used. We currently use chrome-nativeui:
static std::string GetScheme();
// Register a NativeUIFactory for a given path.
diff --git a/chrome/browser/render_view_context_menu_controller.cc b/chrome/browser/render_view_context_menu_controller.cc
index 43836d2..e54868c 100644
--- a/chrome/browser/render_view_context_menu_controller.cc
+++ b/chrome/browser/render_view_context_menu_controller.cc
@@ -480,7 +480,7 @@ bool RenderViewContextMenuController::IsDevCommandEnabled(int id) const {
return false;
// Don't inspect inspector, new tab UI, etc.
- if (active_entry->url().SchemeIs("chrome-resource"))
+ if (active_entry->url().SchemeIs("chrome"))
return false;
// Don't inspect about:network, about:memory, etc.
diff --git a/chrome/browser/renderer_security_policy.cc b/chrome/browser/renderer_security_policy.cc
index f72848a..32d29f8 100644
--- a/chrome/browser/renderer_security_policy.cc
+++ b/chrome/browser/renderer_security_policy.cc
@@ -195,9 +195,9 @@ void RendererSecurityPolicy::GrantInspectElement(int renderer_id) {
if (state == security_state_.end())
return;
- // The inspector is served from a chrome-resource: URL. In order to run the
- // inspector, the renderer needs to be able to load chrome-resource URLs.
- state->second->GrantScheme("chrome-resource");
+ // The inspector is served from a chrome: URL. In order to run the
+ // inspector, the renderer needs to be able to load chrome URLs.
+ state->second->GrantScheme("chrome");
}
void RendererSecurityPolicy::GrantDOMUIBindings(int renderer_id) {
@@ -209,8 +209,8 @@ void RendererSecurityPolicy::GrantDOMUIBindings(int renderer_id) {
state->second->GrantDOMUIBindings();
- // DOM UI bindings need the ability to request chrome-resource URLs.
- state->second->GrantScheme("chrome-resource");
+ // DOM UI bindings need the ability to request chrome URLs.
+ state->second->GrantScheme("chrome");
// DOM UI pages can contain links to file:// URLs.
state->second->GrantScheme("file");
diff --git a/chrome/browser/renderer_security_policy_unittest.cc b/chrome/browser/renderer_security_policy_unittest.cc
index 87e05cb..7d4318d 100644
--- a/chrome/browser/renderer_security_policy_unittest.cc
+++ b/chrome/browser/renderer_security_policy_unittest.cc
@@ -14,12 +14,12 @@ class RendererSecurityPolicyTest : public testing::Test {
protected:
// testing::Test
virtual void SetUp() {
- // In the real world, "chrome-resource" is a handled scheme.
- URLRequest::RegisterProtocolFactory("chrome-resource",
+ // In the real world, "chrome" is a handled scheme.
+ URLRequest::RegisterProtocolFactory("chrome",
&URLRequestTestJob::Factory);
}
virtual void TearDown() {
- URLRequest::RegisterProtocolFactory("chrome-resource", NULL);
+ URLRequest::RegisterProtocolFactory("chrome", NULL);
}
};
@@ -70,7 +70,7 @@ TEST_F(RendererSecurityPolicyTest, StandardSchemesTest) {
EXPECT_FALSE(p->CanRequestURL(kRendererID,
GURL("view-cache:http://www.google.com/")));
EXPECT_FALSE(p->CanRequestURL(kRendererID,
- GURL("chrome-resource://foo/bar")));
+ GURL("chrome://foo/bar")));
p->Remove(kRendererID);
}
@@ -203,7 +203,7 @@ TEST_F(RendererSecurityPolicyTest, CanUploadFiles) {
TEST_F(RendererSecurityPolicyTest, CanServiceInspectElement) {
RendererSecurityPolicy* p = RendererSecurityPolicy::GetInstance();
- GURL url("chrome-resource://inspector/inspector.html");
+ GURL url("chrome://inspector/inspector.html");
p->Add(kRendererID);
@@ -217,7 +217,7 @@ TEST_F(RendererSecurityPolicyTest, CanServiceInspectElement) {
TEST_F(RendererSecurityPolicyTest, CanServiceDOMUIBindings) {
RendererSecurityPolicy* p = RendererSecurityPolicy::GetInstance();
- GURL url("chrome-resource://thumb/http://www.google.com/");
+ GURL url("chrome://thumb/http://www.google.com/");
p->Add(kRendererID);
diff --git a/chrome/browser/resources/browser_resources.vcproj b/chrome/browser/resources/browser_resources.vcproj
index d49ed50..0c5886b 100644
--- a/chrome/browser/resources/browser_resources.vcproj
+++ b/chrome/browser/resources/browser_resources.vcproj
@@ -80,6 +80,10 @@
>
</File>
<File
+ RelativePath=".\history.html"
+ >
+ </File>
+ <File
RelativePath=".\incognito_tab.html"
>
</File>
diff --git a/chrome/browser/resources/history.html b/chrome/browser/resources/history.html
new file mode 100644
index 0000000..d86d6fe
--- /dev/null
+++ b/chrome/browser/resources/history.html
@@ -0,0 +1,789 @@
+<!DOCTYPE HTML>
+<html id="t">
+<head>
+<meta charset="utf-8">
+<title jscontent="title"></title>
+<script type="text/javascript">
+///////////////////////////////////////////////////////////////////////////////
+// Globals:
+var RESULTS_PER_PAGE = 60;
+var MAX_SEARCH_DEPTH = 18;
+
+// Amount of time between pageviews that we consider a 'break' in browsing,
+// measured in milliseconds.
+var BROWSING_GAP_TIME = 15 * 60 * 1000;
+
+function $(o) {return document.getElementById(o);}
+
+// TODO(glen): Get rid of these global references, replace with a controller
+// or just make the classes own more of the page.
+var historyModel;
+var historyView;
+var localStrings;
+var pageState;
+
+///////////////////////////////////////////////////////////////////////////////
+// localStrings:
+/**
+ * We get strings into the page by using JSTemplate to populate some elements
+ * with localized content, then reading the content of those elements into
+ * this global strings object.
+ * @param {Node} node The DOM node containing all our strings.
+ */
+function LocalStrings(node) {
+ this.strings_ = {};
+
+ var children = node.childNodes;
+ for (var i = 0, child; child = children[i]; i++) {
+ var id = child.id;
+ if (id) {
+ this.strings_[id] = child.innerHTML;
+ }
+ }
+}
+
+/**
+ * Gets a localized string by its id.
+ * @param {string} s The id of the string we want
+ * @return {string} The localized string
+ */
+LocalStrings.prototype.getString = function(s) {
+ return (s in this.strings_) ? this.strings_[s] : '';
+}
+
+/**
+ * Returns a formatted localized string (where all %s contents are replaced
+ * by the second argument).
+ * @param {string} s The id of the string we want
+ * @param {string} d The string to include in the formatted string
+ * @return {string} The formatted string.
+ */
+LocalStrings.prototype.formatString = function(s, d) {
+ return (s in this.strings_) ? this.strings_[s].replace(/\%s/, d) : '';
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// Page:
+/**
+ * Class to hold all the information about an entry in our model.
+ * @param {Object} result An object containing the page's data.
+ * @param {boolean} continued Whether this page is on the same day as the
+ * page before it
+ */
+function Page(result, continued, model) {
+ this.model_ = model;
+ this.title_ = result.title;
+ this.url_ = result.url;
+ this.snippet_ = result.snippet || "";
+
+ // All the date information is public so that owners can compare properties of
+ // two items easily.
+
+ // We get the time in seconds, but we want it in milliseconds.
+ this.time = new Date(result.time * 1000);
+
+ // See comment in BrowsingHistoryHandler::QueryComplete - we won't always
+ // get all of these.
+ this.dateRelativeDay = result.dateRelativeDay || "";
+ this.dateTimeOfDay = result.dateTimeOfDay || "";
+ this.dateShort = result.dateShort || "";
+
+ // Whether this is the continuation of a previous day.
+ this.continued = continued;
+}
+
+// Page, Public: --------------------------------------------------------------
+/**
+ * @return {string} Gets the HTML representation of the page
+ * for use in browse results.
+ */
+Page.prototype.getBrowseResultHTML = function() {
+ return '<div class="entry">' +
+ '<div class="time">' +
+ this.dateTimeOfDay +
+ '</div>' +
+ this.getTitleHTML_() +
+ '</div>';
+}
+
+/**
+ * @return {string} Gets the HTML representation of the page for
+ * use in search results.
+ */
+Page.prototype.getSearchResultHTML = function() {
+ return '<tr class="entry"><td valign="top">' +
+ '<div class="time">' +
+ this.dateShort +
+ '</div>' +
+ '</td><td valign="top">' +
+ this.getTitleHTML_() +
+ '<div class="snippet">' +
+ this.getHighlightedSnippet_() +
+ '</div>' +
+ '</td></tr>';
+}
+
+// Page, private: -------------------------------------------------------------
+/**
+ * @return {string} The page's snippet highlighted with the model's
+ * current search term.
+ */
+Page.prototype.getHighlightedSnippet_ = function() {
+ return Page.getHighlightedText_(this.snippet_, this.model_.getSearchText());
+}
+
+/**
+ * @return {string} Gets the page's title highlighted with the
+ * model's current search term.
+ */
+Page.prototype.getHighlightedTitle_ = function() {
+ return Page.getHighlightedText_(this.title_, this.model_.getSearchText());
+}
+
+/**
+ * @return {string} HTML for the title block.
+ */
+Page.prototype.getTitleHTML_ = function() {
+ return '<div class="title">' +
+ '<a ' +
+ 'href="' + this.url_ + '" ' +
+ 'style="background-image:url(chrome://favicon/' +
+ this.url_ + ')" ' +
+ '>' +
+ this.getHighlightedTitle_() +
+ '</a>' +
+ '</div>';
+}
+
+// Page, private, static: -----------------------------------------------------
+/**
+ * Case-insensitively highlights a string.
+ * @param {string} str The source string
+ * @param {string} opt_highlight The string to highlight with
+ * @return {string} The highlighted string
+ */
+Page.getHighlightedText_ = function(str, opt_highlight ) {
+ if (!opt_highlight) return str;
+
+ var r = new RegExp(Page.pregQuote_(opt_highlight), 'gim');
+ return str.replace(r, "<b>\$&</b>");
+}
+
+/**
+ * Quote a string so it can be used in a regular expression.
+ * @param {string} str The source string
+ * @return {string} The escaped string
+ */
+Page.pregQuote_ = function(str) {
+ return str.replace(/([\\\.\+\*\?\[\^\]\$\(\)\{\}\=\!\<\>\|\:])/g, "\\$1");
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// HistoryModel:
+/**
+ * Global container for history data. Future optimizations might include
+ * allowing the creation of a HistoryModel for each search string, allowing
+ * quick flips back and forth between results.
+ *
+ * The history model is based around pages, and only fetching the data to
+ * fill the currently requested page. This is somewhat dependent on the view,
+ * and so future work may wish to change history model to operate on
+ * timeframe (day or week) based containers.
+ */
+function HistoryModel() {
+ this.clearModel_();
+ this.view_;
+}
+
+// HistoryModel, Public: ------------------------------------------------------
+/**
+ * Sets our current view that is called when the history model changes.
+ * @param {HistoryView} view The view to set our current view to.
+ */
+HistoryModel.prototype.setView = function(view) {
+ this.view_ = view;
+}
+
+/**
+ * Start a new search - this will clear out our model.
+ * @param {String} searchText The text to search for
+ * @param {Number} opt_page The page to view - this is mostly used when setting
+ * up an initial view, use #requestPage otherwise.
+ */
+HistoryModel.prototype.setSearchText = function(searchText, opt_page) {
+ this.clearModel_();
+ this.searchText_ = searchText;
+ this.requestedPage_ = opt_page ? opt_page : 0;
+ this.getSearchResults_();
+}
+
+/**
+ * @return {String} The current search text.
+ */
+HistoryModel.prototype.getSearchText = function() {
+ return this.searchText_;
+}
+
+/**
+ * Tell the model that the view will want to see the current page. When
+ * the data becomes available, the model will call the view back.
+ * @page {Number} page The page we want to view.
+ */
+HistoryModel.prototype.requestPage = function(page) {
+ this.requestedPage_ = page;
+ this.updateSearch_();
+}
+
+/**
+ * Receiver for history query.
+ * @param {String} term The search term that the results are for.
+ * @param {Array} results A list of results
+ */
+HistoryModel.prototype.addResults = function(term, results) {
+ this.inFlight_ = false;
+ if (term != this.searchText_) {
+ // If our results aren't for our current search term, they're rubbish.
+ return;
+ }
+
+ // Currently we assume we're getting things in date order. This needs to
+ // be updated if that ever changes.
+ if (results) {
+ var lastURL, lastDay;
+ var oldLength = this.pages_.length;
+ if (oldLength) {
+ var oldPage = this.pages_[oldLength - 1];
+ lastURL = oldPage.url;
+ lastDay = oldPage.dateRelativeDay;
+ }
+
+ for (var i = 0, thisResult; thisResult = results[i]; i++) {
+ var thisURL = thisResult.url;
+ var thisDay = thisResult.dateRelativeDay;
+
+ // Remove adjacent duplicates.
+ if (!lastURL || lastURL != thisURL) {
+ // Figure out if this page is in the same day as the previous page,
+ // this is used to determine how day headers should be drawn.
+ this.pages_.push(new Page(thisResult, thisDay == lastDay, this));
+ lastDay = thisDay;
+ lastURL = thisURL;
+ }
+ }
+ }
+
+ this.updateSearch_();
+}
+
+/**
+ * @return {Number} The number of pages in the model.
+ */
+HistoryModel.prototype.getSize = function() {
+ return this.pages_.length;
+}
+
+/**
+ * @return {boolean} Whether our history query has covered all of
+ * the user's history
+ */
+HistoryModel.prototype.isComplete = function() {
+ return this.complete_;
+}
+
+/**
+ * Get a list of pages between specified index positions.
+ * @param {Number} start The start index
+ * @param {Number} end The end index
+ * @return {Array} A list of pages
+ */
+HistoryModel.prototype.getNumberedRange = function(start, end) {
+ if (start >= this.getSize())
+ return [];
+
+ var end = end > this.getSize() ? this.getSize() : end;
+ return this.pages_.slice(start, end);
+}
+
+// HistoryModel, Private: -----------------------------------------------------
+HistoryModel.prototype.clearModel_ = function() {
+ this.inFlight_ = false; // Whether a query is inflight.
+ this.searchText_ = '';
+ this.searchMonth_ = 0;
+ this.pages_ = []; // Date-sorted list of pages.
+
+ // The page that the view wants to see - we only fetch slightly past this
+ // point. If the view requests a page that we don't have data for, we try
+ // to fetch it and call back when we're done.
+ this.requestedPage_ = 0;
+
+ this.complete_ = false;
+}
+
+/**
+ * Figure out if we need to do more searches to fill the currently requested
+ * page. If we think we can fill the page, call the view and let it know
+ * we're ready to show something.
+ */
+HistoryModel.prototype.updateSearch_ = function() {
+ if (this.searchMonth_ >= MAX_SEARCH_DEPTH) {
+ // We have maxed out. There will be no more data.
+ this.complete_ = true;
+ this.view_.onModelReady();
+ } else {
+ // If we can't fill the requested page, ask for more data unless a request
+ // is still in-flight.
+ if (!this.canFillPage_(this.requestedPage_) && !this.inFlight_) {
+ this.getSearchResults_(this.searchMonth_ + 1);
+ }
+
+ // If we have any data for the requested page, show it.
+ if (this.haveDataForPage_(this.requestedPage_)) {
+ this.view_.onModelReady();
+ }
+ }
+}
+
+/**
+ * Get search results for a selected month. Our history system is optimized
+ * for queries that don't cross month boundaries.
+ *
+ * TODO: Fix this for when the user's clock goes across month boundaries.
+ * @param {number} opt_month How many months back to do the search.
+ */
+HistoryModel.prototype.getSearchResults_ = function(opt_month) {
+ this.searchMonth_ = opt_month || 0;
+ chrome.send('getHistory',
+ [this.searchText_, String(this.searchMonth_)]);
+ this.inFlight_ = true;
+}
+
+/**
+ * Check to see if we have data for a given page.
+ * @param {number} page The page number
+ * @return {boolean} Whether we have any data for the given page.
+ */
+HistoryModel.prototype.haveDataForPage_ = function(page) {
+ return (page * RESULTS_PER_PAGE < this.getSize());
+}
+
+/**
+ * Check to see if we have data to fill a page.
+ * @param {number} page The page number.
+ * @return {boolean} Whether we have data to fill the page.
+ */
+HistoryModel.prototype.canFillPage_ = function(page) {
+ return ((page + 1) * RESULTS_PER_PAGE <= this.getSize());
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// HistoryView:
+/**
+ * Functions and state for populating the page with HTML. This should one-day
+ * contain the view and use event handlers, rather than pushing HTML out and
+ * getting called externally.
+ * @param {HistoryModel} model The model backing this view.
+ */
+function HistoryView(model) {
+ this.summaryDiv_ = $('results-summary');
+ this.summaryDiv_.innerHTML = localStrings.getString('loading');
+ this.resultDiv_ = $('results-display');
+ this.pageDiv_ = $('results-pagination');
+ this.model_ = model
+ this.pageIndex_ = 0;
+
+ this.model_.setView(this);
+}
+
+// HistoryView, public: -------------------------------------------------------
+/**
+ * Do a search and optionally view a certain page.
+ * @param {string} term The string to search for.
+ * @param {number} opt_page The page we wish to view, only use this for
+ * setting up initial views, as this triggers a search.
+ */
+HistoryView.prototype.setSearch = function(term, opt_page) {
+ this.pageIndex_ = parseInt(opt_page || 0, 10);
+ window.scrollTo(0, 0);
+ this.model_.setSearchText(term, this.pageIndex_);
+ pageState.setUIState(term, this.pageIndex_);
+}
+
+/**
+ * Switch to a specified page.
+ * @param {string} term The string to search for.
+ * @param {number} opt_page The page we wish to view.
+ */
+HistoryView.prototype.setPage = function(page) {
+ this.pageIndex_ = parseInt(page, 10);
+ window.scrollTo(0, 0);
+ this.model_.requestPage(page);
+ pageState.setUIState(this.model_.getSearchText(), this.pageIndex_);
+}
+
+/**
+ * @return {number} The page number being viewed.
+ */
+HistoryView.prototype.getPage = function() {
+ return this.pageIndex_;
+}
+
+/**
+ * Callback for the history model to let it know that it has data ready for us
+ * to view.
+ */
+HistoryView.prototype.onModelReady = function() {
+ this.displayResults_();
+}
+
+// HistoryView, private: ------------------------------------------------------
+/**
+ * Update the page with results.
+ */
+HistoryView.prototype.displayResults_ = function() {
+ var output = [];
+ var results = this.model_.getNumberedRange(
+ this.pageIndex_ * RESULTS_PER_PAGE,
+ this.pageIndex_ * RESULTS_PER_PAGE + RESULTS_PER_PAGE);
+
+ if (this.model_.getSearchText()) {
+ output.push('<table class="results" cellspacing="0" ',
+ 'cellpadding="0" border="0">');
+ for (var i = 0, page; page = results[i]; i++) {
+ output.push(page.getSearchResultHTML());
+ }
+ output.push('</table>');
+ } else {
+ var lastTime = Math.infinity;
+ for (var i = 0, page; page = results[i]; i++) {
+ // Break across day boundaries and insert gaps for browsing pauses.
+ var thisTime = page.time.getTime();
+ if (page.continued && i == 0) {
+ output.push('<div class="day">' + page.dateRelativeDay + ' ' +
+ localStrings.getString('cont') + '</div>');
+ } else if (!page.continued) {
+ output.push('<div class="day">' + page.dateRelativeDay + '</div>');
+ } else if (lastTime - thisTime > BROWSING_GAP_TIME) {
+ output.push('<div class="gap"></div>');
+ }
+ lastTime = thisTime;
+
+ // Draw entry.
+ output.push(page.getBrowseResultHTML());
+ }
+ }
+ this.resultDiv_.innerHTML = output.join("");
+
+ this.displaySummaryBar_();
+ this.displayNavBar_();
+}
+
+/**
+ * Update the summary bar with descriptive text.
+ */
+HistoryView.prototype.displaySummaryBar_ = function() {
+ var searchText = this.model_.getSearchText();
+ if (searchText != '') {
+ this.summaryDiv_.innerHTML = localStrings.formatString('searchresultsfor',
+ searchText);
+ } else {
+ this.summaryDiv_.innerHTML = localStrings.getString('history');
+ }
+}
+
+/**
+ * Update the pagination tools.
+ */
+HistoryView.prototype.displayNavBar_ = function() {
+ var navOutput = '';
+ if (this.pageIndex_ > 0) {
+ navOutput += this.createPageNavHTML_(0, localStrings.getString('newest'));
+ navOutput += this.createPageNavHTML_(this.pageIndex_ - 1,
+ localStrings.getString('newer'));
+ }
+ if (this.model_.getSize() > (this.pageIndex_ + 1) * RESULTS_PER_PAGE) {
+ navOutput += this.createPageNavHTML_(this.pageIndex_ + 1,
+ localStrings.getString('older'));
+ }
+ this.pageDiv_.innerHTML = navOutput;
+}
+
+/**
+ * Get the HTML representation of a page navigation link.
+ * @param {number} page The page index the navigation element should link to
+ * @param {string} name The text content of the link
+ * @return {string} HTML representation of the pagination link
+ */
+HistoryView.prototype.createPageNavHTML_ = function(page, name) {
+ var hashString = PageState.getHashString(this.model_.getSearchText(), page);
+ return '<a href="chrome://history/' +
+ (hashString ? '#' + hashString : '') +
+ '"' +
+ 'class="page-navigation"' +
+ 'onclick="setPage(' + page + '); return false;"' +
+ '>' + name + '</a>';
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// State object:
+/**
+ * An 'AJAX-history' implementation.
+ * @param {HistoryModel} model The model we're representing
+ * @param {HistoryView} view The view we're representing
+ */
+function PageState(model, view) {
+ // Enforce a singleton.
+ if (PageState.instance) {
+ return PageState.instance;
+ }
+
+ this.model = model;
+ this.view = view;
+
+ if (typeof this.checker_ != 'undefined' && this.checker_) {
+ clearInterval(this.checker_);
+ }
+
+ // TODO(glen): Replace this with a bound method so we don't need
+ // public model and view.
+ this.checker_ = setInterval((function(state_obj) {
+ var hashData = state_obj.getHashData();
+
+ if (hashData.q != state_obj.model.getSearchText(term)) {
+ state_obj.view.setSearch(hashData.q, parseInt(hashData.p, 10));
+ } else if (parseInt(hashData.p, 10) != state_obj.view.getPage()) {
+ state_obj.view.setPage(hashData.p);
+ }
+ }), 50, this);
+}
+
+PageState.instance = null;
+
+/**
+ * @return {Object} An object containing parameters from our window hash.
+ */
+PageState.prototype.getHashData = function() {
+ var result = {
+ q : '',
+ p : 0
+ };
+
+ if (!window.location.hash) {
+ return result;
+ }
+
+ var hashSplit = window.location.hash.substr(1).split("&");
+ for (var i = 0; i < hashSplit.length; i++) {
+ var pair = hashSplit[i].split("=");
+ if (pair.length > 1) {
+ result[pair[0]] = unescape(pair[1]);
+ }
+ }
+
+ return result;
+}
+
+/**
+ * Set the hash to a specified state, this will create an entry in the
+ * session history so the back button cycles through hash states, which
+ * are then picked up by our listener.
+ * @param {string} term The current search string.
+ * @param {string} page The page currently being viewed.
+ */
+PageState.prototype.setUIState = function(term, page) {
+ // Make sure the form looks pretty.
+ document.forms[0].term.value = term;
+
+ var hash = PageState.getHashString(term, page);
+ if (window.location.hash.substr(1) != hash) {
+ window.location.hash = hash;
+ }
+}
+
+/**
+ * Static method to get the hash string for a specified state
+ * @param {string} term The current search string.
+ * @param {string} page The page currently being viewed.
+ * @return {string} The string to be used in a hash.
+ */
+PageState.getHashString = function(term, page) {
+ var newHash = [];
+ if (term) {
+ newHash.push("q=" + escape(term));
+ }
+ if (page) {
+ newHash.push("p=" + page);
+ }
+
+ return newHash.join("&");
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// Document Functions:
+/**
+ * Window onload handler, sets up the page.
+ */
+ function load() {
+ localStrings = new LocalStrings($('l10n'));
+ historyModel = new HistoryModel();
+ historyView = new HistoryView(historyModel);
+ pageState = new PageState(historyModel, historyView);
+
+ // Create default view.
+ var hashData = pageState.getHashData();
+ historyView.setSearch(hashData.q, hashData.p);
+}
+
+/**
+ * TODO(glen): Get rid of this function.
+ * Set the history view to a specified page.
+ * @param {String} term The string to search for
+ */
+function setSearch(term) {
+ if (historyView) {
+ historyView.setSearch(term);
+ }
+}
+
+/**
+ * TODO(glen): Get rid of this function.
+ * Set the history view to a specified page.
+ * @param {number} page The page to set the view to.
+ */
+function setPage(page) {
+ if (historyView) {
+ historyView.setPage(page);
+ }
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// Chrome callbacks:
+/**
+ * Our history system calls this function with results from searches.
+ */
+function historyResult(term, results) {
+ historyModel.addResults(term, results);
+}
+</script>
+<style type="text/css">
+body {
+ font-family:arial;
+ background-color:white;
+ color:black;
+ font-size:84%;
+ margin:10px;
+}
+.header {
+ overflow:auto;
+ clear:both;
+}
+.header .logo {
+ float:left;
+}
+.header .form {
+ float:left;
+ margin-top:22px;
+ margin-left:12px;
+}
+#results-summary {
+ margin-top:12px;
+ border-top:1px solid #9cc2ef;
+ background-color:#ebeff9;
+ font-weight:bold;
+ padding:3px;
+ margin-bottom:-8px;
+}
+#results-display {
+ max-width:740px;
+}
+.day {
+ margin-top:18px;
+ margin-left:3px;
+}
+.gap {
+ margin-left:18px;
+ width:15px;
+ border-right:1px solid #ddd;
+ height:14px;
+}
+.entry {
+ margin-left:18px;
+ margin-top:6px;
+ overflow:auto;
+}
+table.results {
+ margin-left:4px;
+}
+.entry .time {
+ color:#888;
+ float:left;
+ min-width:56px;
+ margin-right:5px;
+ padding-top:1px;
+}
+.entry .title {
+ max-width:600px;
+ overflow: hidden;
+ white-space: nowrap;
+ text-overflow: ellipsis;
+}
+.results .time, .results .title {
+ margin-top:18px;
+}
+.entry .title a {
+ background-repeat:no-repeat;
+ background-size:16px;
+ background-position:0px 1px;
+ padding:1px 0px 4px 22px;
+}
+html[dir='rtl'] .entry .title a {
+ background-position:right;
+ padding-left:0px;
+ padding-right:22px;
+}
+#results-pagination {
+ padding-top:24px;
+ margin-left:18px;
+}
+.page-navigation {
+ padding:8px;
+ background-color:#ebeff9;
+ margin-right:4px;
+}
+.footer {
+ height:24px;
+}
+</style>
+</head>
+<body onload="load();">
+<div class="header">
+ <a href="" onclick="setSearch(''); return false;">
+ <img src="../../app/theme/history_section.png"
+ width="67" height="67" class="logo" border="0" /></a>
+ <form method="post" action=""
+ onsubmit="setSearch(this.term.value); return false;"
+ class="form">
+ <input type="text" name="term" id="term" />
+ <input type="submit" name="submit" jsvalues="value:searchbutton" />
+ </form>
+</div>
+<div class="main">
+ <div id="results-summary"></div>
+ <div id="results-display"></div>
+ <div id="results-pagination"></div>
+</div>
+<div class="footer">
+</div>
+<div id="l10n" style="display:none;">
+ <span id="loading" jscontent="loading">Loading...</span>
+ <span id="newest" jscontent="newest">&laquo; Newest</span>
+ <span id="newer" jscontent="newer">&#8249; Newer</span>
+ <span id="older" jscontent="older">Older &#8250;</span>
+ <span id="searchresultsfor" jscontent="searchresultsfor">Search results for '%s'</span>
+ <span id="history" jscontent="history">History</span>
+ <span id="cont" jscontent="cont">(cont.)</span>
+ <span id="noresults" jscontent="noresults">No results</span>
+ <span id="noitems" jscontent="noitems">No items</span>
+ <span id="delete" jscontent="delete">delete</span>
+</div>
+</body>
+</html> \ No newline at end of file
diff --git a/chrome/browser/resources/new_tab.html b/chrome/browser/resources/new_tab.html
index 8fe2429..dc0516b 100644
--- a/chrome/browser/resources/new_tab.html
+++ b/chrome/browser/resources/new_tab.html
@@ -180,7 +180,7 @@ html[dir='rtl'] #mostvisited td {
-webkit-transition:all 0.12s;
}
.thumbnail-title {
- background-image:url(chrome-resource://favicon/);
+ background-image:url(chrome://favicon/);
display:block;
background-repeat:no-repeat;
background-size:16px;
@@ -359,7 +359,7 @@ document.addEventListener('DOMContentLoaded', handleDOMContentLoaded);
<form onsubmit="chrome.send('searchHistoryPage', [this.search.value]); return false;">
<input type="text" class="hint"
name="search"
- style="background-image:url(chrome-resource://favicon/);"
+ style="background-image:url(chrome://favicon/);"
jsvalues="value:searchhistory"
onfocus="handleInputFocus.apply(this);"
onblur="handleInputBlur.apply(this);" />
@@ -416,12 +416,12 @@ function makeMostVisitedDOM(page, number) {
/* Create the thumbnail */
var img_thumbnail = DOM('img', {className:'thumbnail'});
img_thumbnail.setAttribute('onload', "logEvent('image loaded');");
- img_thumbnail.src = 'chrome-resource://thumb/' + page.url;
+ img_thumbnail.src = 'chrome://thumb/' + page.url;
/* Create the title */
var div_title = DOM('div', {className:'thumbnail-title'});
div_title.style.backgroundImage =
- 'url("chrome-resource://favicon/' + page.url + '")';
+ 'url("chrome://favicon/' + page.url + '")';
if (page.title) {
div_title.appendChild(document.createTextNode(page.title));
} else {
@@ -484,7 +484,7 @@ function makeSearchURL(url) {
/* The HTML we want looks like this:
<form>
<input type="text" class="hint"
- style="background-image:url(chrome-resource://favicon/"+url+");"
+ style="background-image:url(chrome://favicon/"+url+");"
value="Search Wikipedia"
onfocus="handleInputFocus();"
onblur="handleInputBlur();" />
@@ -497,10 +497,10 @@ function makeSearchURL(url) {
if (url.favIconURL) {
input.style.backgroundImage =
- 'url("chrome-resource://favicon/iconurl/' + url.favIconURL + '")';
+ 'url("chrome://favicon/iconurl/' + url.favIconURL + '")';
} else {
input.style.backgroundImage =
- 'url("chrome-resource://favicon/http://' + url.short_name + '")';
+ 'url("chrome://favicon/http://' + url.short_name + '")';
}
input.onfocus = handleInputFocus;
@@ -555,7 +555,7 @@ function renderRecentlyBookmarked(entries) {
chrome.send("metrics", ["NTP_Bookmark" + i])
}, false);
link.style.backgroundImage =
- 'url("chrome-resource://favicon/' + entry.url + '")';
+ 'url("chrome://favicon/' + entry.url + '")';
link.appendChild(document.createTextNode(entry.title));
container.appendChild(link);
}
@@ -593,7 +593,7 @@ function renderRecentlyClosedTabs(entries) {
}
}(entry.sessionId);
- link.style.backgroundImage = 'url("chrome-resource://favicon/' + entry.url + '")';
+ link.style.backgroundImage = 'url("chrome://favicon/' + entry.url + '")';
link.appendChild(document.createTextNode(entry.title));
container.appendChild(link);
}
diff --git a/chrome/browser/site_instance.cc b/chrome/browser/site_instance.cc
index 63517d8..ec1eaf1 100644
--- a/chrome/browser/site_instance.cc
+++ b/chrome/browser/site_instance.cc
@@ -81,7 +81,7 @@ GURL SiteInstance::GetSiteForURL(const GURL& url) {
GURL site;
// TODO(creis): For many protocols, we should just treat the scheme as the
- // site, since there is no host. e.g., file:, about:, chrome-resource:
+ // site, since there is no host. e.g., file:, about:, chrome:
// If the url has a host, then determine the site.
if (url.has_host()) {
diff --git a/chrome/browser/tab_contents_factory.cc b/chrome/browser/tab_contents_factory.cc
index 2488222..6a6abba 100644
--- a/chrome/browser/tab_contents_factory.cc
+++ b/chrome/browser/tab_contents_factory.cc
@@ -7,6 +7,7 @@
#include "chrome/browser/about_internets_status_view.h"
#include "chrome/browser/browser_about_handler.h"
#include "chrome/browser/browser_url_handler.h"
+#include "chrome/browser/dom_ui/dom_ui_contents.h"
#include "chrome/browser/dom_ui/html_dialog_contents.h"
#include "chrome/browser/dom_ui/new_tab_ui.h"
#include "chrome/browser/ipc_status_view.h"
@@ -75,6 +76,9 @@ TabContents* TabContents::CreateWithType(TabContentsType type,
case TAB_CONTENTS_DEBUGGER:
contents = new DebuggerContents(profile, instance);
break;
+ case TAB_CONTENTS_DOM_UI:
+ contents = new DOMUIContents(profile, instance, NULL);
+ break;
default:
if (g_extra_types) {
TabContentsFactoryMap::const_iterator it = g_extra_types->find(type);
@@ -119,6 +123,9 @@ TabContentsType TabContents::TypeForURL(GURL* url) {
if (DebuggerContents::IsDebuggerUrl(*url))
return TAB_CONTENTS_DEBUGGER;
+ if (url->SchemeIs(DOMUIContents::GetScheme().c_str()))
+ return TAB_CONTENTS_DOM_UI;
+
if (url->SchemeIs("view-source")) {
// Load the inner URL instead, but render it using a ViewSourceContents.
*url = GURL(url->path());
diff --git a/chrome/browser/tab_contents_type.h b/chrome/browser/tab_contents_type.h
index 462227f..86f38cc 100644
--- a/chrome/browser/tab_contents_type.h
+++ b/chrome/browser/tab_contents_type.h
@@ -23,6 +23,7 @@ enum TabContentsType {
TAB_CONTENTS_HTML_DIALOG,
TAB_CONTENTS_ABOUT_UI,
TAB_CONTENTS_DEBUGGER,
+ TAB_CONTENTS_DOM_UI,
TAB_CONTENTS_NUM_TYPES
};