diff options
author | glen@chromium.org <glen@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2008-12-07 23:48:03 +0000 |
---|---|---|
committer | glen@chromium.org <glen@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2008-12-07 23:48:03 +0000 |
commit | 76a010b47593d41d1d443dacc51bc906689c2e53 (patch) | |
tree | 28f61efd20f447d21bb5ca3e8582b29994c79eba /chrome/browser | |
parent | 85ad84eba6540630a33ab7bfa37c2d37c4a9554d (diff) | |
download | chromium_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')
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">« Newest</span> + <span id="newer" jscontent="newer">‹ Newer</span> + <span id="older" jscontent="older">Older ›</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 }; |