diff options
author | mirandac@chromium.org <mirandac@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2009-08-26 00:32:11 +0000 |
---|---|---|
committer | mirandac@chromium.org <mirandac@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2009-08-26 00:32:11 +0000 |
commit | 61a523f378291307081d46277cca5dd087fb30ac (patch) | |
tree | 76a60b79fafd0f01c2e94b5740db63e88cd9ef99 | |
parent | 5bbf2884b6ff9466d95e3c6f177ebb7a39b70268 (diff) | |
download | chromium_src-61a523f378291307081d46277cca5dd087fb30ac.zip chromium_src-61a523f378291307081d46277cca5dd087fb30ac.tar.gz chromium_src-61a523f378291307081d46277cca5dd087fb30ac.tar.bz2 |
Add single line of tips to NNTP.
BUG= http://crbug.com/19162
TEST= Start browser with NNTP, note line of tips at bottom.
Review URL: http://codereview.chromium.org/173087
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@24384 0039d316-1c4b-4281-b951-d872f2087c98
-rw-r--r-- | chrome/browser/browser_theme_provider.cc | 2 | ||||
-rw-r--r-- | chrome/browser/dom_ui/tips_handler.cc | 53 | ||||
-rw-r--r-- | chrome/browser/dom_ui/tips_handler.h | 12 | ||||
-rw-r--r-- | chrome/browser/resources/new_new_tab.css | 7 | ||||
-rw-r--r-- | chrome/browser/resources/new_new_tab.html | 5 | ||||
-rw-r--r-- | chrome/browser/resources/new_new_tab.js | 98 | ||||
-rw-r--r-- | chrome/browser/resources/new_tab_theme.css | 7 | ||||
-rw-r--r-- | chrome/browser/utility_process_host.h | 2 | ||||
-rw-r--r-- | chrome/browser/web_resource/web_resource_service.cc | 107 | ||||
-rw-r--r-- | chrome/browser/web_resource/web_resource_service.h | 17 | ||||
-rw-r--r-- | chrome/common/pref_names.cc | 2 | ||||
-rw-r--r-- | chrome/common/render_messages_internal.h | 2 | ||||
-rw-r--r-- | chrome/common/web_resource/web_resource_unpacker.cc | 4 | ||||
-rw-r--r-- | chrome/common/web_resource/web_resource_unpacker.h | 6 |
14 files changed, 202 insertions, 122 deletions
diff --git a/chrome/browser/browser_theme_provider.cc b/chrome/browser/browser_theme_provider.cc index 0b43fa3..3a7dc92 100644 --- a/chrome/browser/browser_theme_provider.cc +++ b/chrome/browser/browser_theme_provider.cc @@ -116,7 +116,7 @@ const SkColor BrowserThemeProvider::kDefaultColorNTPSection = const SkColor BrowserThemeProvider::kDefaultColorNTPSectionText = SkColorSetRGB(0, 0, 0); const SkColor BrowserThemeProvider::kDefaultColorNTPSectionLink = - SkColorSetRGB(16, 50, 105); + SkColorSetRGB(0, 0, 204); const SkColor BrowserThemeProvider::kDefaultColorControlBackground = NULL; const SkColor BrowserThemeProvider::kDefaultColorButtonBackground = NULL; diff --git a/chrome/browser/dom_ui/tips_handler.cc b/chrome/browser/dom_ui/tips_handler.cc index c495a0d..4690c27 100644 --- a/chrome/browser/dom_ui/tips_handler.cc +++ b/chrome/browser/dom_ui/tips_handler.cc @@ -12,19 +12,10 @@ #include "chrome/common/url_constants.h" #include "googleurl/src/gurl.h" -namespace { - - // TODO(mrc): l10n - // This title should only appear the very first time Chrome is run with - // web resources enabled; otherwise the cache should be populated. - static const wchar_t* kTipsTitleAtStartup = - L"Tips and recommendations to help you discover interesting websites."; -} - DOMMessageHandler* TipsHandler::Attach(DOMUI* dom_ui) { dom_ui_ = dom_ui; tips_cache_ = dom_ui_->GetProfile()->GetPrefs()-> - GetDictionary(prefs::kNTPTipsCache); + GetMutableDictionary(prefs::kNTPTipsCache); return DOMMessageHandler::Attach(dom_ui); } @@ -38,36 +29,26 @@ void TipsHandler::HandleGetTips(const Value* content) { ListValue list_value; // Holds the web resource data found in the preferences cache. - DictionaryValue* wr_dict; + ListValue* wr_list; - // These values hold the data for each web resource item. As the web - // resource server solidifies, these may change. - std::wstring title; - std::wstring thumb; - std::wstring source; - std::wstring snipp; - std::wstring url; + // These values hold the data for each web resource item. + int current_tip_index; + std::string current_tip; - // This should only be true on the very first Chrome run; otherwise, - // the cache should be populated. - if (tips_cache_ == NULL || tips_cache_->GetSize() < 1) { - title = kTipsTitleAtStartup; - DictionaryValue* tip_dict = new DictionaryValue(); - tip_dict->SetString(WebResourceService::kWebResourceTitle, title); - tip_dict->SetString(WebResourceService::kWebResourceURL, L""); - list_value.Append(tip_dict); - } else { - int tip_counter = 0; - while (tips_cache_->GetDictionary(IntToWString(tip_counter++), &wr_dict)) { - if (wr_dict && - wr_dict->GetSize() > 0 && - wr_dict->GetString(WebResourceService::kWebResourceTitle, &title) && - wr_dict->GetString(WebResourceService::kWebResourceURL, &url) && - IsValidURL(url)) { + if (tips_cache_ != NULL && tips_cache_->GetSize() >= 0) { + if (tips_cache_->GetInteger( + WebResourceService::kCurrentTipPrefName, ¤t_tip_index) && + tips_cache_->GetList( + WebResourceService::kTipCachePrefName, &wr_list)) { + if (wr_list && wr_list->GetSize() > 0) + if (wr_list->GetSize() <= static_cast<size_t>(current_tip_index)) + current_tip_index = 0; + if (wr_list->GetString(current_tip_index, ¤t_tip)) { DictionaryValue* tip_dict = new DictionaryValue(); - tip_dict->SetString(WebResourceService::kWebResourceTitle, title); - tip_dict->SetString(WebResourceService::kWebResourceURL, url); + tip_dict->SetString(L"tip_html_text", current_tip); list_value.Append(tip_dict); + tips_cache_->SetInteger(WebResourceService::kCurrentTipPrefName, + current_tip_index + 1); } } } diff --git a/chrome/browser/dom_ui/tips_handler.h b/chrome/browser/dom_ui/tips_handler.h index e5afe38..a5915ec 100644 --- a/chrome/browser/dom_ui/tips_handler.h +++ b/chrome/browser/dom_ui/tips_handler.h @@ -6,16 +6,6 @@ // has been stored in the user's preferences file. Used mainly // by the suggestions and tips area of the new tab page. -// Current sketch of tip cache format, hardcoded for popgadget data in -// basic text form: - -// "tip_cache": { -// "0": { -// "title": text giving title of item -// "url": link to item's page -// }, -// [up to number of items in kMaxWebResourceCacheSize] - #ifndef CHROME_BROWSER_DOM_UI_TIPS_HANDLER_H_ #define CHROME_BROWSER_DOM_UI_TIPS_HANDLER_H_ @@ -49,7 +39,7 @@ class TipsHandler : public DOMMessageHandler { DOMUI* dom_ui_; // Filled with data from cache in preferences. - const DictionaryValue* tips_cache_; + DictionaryValue* tips_cache_; DISALLOW_COPY_AND_ASSIGN(TipsHandler); }; diff --git a/chrome/browser/resources/new_new_tab.css b/chrome/browser/resources/new_new_tab.css index c2ce487..a2af6fb0 100644 --- a/chrome/browser/resources/new_new_tab.css +++ b/chrome/browser/resources/new_new_tab.css @@ -682,6 +682,13 @@ html[dir='rtl'] #t4 { top: 183px; } +/* tip line */ +#tip-line { + margin-top: 40px; + margin-bottom: 10px; + text-align: center; +} + /* small */ @media (max-width: 920px) { diff --git a/chrome/browser/resources/new_new_tab.html b/chrome/browser/resources/new_new_tab.html index 9415d16..5266a88 100644 --- a/chrome/browser/resources/new_new_tab.html +++ b/chrome/browser/resources/new_new_tab.html @@ -35,11 +35,13 @@ function registerCallback(name) { chrome.send('getShownSections'); chrome.send('getMostVisited'); chrome.send('getRecentlyClosedTabs'); +chrome.send('getTips'); registerCallback('onShownSections'); registerCallback('mostVisitedPages'); registerCallback('recentlyClosedTabs'); registerCallback('syncMessageChanged'); +registerCallback('tips'); logEvent('log start'); @@ -223,6 +225,9 @@ document.write('<link id="themecss" rel="stylesheet" ' + <span><a href=""> </a></span> </div> + <div id="tip-line"> + </div> + <div id="attribution" class="attribution"> <span i18n-content="attributionintro"></span><br /> <img id="attribution-img" /> diff --git a/chrome/browser/resources/new_new_tab.js b/chrome/browser/resources/new_new_tab.js index 78f7912..e9618a9 100644 --- a/chrome/browser/resources/new_new_tab.js +++ b/chrome/browser/resources/new_new_tab.js @@ -94,6 +94,31 @@ function mostVisitedPages(data, firstRun) { } } +var tipCache = {}; + +function tips(data) { + logEvent('received tips'); + tipCache = data; + renderTip(); +} + +function createTip(data) { + var parsedTips; + try { + parsedTips = parseHtmlSubset(data[0].tip_html_text); + } catch (parseErr) { + console.log('Error parsing tips: ' + parseErr.message); + } + return parsedTips; +} + +function renderTip() { + var tipElement = $('tip-line'); + // There should always be only one tip. + tipElement.textContent = ''; + tipElement.appendChild(createTip(tipCache)); +} + function recentlyClosedTabs(data) { logEvent('received recently closed tabs'); // We need to store the recent items so we can update the layout on a resize. @@ -1539,3 +1564,76 @@ var dnd = { }; dnd.init(); + +/** + * Whitelist of tag names allowed in parseHtmlSubset. + * @type {[string]} + * / +var allowedTags = ['A', 'B', 'STRONG']; + +/** + * Parse a very small subset of HTML. + * @param {string} s The string to parse. + * @throws {Error} In case of non supported markup. + * @return {DocumentFragment} A document fragment containing the DOM tree. + */ +var allowedAttributes = { + 'href': function(node, value) { + // Only allow a[href] starting with http:// and https:// + return node.tagName == 'A' && (value.indexOf('http://') == 0 || + value.indexOf('https://') == 0); + } +} + +/** + * Parse a very small subset of HTML. This ensures that insecure HTML / + * javascript cannot be injected into the new tab page. + * @param {string} s The string to parse. + * @throws {Error} In case of non supported markup. + * @return {DocumentFragment} A document fragment containing the DOM tree. + */ +function parseHtmlSubset(s) { + function walk(n, f) { + f(n); + for (var i = 0; i < n.childNodes.length; i++) { + walk(n.childNodes[i], f); + } + } + + function assertElement(node) { + if (allowedTags.indexOf(node.tagName) == -1) + throw Error(node.tagName + ' is not supported'); + } + + function assertAttribute(attrNode, node) { + var n = attrNode.nodeName; + var v = attrNode.nodeValue; + if (!allowedAttributes.hasOwnProperty(n) || !allowedAttributes[n](node, v)) + throw Error(node.tagName + '[' + n + '="' + v + '"] is not supported'); + } + + var r = document.createRange(); + r.selectNode(document.body); + // This does not execute any scripts. + var df = r.createContextualFragment(s); + walk(df, function(node) { + switch (node.nodeType) { + case Node.ELEMENT_NODE: + assertElement(node); + var attrs = node.attributes; + for (var i = 0; i < attrs.length; i++) { + assertAttribute(attrs[i], node); + } + break; + + case Node.COMMENT_NODE: + case Node.DOCUMENT_FRAGMENT_NODE: + case Node.TEXT_NODE: + break; + + default: + throw Error('Node type ' + node.nodeType + ' is not supported'); + } + }); + return df; +} diff --git a/chrome/browser/resources/new_tab_theme.css b/chrome/browser/resources/new_tab_theme.css index b59ef62c..e4547cd 100644 --- a/chrome/browser/resources/new_tab_theme.css +++ b/chrome/browser/resources/new_tab_theme.css @@ -56,7 +56,8 @@ body { } #recently-closed span, #recently-closed a, -#recently-closed a:link { +#recently-closed a:link, +#tip-line a { color: $$4; /* COLOR_NTP_SECTION_LINK */ text-decoration:underline; } @@ -66,3 +67,7 @@ body { color: $9; text-align:right; } + +#tip-line { + color: $$8; +} diff --git a/chrome/browser/utility_process_host.h b/chrome/browser/utility_process_host.h index c52c424..fa0a63c 100644 --- a/chrome/browser/utility_process_host.h +++ b/chrome/browser/utility_process_host.h @@ -48,7 +48,7 @@ class UtilityProcessHost : public ChildProcessHost { // contains the parsed list of web resource items downloaded from the // web resource server. virtual void OnUnpackWebResourceSucceeded( - const ListValue& json_data) {} + const DictionaryValue& json_data) {} // Called when an error occurred while parsing the resource data. // |error_message| contains a description of the problem. diff --git a/chrome/browser/web_resource/web_resource_service.cc b/chrome/browser/web_resource/web_resource_service.cc index 5692fdb..f88b95d 100644 --- a/chrome/browser/web_resource/web_resource_service.cc +++ b/chrome/browser/web_resource/web_resource_service.cc @@ -15,8 +15,8 @@ #include "net/base/load_flags.h" #include "net/url_request/url_request_status.h" -const wchar_t* WebResourceService::kWebResourceTitle = L"title"; -const wchar_t* WebResourceService::kWebResourceURL = L"url"; +const wchar_t* WebResourceService::kCurrentTipPrefName = L"current_tip"; +const wchar_t* WebResourceService::kTipCachePrefName = L"tips"; class WebResourceService::WebResourceFetcher : public URLFetcher::Delegate { @@ -130,7 +130,8 @@ class WebResourceService::UnpackerClient "Chrome crashed while trying to retrieve web resources."); } - virtual void OnUnpackWebResourceSucceeded(const ListValue& parsed_json) { + virtual void OnUnpackWebResourceSucceeded( + const DictionaryValue& parsed_json) { web_resource_service_->OnWebResourceUnpacked(parsed_json); Cleanup(); } @@ -167,9 +168,15 @@ class WebResourceService::UnpackerClient bool got_response_; }; -// TODO(mrc): make into a changeable preference. +// TODO(mirandac): replace these servers tomorrow! const wchar_t* WebResourceService::kDefaultResourceServer = - L"http://www.google.com/labs/popgadget/world?view=json"; +#if defined(OS_MACOSX) + L"https://clients2.google.com/tools/service/npredir?r=chrometips_mac&hl="; +#elif defined(OS_LINUX) + L"https://clients2.google.com/tools/service/npredir?r=chrometips_linux&hl="; +#else + L"https://clients2.google.com/tools/service/npredir?r=chrometips_win&hl="; +#endif const char* WebResourceService::kResourceDirectoryName = "Resources"; @@ -189,65 +196,57 @@ void WebResourceService::Init() { resource_dispatcher_host_ = g_browser_process->resource_dispatcher_host(); web_resource_fetcher_ = new WebResourceFetcher(this); prefs_->RegisterStringPref(prefs::kNTPTipsCacheUpdate, L"0"); - // TODO(mrc): make sure server name is valid. - web_resource_server_ = prefs_->HasPrefPath(prefs::kNTPTipsServer) ? - prefs_->GetString(prefs::kNTPTipsServer) : - kDefaultResourceServer; + + // TODO(mirandac): allow for language change without wiping out prefs file. + if (prefs_->HasPrefPath(prefs::kNTPTipsServer)) { + web_resource_server_ = prefs_->GetString(prefs::kNTPTipsServer); + } else { + web_resource_server_ = kDefaultResourceServer; + web_resource_server_.append( + ASCIIToWide(g_browser_process->GetApplicationLocale())); + } } void WebResourceService::EndFetch() { in_fetch_ = false; } -void WebResourceService::OnWebResourceUnpacked(const ListValue& parsed_json) { +void WebResourceService::OnWebResourceUnpacked( + const DictionaryValue& parsed_json) { // Get dictionary of cached preferences. web_resource_cache_ = prefs_->GetMutableDictionary(prefs::kNTPTipsCache); - ListValue::const_iterator wr_iter = parsed_json.begin(); - int wr_counter = 0; - - // These values store the data for each new web resource item. - std::wstring result_snippet; - std::wstring result_url; - std::wstring result_source; - std::wstring result_title; - std::wstring result_title_type; - std::wstring result_thumbnail; - - // Iterate through newly parsed preferences, replacing stale cache with - // new data. - // TODO(mrc): make this smarter, so it actually only replaces stale data, - // instead of overwriting the whole thing every time. - while (wr_iter != parsed_json.end() && - wr_counter < kMaxResourceCacheSize) { - // Each item is stored in the form of a dictionary. - // See tips_handler.h for format (this will change until - // tip services are solidified!). - if (!(*wr_iter)->IsType(Value::TYPE_DICTIONARY)) - continue; - DictionaryValue* wr_dict = - static_cast<DictionaryValue*>(*wr_iter); - - // Get next space for resource in prefs file. - Value* current_wr; - std::wstring wr_counter_str = IntToWString(wr_counter); - // Create space if it doesn't exist yet. - if (!web_resource_cache_->Get(wr_counter_str, ¤t_wr) || - !current_wr->IsType(Value::TYPE_DICTIONARY)) { - current_wr = new DictionaryValue(); - web_resource_cache_->Set(wr_counter_str, current_wr); - } - DictionaryValue* wr_cache_dict = - static_cast<DictionaryValue*>(current_wr); - // Update the resource cache. - if (wr_dict->GetString(kWebResourceURL, &result_url)) - wr_cache_dict->SetString(kWebResourceURL, result_url); - if (wr_dict->GetString(kWebResourceTitle, &result_title)) - wr_cache_dict->SetString(kWebResourceTitle, result_title); - - wr_counter++; - wr_iter++; + // The list of individual tips. + ListValue* tip_holder = new ListValue(); + web_resource_cache_->Set(WebResourceService::kTipCachePrefName, tip_holder); + + DictionaryValue* topic_dict; + ListValue* answer_list; + std::wstring topic_id; + std::wstring inproduct; + int tip_counter = 0; + + if (parsed_json.GetDictionary(L"topic", &topic_dict)) { + if (topic_dict->GetString(L"topic_id", &topic_id)) + web_resource_cache_->SetString(L"topic_id", topic_id); + if (topic_dict->GetList(L"answers", &answer_list)) { + for (ListValue::const_iterator tip_iter = answer_list->begin(); + tip_iter != answer_list->end(); ++tip_iter) { + if (!(*tip_iter)->IsType(Value::TYPE_DICTIONARY)) + continue; + DictionaryValue* a_dic = + static_cast<DictionaryValue*>(*tip_iter); + if (a_dic->GetString(L"inproduct", &inproduct)) { + tip_holder->Append(Value::CreateStringValue(inproduct)); + } + tip_counter++; + } + // If we have tips, set current tip to zero. + if (!inproduct.empty()) + web_resource_cache_->SetInteger( + WebResourceService::kCurrentTipPrefName, 0); + } } EndFetch(); } diff --git a/chrome/browser/web_resource/web_resource_service.h b/chrome/browser/web_resource/web_resource_service.h index dac392f..caf9d90 100644 --- a/chrome/browser/web_resource/web_resource_service.h +++ b/chrome/browser/web_resource/web_resource_service.h @@ -28,16 +28,11 @@ class WebResourceService // the process that will parse the JSON, and then update the cache. void UpdateResourceCache(const std::string& json_data); - // Right now, these values correspond to data pulled from the popgadget - // JSON feed. Once we have decided on the final format for the - // web resources servers, these will probably change. - static const wchar_t* kWebResourceTitle; - static const wchar_t* kWebResourceURL; + static const wchar_t* kTipDictionaryPrefName; + static const wchar_t* kCurrentTipPrefName; + static const wchar_t* kTipCachePrefName; // Default server from which to gather resources. - // For now, hard-coded to test JSON data hosted on chromium.org. - // Starting 6/22, poptart server will be ready to host data. - // Future: more servers and different kinds of data will be served. static const wchar_t* kDefaultResourceServer; private: @@ -52,7 +47,7 @@ class WebResourceService void EndFetch(); // Puts parsed json data in the right places, and writes to prefs file. - void OnWebResourceUnpacked(const ListValue& parsed_json); + void OnWebResourceUnpacked(const DictionaryValue& parsed_json); // We need to be able to load parsed resource data into preferences file, // and get proper install directory. @@ -85,8 +80,8 @@ class WebResourceService // Delay on first fetch so we don't interfere with startup. static const int kStartResourceFetchDelay = 5000; - // Delay between calls to update the cache (4 hours). - static const int kCacheUpdateDelay = 4 * 60 * 60 * 1000; + // Delay between calls to update the cache (48 hours). + static const int kCacheUpdateDelay = 48 * 60 * 60 * 1000; // Name of directory inside the profile where we will store resource-related // data (for now, thumbnail images). diff --git a/chrome/common/pref_names.cc b/chrome/common/pref_names.cc index 29490f6..f3796a2 100644 --- a/chrome/common/pref_names.cc +++ b/chrome/common/pref_names.cc @@ -561,7 +561,7 @@ const wchar_t kNTPTipsCache[] = L"ntp.tips_cache"; const wchar_t kNTPTipsCacheUpdate[] = L"ntp.tips_cache_update"; // Last server used to fill tips_cache. -const wchar_t kNTPTipsServer[] = L"ntp.web_resource_server"; +const wchar_t kNTPTipsServer[] = L"ntp.tips_server"; // Which sections should be visible on the new tab page // 1 - Show the most visited sites in a grid diff --git a/chrome/common/render_messages_internal.h b/chrome/common/render_messages_internal.h index 891dbb7..83f2c62 100644 --- a/chrome/common/render_messages_internal.h +++ b/chrome/common/render_messages_internal.h @@ -1653,7 +1653,7 @@ IPC_BEGIN_MESSAGES(ViewHost) // Reply when the utility process is done unpacking and parsing JSON data // from a web resource. IPC_MESSAGE_CONTROL1(UtilityHostMsg_UnpackWebResource_Succeeded, - ListValue /* json data */) + DictionaryValue /* json data */) // Reply when the utility process has failed while unpacking and parsing a // web resource. |error_message| is a user-readable explanation of what diff --git a/chrome/common/web_resource/web_resource_unpacker.cc b/chrome/common/web_resource/web_resource_unpacker.cc index a821547..7f0ced4 100644 --- a/chrome/common/web_resource/web_resource_unpacker.cc +++ b/chrome/common/web_resource/web_resource_unpacker.cc @@ -25,11 +25,11 @@ bool WebResourceUnpacker::Run() { error_message_ = kInvalidDataTypeError; return false; } - if (!value->IsType(Value::TYPE_LIST)) { + if (!value->IsType(Value::TYPE_DICTIONARY)) { error_message_ = kUnexpectedJSONFormatError; return false; } - parsed_json_.reset(static_cast<ListValue*>(value.release())); + parsed_json_.reset(static_cast<DictionaryValue*>(value.release())); return true; } error_message_ = kInvalidDataTypeError; diff --git a/chrome/common/web_resource/web_resource_unpacker.h b/chrome/common/web_resource/web_resource_unpacker.h index 194e1c5..95600f9 100644 --- a/chrome/common/web_resource/web_resource_unpacker.h +++ b/chrome/common/web_resource/web_resource_unpacker.h @@ -17,7 +17,7 @@ #include "base/file_path.h" #include "base/scoped_ptr.h" -class ListValue; +class DictionaryValue; class WebResourceUnpacker { public: @@ -35,7 +35,7 @@ class WebResourceUnpacker { const std::string& error_message() { return error_message_; } // Gets data which has been parsed by Run(). - ListValue* parsed_json() { + DictionaryValue* parsed_json() { return parsed_json_.get(); } @@ -44,7 +44,7 @@ class WebResourceUnpacker { std::string resource_data_; // Holds the result of JSON parsing of resource_data_. - scoped_ptr<ListValue> parsed_json_; + scoped_ptr<DictionaryValue> parsed_json_; // Holds the last error message produced by Run(). std::string error_message_; |