Chromium Code Reviews| Index: chrome/browser/ui/autofill/save_card_bubble_controller_impl.cc |
| diff --git a/chrome/browser/ui/autofill/save_card_bubble_controller_impl.cc b/chrome/browser/ui/autofill/save_card_bubble_controller_impl.cc |
| index 2e43699e3f435ffe870588f220a00da460322e94..ecbe43bed0901c9b17348767f5da0cd5820a437e 100644 |
| --- a/chrome/browser/ui/autofill/save_card_bubble_controller_impl.cc |
| +++ b/chrome/browser/ui/autofill/save_card_bubble_controller_impl.cc |
| @@ -4,6 +4,9 @@ |
| #include "chrome/browser/ui/autofill/save_card_bubble_controller_impl.h" |
| +#include "base/i18n/message_formatter.h" |
| +#include "base/strings/string_util.h" |
| +#include "base/strings/utf_string_conversions.h" |
| #include "chrome/browser/ui/autofill/save_card_bubble_view.h" |
| #include "chrome/browser/ui/browser.h" |
| #include "chrome/browser/ui/browser_finder.h" |
| @@ -21,6 +24,115 @@ namespace { |
| // TODO(bondd): Share with ManagePasswordsUIController. |
| const int kSurviveNavigationSeconds = 5; |
| +// Replace "{0}", "{1}", ... in |template_icu| with corresponding strings |
| +// from |display_texts|. Sets |out_message| to the resulting string, with |
| +// start position of each replacement in |out_offsets|. |
| +// Return false on failure. If false is returned then contents of |out_message| |
| +// and |out_offsets| are undefined. |
| +bool ReplaceTemplatePlaceholders( |
| + const base::string16& template_icu, |
| + const std::vector<base::string16>& display_texts, |
| + base::string16& out_message, |
| + std::vector<size_t>& out_offsets) { |
| + // Escape "$" -> "$$" for ReplaceStringPlaceholders(). |
| + // |
| + // Edge cases: |
| + // 1. Two or more consecutive $ characters will be incorrectly expanded |
| + // ("$$" -> "$$$$", which ReplaceStringPlaceholders() then turns into |
| + // "$$$"). |
| + // |
| + // 2. "${" will cause false to be returned. "${0}" will expand to "$${0}". |
| + // FormatWithNumberedArgs() turns it into "$$$1", which |
| + // ReplaceStringPlaceholders() then turns into "$$1" without doing the |
| + // parameter replacement. This causes false to be returned because each |
| + // parameter is not used exactly once. |
| + // |
| + // Both of these cases are noted in the header file, and are unlikely to |
| + // occur in any actual legal message. |
| + base::string16 template_icu_escaped; |
| + base::ReplaceChars(template_icu, base::ASCIIToUTF16("$"), |
| + base::ASCIIToUTF16("$$"), &template_icu_escaped); |
| + |
| + // Replace "{0}" -> "$1", "{1}" -> "$2", ... to prepare |template_dollars| |
| + // for ReplaceStringPlaceholders(). |
| + base::string16 template_dollars = |
| + base::i18n::MessageFormatter::FormatWithNumberedArgs( |
| + template_icu_escaped, "$1", "$2", "$3", "$4", "$5", "$6", "$7"); |
| + |
| + // FormatWithNumberedArgs() returns an empty string on failure. |
| + if (template_dollars.empty() && !template_icu.empty()) |
| + return false; |
| + |
| + // Replace "$1", "$2", ... with the display text of each parameter. |
| + out_message = |
| + ReplaceStringPlaceholders(template_dollars, display_texts, &out_offsets); |
| + |
| + // Each parameter must be used exactly once. If a parameter is unused or |
| + // used more than once then it can't be determined which |offsets| entry |
| + // corresponds to which parameter. |
| + return out_offsets.size() == display_texts.size(); |
| +} |
| + |
| +// Parses |line| and sets |out|. |
| +// Returns false on failure. |out| is not modified if false is returned. |
| +bool ParseLegalMessageLine( |
| + const base::DictionaryValue& line, |
| + autofill::SaveCardBubbleController::LegalMessageLine& out) { |
|
Evan Stade
2015/11/13 01:33:07
outparams must always be pointer type
that said,
bondd
2015/11/13 22:30:43
Done. I made it a pointer.
|
| + autofill::SaveCardBubbleController::LegalMessageLine result; |
| + |
| + // |display_texts| elements are the strings that will be substituted for |
| + // "{0}", "{1}", etc. in the template string. |
| + std::vector<base::string16> display_texts; |
| + |
| + // Process all the template parameters. |
| + const base::ListValue* template_parameters = nullptr; |
| + if (line.GetList("template_parameter", &template_parameters)) { |
| + for (size_t parameter_index = 0; |
| + parameter_index < template_parameters->GetSize(); ++parameter_index) { |
| + // Get a single element of the "template_parameter" list. |
| + const base::DictionaryValue* single_parameter; |
| + if (!template_parameters->GetDictionary(parameter_index, |
| + &single_parameter)) |
| + return false; |
| + |
| + // Read and store the "display_text" string. |
| + display_texts.push_back(base::string16()); |
| + if (!single_parameter->GetString("display_text", &display_texts.back())) |
| + return false; |
| + |
| + // Read and store the "url" string. |
| + result.links.push_back( |
| + autofill::SaveCardBubbleController::LegalMessageLine::Link()); |
| + if (!single_parameter->GetString("url", &result.links.back().url)) |
| + return false; |
| + } |
| + } |
| + |
| + // Read the template string. It's a small subset of the ICU message format |
| + // syntax. |
| + base::string16 template_icu; |
| + if (!line.GetString("template", &template_icu)) |
| + return false; |
| + |
| + // Replace the placeholders in |template_icu| with strings from |
| + // |display_texts|, and store the start position of each replacement in |
| + // |offsets|. |
| + std::vector<size_t> offsets; |
| + if (!ReplaceTemplatePlaceholders(template_icu, display_texts, result.text, |
| + offsets)) |
| + return false; |
| + |
| + // Fill in range values for all links. |
| + for (size_t offset_index = 0; offset_index < offsets.size(); ++offset_index) { |
| + size_t range_start = offsets[offset_index]; |
| + result.links[offset_index].range = gfx::Range( |
| + range_start, range_start + display_texts[offset_index].size()); |
| + } |
| + |
| + out = result; |
| + return true; |
| +} |
| + |
| } // namespace |
| namespace autofill { |
| @@ -42,6 +154,31 @@ void SaveCardBubbleControllerImpl::SetCallback( |
| save_card_callback_ = save_card_callback; |
| } |
| +bool SaveCardBubbleControllerImpl::SetLegalMessage( |
| + const base::ListValue& lines) { |
| + ClearLegalMessage(); |
| + std::vector<LegalMessageLine> parsed_lines; |
|
Evan Stade
2015/11/13 01:33:07
parsed_lines? Why not just legal_message_lines_? I
bondd
2015/11/13 22:30:43
Done.
|
| + |
| + // Process all lines of the message. See comment in header file for example |
| + // of valid |lines| data. |
| + for (size_t line_index = 0; line_index < lines.GetSize(); ++line_index) { |
| + const base::DictionaryValue* single_line; |
| + if (!lines.GetDictionary(line_index, &single_line)) |
| + return false; |
| + |
| + parsed_lines.push_back(LegalMessageLine()); |
| + if (!ParseLegalMessageLine(*single_line, parsed_lines.back())) |
| + return false; |
| + } |
| + |
| + legal_message_lines_ = parsed_lines; |
|
Evan Stade
2015/11/13 01:33:07
if you keep this line you should use swap()
bondd
2015/11/13 22:30:43
Obsolete.
|
| + return true; |
| +} |
| + |
| +void SaveCardBubbleControllerImpl::ClearLegalMessage() { |
|
Evan Stade
2015/11/13 01:33:07
I don't get the purpose of this fn
bondd
2015/11/13 22:30:43
SaveCardBubbleControllerImpl is per tab, and once
Evan Stade
2015/11/14 00:22:49
I would vote for reusing SetLegalMessage, but this
bondd
2015/11/17 00:12:04
Done.
|
| + legal_message_lines_.clear(); |
| +} |
| + |
| void SaveCardBubbleControllerImpl::ShowBubble() { |
| DCHECK(!save_card_callback_.is_null()); |
| @@ -84,9 +221,12 @@ void SaveCardBubbleControllerImpl::OnCancelButton() { |
| } |
| void SaveCardBubbleControllerImpl::OnLearnMoreClicked() { |
| - web_contents()->OpenURL(content::OpenURLParams( |
| - GURL(kHelpURL), content::Referrer(), NEW_FOREGROUND_TAB, |
| - ui::PAGE_TRANSITION_LINK, false)); |
| + OpenUrl(kHelpURL); |
| +} |
| + |
| +void SaveCardBubbleControllerImpl::OnLegalMessageLinkClicked( |
| + const std::string& url) { |
| + OpenUrl(url); |
| } |
| void SaveCardBubbleControllerImpl::OnBubbleClosed() { |
| @@ -94,12 +234,23 @@ void SaveCardBubbleControllerImpl::OnBubbleClosed() { |
| UpdateIcon(); |
| } |
| +const std::vector<SaveCardBubbleController::LegalMessageLine>& |
| +SaveCardBubbleControllerImpl::GetLegalMessageLines() const { |
| + return legal_message_lines_; |
| +} |
| + |
| void SaveCardBubbleControllerImpl::UpdateIcon() { |
| Browser* browser = chrome::FindBrowserWithWebContents(web_contents()); |
| LocationBar* location_bar = browser->window()->GetLocationBar(); |
| location_bar->UpdateSaveCreditCardIcon(); |
| } |
| +void SaveCardBubbleControllerImpl::OpenUrl(const std::string& url) { |
| + web_contents()->OpenURL( |
| + content::OpenURLParams(GURL(url), content::Referrer(), NEW_FOREGROUND_TAB, |
| + ui::PAGE_TRANSITION_LINK, false)); |
| +} |
| + |
| void SaveCardBubbleControllerImpl::DidNavigateMainFrame( |
| const content::LoadCommittedDetails& details, |
| const content::FrameNavigateParams& params) { |