Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright 2015 The Chromium Authors. All rights reserved. | 1 // Copyright 2015 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "chrome/browser/ui/autofill/save_card_bubble_controller_impl.h" | 5 #include "chrome/browser/ui/autofill/save_card_bubble_controller_impl.h" |
| 6 | 6 |
| 7 #include "base/i18n/message_formatter.h" | |
| 8 #include "base/strings/string_util.h" | |
| 9 #include "base/strings/utf_string_conversions.h" | |
| 7 #include "chrome/browser/ui/autofill/save_card_bubble_view.h" | 10 #include "chrome/browser/ui/autofill/save_card_bubble_view.h" |
| 8 #include "chrome/browser/ui/browser.h" | 11 #include "chrome/browser/ui/browser.h" |
| 9 #include "chrome/browser/ui/browser_finder.h" | 12 #include "chrome/browser/ui/browser_finder.h" |
| 10 #include "chrome/browser/ui/browser_window.h" | 13 #include "chrome/browser/ui/browser_window.h" |
| 11 #include "chrome/browser/ui/location_bar/location_bar.h" | 14 #include "chrome/browser/ui/location_bar/location_bar.h" |
| 12 #include "components/autofill/core/common/autofill_constants.h" | 15 #include "components/autofill/core/common/autofill_constants.h" |
| 13 #include "content/public/browser/navigation_details.h" | 16 #include "content/public/browser/navigation_details.h" |
| 14 | 17 |
| 15 DEFINE_WEB_CONTENTS_USER_DATA_KEY(autofill::SaveCardBubbleControllerImpl); | 18 DEFINE_WEB_CONTENTS_USER_DATA_KEY(autofill::SaveCardBubbleControllerImpl); |
| 16 | 19 |
| (...skipping 18 matching lines...) Expand all Loading... | |
| 35 SaveCardBubbleControllerImpl::~SaveCardBubbleControllerImpl() { | 38 SaveCardBubbleControllerImpl::~SaveCardBubbleControllerImpl() { |
| 36 if (save_card_bubble_view_) | 39 if (save_card_bubble_view_) |
| 37 save_card_bubble_view_->ControllerGone(); | 40 save_card_bubble_view_->ControllerGone(); |
| 38 } | 41 } |
| 39 | 42 |
| 40 void SaveCardBubbleControllerImpl::SetCallback( | 43 void SaveCardBubbleControllerImpl::SetCallback( |
| 41 const base::Closure& save_card_callback) { | 44 const base::Closure& save_card_callback) { |
| 42 save_card_callback_ = save_card_callback; | 45 save_card_callback_ = save_card_callback; |
| 43 } | 46 } |
| 44 | 47 |
| 48 bool SaveCardBubbleControllerImpl::SetLegalMessage( | |
|
bondd
2015/11/07 02:29:38
I'll add some unit tests for SetLegalMessage() unl
Evan Stade
2015/11/07 03:03:19
this function needs unit tests
| |
| 49 const base::ListValue& lines) { | |
| 50 ClearLegalMessage(); | |
| 51 base::string16 message; | |
| 52 size_t next_range_index = 0; | |
|
Evan Stade
2015/11/07 03:03:19
|next_range_index| is not intuitive at all and req
bondd
2015/11/11 01:53:36
Done.
| |
| 53 | |
| 54 // Process all lines of the message. See comment in header file for example | |
| 55 // of valid |lines| data. | |
| 56 for (size_t line_index = 0; line_index < lines.GetSize(); ++line_index) { | |
| 57 const base::DictionaryValue* single_line; | |
| 58 if (!lines.GetDictionary(line_index, &single_line)) | |
| 59 return false; | |
| 60 | |
| 61 // |display_texts| elements are the strings that will be substituted for | |
| 62 // "{0}", "{1}", etc. in the template string. | |
| 63 std::vector<base::string16> display_texts; | |
| 64 | |
| 65 // Process all the template parameters for the current message line. | |
| 66 const base::ListValue* template_parameters = nullptr; | |
| 67 if (single_line->GetList("template_parameter", &template_parameters)) { | |
| 68 for (size_t parameter_index = 0; | |
| 69 parameter_index < template_parameters->GetSize(); | |
| 70 ++parameter_index) { | |
| 71 // Get a single element of the "template_parameter" list. | |
| 72 const base::DictionaryValue* single_parameter; | |
| 73 if (!template_parameters->GetDictionary(parameter_index, | |
| 74 &single_parameter)) | |
| 75 return false; | |
| 76 | |
| 77 // Read and store the "display_text" string. | |
| 78 base::string16 text; | |
|
Evan Stade
2015/11/07 03:03:19
display_texts.push_back(base::string16());
if (!si
bondd
2015/11/11 01:53:36
Done.
| |
| 79 if (!single_parameter->GetString("display_text", &text)) | |
| 80 return false; | |
| 81 display_texts.push_back(text); | |
| 82 | |
| 83 // Read and store the "url" string. | |
| 84 LegalMessageLink link; | |
|
Evan Stade
2015/11/07 03:03:19
ditto
bondd
2015/11/11 01:53:36
Done.
| |
| 85 if (!single_parameter->GetString("url", &link.url)) | |
| 86 return false; | |
| 87 legal_message_links_.push_back(link); | |
| 88 } | |
| 89 } | |
| 90 | |
| 91 // Read the template string. It's a small subset of the ICU message format | |
| 92 // syntax. | |
| 93 base::string16 template_icu; | |
| 94 if (!single_line->GetString("template", &template_icu)) | |
|
Evan Stade
2015/11/07 03:03:19
this function is pretty long and hard to read, can
bondd
2015/11/11 01:53:36
Done. I think the new level of splitting makes sen
| |
| 95 return false; | |
| 96 | |
| 97 // Escape "$" -> "$$" for ReplaceStringPlaceholders(). | |
| 98 // | |
| 99 // Edge cases: | |
| 100 // 1. Two or more consecutive $ characters will be incorrectly expanded | |
| 101 // ("$$" -> "$$$$", which ReplaceStringPlaceholders() then turns into | |
| 102 // "$$$"). | |
| 103 // | |
| 104 // 2. "${" will cause false to be returned. "${0}" will expand to "$${0}". | |
| 105 // FormatWithNumberedArgs() turns it into "$$$1", which | |
| 106 // ReplaceStringPlaceholders() then turns into "$$1" without doing the | |
| 107 // parameter replacement. This causes false to be returned because each | |
| 108 // parameter is not used exactly once. | |
| 109 // | |
| 110 // Both of these cases are noted in the header file, and are unlikely to | |
| 111 // occur in any actual legal message. | |
| 112 base::ReplaceChars(template_icu, base::ASCIIToUTF16("$"), | |
| 113 base::ASCIIToUTF16("$$"), &template_icu); | |
| 114 | |
| 115 // Replace "{0}" -> "$1", "{1}" -> "$2", ... to prepare |template_dollars| | |
| 116 // for ReplaceStringPlaceholders(). | |
| 117 base::string16 template_dollars = | |
| 118 base::i18n::MessageFormatter::FormatWithNumberedArgs( | |
| 119 template_icu, "$1", "$2", "$3", "$4", "$5", "$6", "$7"); | |
| 120 | |
| 121 // FormatWithNumberedArgs() returns an empty string on failure. | |
| 122 if (template_dollars.empty() && !template_icu.empty()) | |
| 123 return false; | |
| 124 | |
| 125 // Replace "$1", "$2", ... with the display text of each parameter. | |
| 126 std::vector<size_t> offsets; | |
| 127 base::string16 message_line = | |
| 128 ReplaceStringPlaceholders(template_dollars, display_texts, &offsets); | |
| 129 | |
| 130 // Each parameter must be used exactly once. If a parameter is unused or | |
| 131 // used more than once then it can't be determined which |offsets| entry | |
| 132 // corresponds to which parameter. | |
| 133 if (offsets.size() != display_texts.size()) | |
| 134 return false; | |
| 135 | |
| 136 // Fill in |range| values for all links in this line. | |
| 137 for (size_t offset_index = 0; offset_index < offsets.size(); | |
| 138 ++offset_index) { | |
| 139 size_t range_start = message.size() + offsets[offset_index]; | |
| 140 legal_message_links_[next_range_index++].range = gfx::Range( | |
| 141 range_start, range_start + display_texts[offset_index].size()); | |
| 142 } | |
| 143 | |
| 144 // |message_line| is now the final line that will be displayed. Append it to | |
| 145 // |message|, along with a newline if there will be another line after this | |
| 146 // one. | |
| 147 message.append(message_line); | |
| 148 if (line_index + 1 < lines.GetSize()) | |
| 149 message.push_back('\n'); | |
| 150 } | |
| 151 | |
| 152 legal_message_ = message; | |
|
Evan Stade
2015/11/07 03:03:19
so legal_message_ will be empty on failure but leg
bondd
2015/11/11 01:53:36
Done. Everything is now empty on failure.
| |
| 153 return true; | |
| 154 } | |
| 155 | |
| 156 void SaveCardBubbleControllerImpl::ClearLegalMessage() { | |
| 157 legal_message_.clear(); | |
| 158 legal_message_links_.clear(); | |
| 159 } | |
| 160 | |
| 45 void SaveCardBubbleControllerImpl::ShowBubble() { | 161 void SaveCardBubbleControllerImpl::ShowBubble() { |
| 46 DCHECK(!save_card_callback_.is_null()); | 162 DCHECK(!save_card_callback_.is_null()); |
| 47 | 163 |
| 48 // Need to create location bar icon before bubble, otherwise bubble will be | 164 // Need to create location bar icon before bubble, otherwise bubble will be |
| 49 // unanchored. | 165 // unanchored. |
| 50 UpdateIcon(); | 166 UpdateIcon(); |
| 51 | 167 |
| 52 Browser* browser = chrome::FindBrowserWithWebContents(web_contents()); | 168 Browser* browser = chrome::FindBrowserWithWebContents(web_contents()); |
| 53 save_card_bubble_view_ = | 169 save_card_bubble_view_ = |
| 54 browser->window()->ShowSaveCreditCardBubble(web_contents(), this); | 170 browser->window()->ShowSaveCreditCardBubble(web_contents(), this); |
| (...skipping 22 matching lines...) Expand all Loading... | |
| 77 void SaveCardBubbleControllerImpl::OnSaveButton() { | 193 void SaveCardBubbleControllerImpl::OnSaveButton() { |
| 78 save_card_callback_.Run(); | 194 save_card_callback_.Run(); |
| 79 save_card_callback_.Reset(); | 195 save_card_callback_.Reset(); |
| 80 } | 196 } |
| 81 | 197 |
| 82 void SaveCardBubbleControllerImpl::OnCancelButton() { | 198 void SaveCardBubbleControllerImpl::OnCancelButton() { |
| 83 save_card_callback_.Reset(); | 199 save_card_callback_.Reset(); |
| 84 } | 200 } |
| 85 | 201 |
| 86 void SaveCardBubbleControllerImpl::OnLearnMoreClicked() { | 202 void SaveCardBubbleControllerImpl::OnLearnMoreClicked() { |
| 87 web_contents()->OpenURL(content::OpenURLParams( | 203 OpenUrl(kHelpURL); |
| 88 GURL(kHelpURL), content::Referrer(), NEW_FOREGROUND_TAB, | 204 } |
| 89 ui::PAGE_TRANSITION_LINK, false)); | 205 |
| 206 void SaveCardBubbleControllerImpl::OnLegalMessageLinkClicked( | |
| 207 const gfx::Range& link_range) { | |
| 208 for (size_t i = 0; i < legal_message_links_.size(); ++i) { | |
| 209 if (legal_message_links_[i].range == link_range) { | |
| 210 OpenUrl(legal_message_links_[i].url); | |
| 211 return; | |
| 212 } | |
| 213 } | |
| 214 // link_range was not found. | |
| 215 NOTREACHED(); | |
| 90 } | 216 } |
| 91 | 217 |
| 92 void SaveCardBubbleControllerImpl::OnBubbleClosed() { | 218 void SaveCardBubbleControllerImpl::OnBubbleClosed() { |
| 93 save_card_bubble_view_ = nullptr; | 219 save_card_bubble_view_ = nullptr; |
| 94 UpdateIcon(); | 220 UpdateIcon(); |
| 95 } | 221 } |
| 96 | 222 |
| 223 const base::string16& SaveCardBubbleControllerImpl::GetLegalMessage() const { | |
| 224 return legal_message_; | |
| 225 } | |
| 226 | |
| 227 size_t SaveCardBubbleControllerImpl::GetLegalMessageNumLinks() const { | |
| 228 return legal_message_links_.size(); | |
| 229 } | |
| 230 | |
| 231 const gfx::Range& SaveCardBubbleControllerImpl::GetLegalMessageLinkRange( | |
| 232 size_t index) const { | |
| 233 return legal_message_links_[index].range; | |
| 234 } | |
| 235 | |
| 97 void SaveCardBubbleControllerImpl::UpdateIcon() { | 236 void SaveCardBubbleControllerImpl::UpdateIcon() { |
| 98 Browser* browser = chrome::FindBrowserWithWebContents(web_contents()); | 237 Browser* browser = chrome::FindBrowserWithWebContents(web_contents()); |
| 99 LocationBar* location_bar = browser->window()->GetLocationBar(); | 238 LocationBar* location_bar = browser->window()->GetLocationBar(); |
| 100 location_bar->UpdateSaveCreditCardIcon(); | 239 location_bar->UpdateSaveCreditCardIcon(); |
| 101 } | 240 } |
| 102 | 241 |
| 242 void SaveCardBubbleControllerImpl::OpenUrl(const std::string& url) { | |
| 243 web_contents()->OpenURL( | |
| 244 content::OpenURLParams(GURL(url), content::Referrer(), NEW_FOREGROUND_TAB, | |
| 245 ui::PAGE_TRANSITION_LINK, false)); | |
| 246 } | |
| 247 | |
| 103 void SaveCardBubbleControllerImpl::DidNavigateMainFrame( | 248 void SaveCardBubbleControllerImpl::DidNavigateMainFrame( |
| 104 const content::LoadCommittedDetails& details, | 249 const content::LoadCommittedDetails& details, |
| 105 const content::FrameNavigateParams& params) { | 250 const content::FrameNavigateParams& params) { |
| 106 // Nothing to do if there's no bubble available. | 251 // Nothing to do if there's no bubble available. |
| 107 if (save_card_callback_.is_null()) | 252 if (save_card_callback_.is_null()) |
| 108 return; | 253 return; |
| 109 | 254 |
| 110 // Don't react to in-page (fragment) navigations. | 255 // Don't react to in-page (fragment) navigations. |
| 111 if (details.is_in_page) | 256 if (details.is_in_page) |
| 112 return; | 257 return; |
| 113 | 258 |
| 114 // Don't do anything if a navigation occurs before a user could reasonably | 259 // Don't do anything if a navigation occurs before a user could reasonably |
| 115 // interact with the bubble. | 260 // interact with the bubble. |
| 116 if (timer_->Elapsed() < | 261 if (timer_->Elapsed() < |
| 117 base::TimeDelta::FromSeconds(kSurviveNavigationSeconds)) | 262 base::TimeDelta::FromSeconds(kSurviveNavigationSeconds)) |
| 118 return; | 263 return; |
| 119 | 264 |
| 120 // Otherwise, get rid of the bubble and icon. | 265 // Otherwise, get rid of the bubble and icon. |
| 121 save_card_callback_.Reset(); | 266 save_card_callback_.Reset(); |
| 122 if (save_card_bubble_view_) | 267 if (save_card_bubble_view_) |
| 123 save_card_bubble_view_->Close(); | 268 save_card_bubble_view_->Close(); |
| 124 else | 269 else |
| 125 UpdateIcon(); | 270 UpdateIcon(); |
| 126 } | 271 } |
| 127 | 272 |
| 128 } // namespace autofill | 273 } // namespace autofill |
| OLD | NEW |