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 |
| 20 namespace autofill { | |
| 21 | |
| 17 namespace { | 22 namespace { |
| 18 | 23 |
| 19 // Number of seconds the bubble and icon will survive navigations, starting | 24 // Number of seconds the bubble and icon will survive navigations, starting |
| 20 // from when the bubble is shown. | 25 // from when the bubble is shown. |
| 21 // TODO(bondd): Share with ManagePasswordsUIController. | 26 // TODO(bondd): Share with ManagePasswordsUIController. |
| 22 const int kSurviveNavigationSeconds = 5; | 27 const int kSurviveNavigationSeconds = 5; |
| 23 | 28 |
| 29 // Replace "{0}", "{1}", ... in |template_icu| with corresponding strings | |
| 30 // from |display_texts|. Sets |out_message| to the resulting string, with | |
| 31 // start position of each replacement in |out_offsets|. | |
| 32 // Return false on failure. If false is returned then contents of |out_message| | |
| 33 // and |out_offsets| are undefined. | |
| 34 bool ReplaceTemplatePlaceholders( | |
| 35 const base::string16& template_icu, | |
| 36 const std::vector<base::string16>& display_texts, | |
| 37 base::string16* out_message, | |
| 38 std::vector<size_t>* out_offsets) { | |
| 39 // Escape "$" -> "$$" for ReplaceStringPlaceholders(). | |
| 40 // | |
| 41 // Edge cases: | |
| 42 // 1. Two or more consecutive $ characters will be incorrectly expanded | |
| 43 // ("$$" -> "$$$$", which ReplaceStringPlaceholders() then turns into | |
| 44 // "$$$"). | |
| 45 // | |
| 46 // 2. "${" will cause false to be returned. "${0}" will expand to "$${0}". | |
| 47 // FormatWithNumberedArgs() turns it into "$$$1", which | |
| 48 // ReplaceStringPlaceholders() then turns into "$$1" without doing the | |
| 49 // parameter replacement. This causes false to be returned because each | |
| 50 // parameter is not used exactly once. | |
| 51 // | |
| 52 // Both of these cases are noted in the header file, and are unlikely to | |
| 53 // occur in any actual legal message. | |
| 54 base::string16 template_icu_escaped; | |
| 55 base::ReplaceChars(template_icu, base::ASCIIToUTF16("$"), | |
| 56 base::ASCIIToUTF16("$$"), &template_icu_escaped); | |
| 57 | |
| 58 // Replace "{0}" -> "$1", "{1}" -> "$2", ... to prepare |template_dollars| | |
| 59 // for ReplaceStringPlaceholders(). | |
| 60 base::string16 template_dollars = | |
| 61 base::i18n::MessageFormatter::FormatWithNumberedArgs( | |
| 62 template_icu_escaped, "$1", "$2", "$3", "$4", "$5", "$6", "$7"); | |
| 63 | |
| 64 // FormatWithNumberedArgs() returns an empty string on failure. | |
| 65 if (template_dollars.empty() && !template_icu.empty()) | |
| 66 return false; | |
| 67 | |
| 68 // Replace "$1", "$2", ... with the display text of each parameter. | |
| 69 *out_message = base::ReplaceStringPlaceholders(template_dollars, | |
| 70 display_texts, out_offsets); | |
| 71 | |
| 72 // Each parameter must be used exactly once. If a parameter is unused or | |
| 73 // used more than once then it can't be determined which |offsets| entry | |
| 74 // corresponds to which parameter. | |
| 75 return out_offsets->size() == display_texts.size(); | |
| 76 } | |
| 77 | |
| 78 // Parses |line| and sets |out|. | |
| 79 // Returns false on failure. |out| is not modified if false is returned. | |
| 80 bool ParseLegalMessageLine(const base::DictionaryValue& line, | |
| 81 SaveCardBubbleController::LegalMessageLine* out) { | |
| 82 SaveCardBubbleController::LegalMessageLine result; | |
| 83 | |
| 84 // |display_texts| elements are the strings that will be substituted for | |
| 85 // "{0}", "{1}", etc. in the template string. | |
| 86 std::vector<base::string16> display_texts; | |
| 87 | |
| 88 // Process all the template parameters. | |
| 89 const base::ListValue* template_parameters = nullptr; | |
| 90 if (line.GetList("template_parameter", &template_parameters)) { | |
| 91 display_texts.resize(template_parameters->GetSize()); | |
| 92 result.links.resize(template_parameters->GetSize()); | |
| 93 | |
| 94 for (size_t parameter_index = 0; | |
| 95 parameter_index < template_parameters->GetSize(); ++parameter_index) { | |
| 96 // Get a single element of the "template_parameter" list. | |
| 97 const base::DictionaryValue* single_parameter; | |
| 98 if (!template_parameters->GetDictionary(parameter_index, | |
| 99 &single_parameter)) { | |
| 100 return false; | |
| 101 } | |
| 102 | |
| 103 // Read and store the "display_text" string. | |
|
Evan Stade
2015/11/19 03:22:43
combine these 3 conditionals
also this comment is
bondd
2015/11/20 02:58:54
Done.
| |
| 104 if (!single_parameter->GetString("display_text", | |
| 105 &display_texts[parameter_index])) { | |
| 106 return false; | |
| 107 } | |
| 108 | |
| 109 // Read and store the "url" string. | |
| 110 std::string url; | |
| 111 if (!single_parameter->GetString("url", &url)) | |
| 112 return false; | |
| 113 result.links[parameter_index].url = GURL(url); | |
| 114 } | |
| 115 } | |
| 116 | |
| 117 // Read the template string. It's a small subset of the ICU message format | |
| 118 // syntax. | |
| 119 base::string16 template_icu; | |
| 120 if (!line.GetString("template", &template_icu)) | |
| 121 return false; | |
| 122 | |
| 123 // Replace the placeholders in |template_icu| with strings from | |
| 124 // |display_texts|, and store the start position of each replacement in | |
| 125 // |offsets|. | |
| 126 std::vector<size_t> offsets; | |
| 127 if (!ReplaceTemplatePlaceholders(template_icu, display_texts, &result.text, | |
| 128 &offsets)) { | |
| 129 return false; | |
| 130 } | |
| 131 | |
| 132 // Fill in range values for all links. | |
| 133 for (size_t offset_index = 0; offset_index < offsets.size(); ++offset_index) { | |
| 134 size_t range_start = offsets[offset_index]; | |
| 135 result.links[offset_index].range = gfx::Range( | |
| 136 range_start, range_start + display_texts[offset_index].size()); | |
| 137 } | |
| 138 | |
| 139 *out = result; | |
| 140 return true; | |
| 141 } | |
| 142 | |
| 24 } // namespace | 143 } // namespace |
| 25 | 144 |
| 26 namespace autofill { | |
| 27 | |
| 28 SaveCardBubbleControllerImpl::SaveCardBubbleControllerImpl( | 145 SaveCardBubbleControllerImpl::SaveCardBubbleControllerImpl( |
| 29 content::WebContents* web_contents) | 146 content::WebContents* web_contents) |
| 30 : content::WebContentsObserver(web_contents), | 147 : content::WebContentsObserver(web_contents), |
| 31 save_card_bubble_view_(nullptr) { | 148 save_card_bubble_view_(nullptr) { |
| 32 DCHECK(web_contents); | 149 DCHECK(web_contents); |
| 33 } | 150 } |
| 34 | 151 |
| 35 SaveCardBubbleControllerImpl::~SaveCardBubbleControllerImpl() { | 152 SaveCardBubbleControllerImpl::~SaveCardBubbleControllerImpl() { |
| 36 if (save_card_bubble_view_) | 153 if (save_card_bubble_view_) |
| 37 save_card_bubble_view_->Hide(); | 154 save_card_bubble_view_->Hide(); |
| 38 } | 155 } |
| 39 | 156 |
| 40 void SaveCardBubbleControllerImpl::SetCallback( | 157 void SaveCardBubbleControllerImpl::SetCallback( |
| 41 const base::Closure& save_card_callback) { | 158 const base::Closure& save_card_callback) { |
| 42 save_card_callback_ = save_card_callback; | 159 save_card_callback_ = save_card_callback; |
| 43 } | 160 } |
| 44 | 161 |
| 162 bool SaveCardBubbleControllerImpl::SetLegalMessage( | |
| 163 const base::ListValue& lines) { | |
| 164 // Process all lines of the message. See comment in header file for example | |
| 165 // of valid |lines| data. | |
| 166 legal_message_lines_.resize(lines.GetSize()); | |
| 167 for (size_t i = 0; i < lines.GetSize(); ++i) { | |
| 168 const base::DictionaryValue* single_line; | |
| 169 if (!lines.GetDictionary(i, &single_line) || | |
| 170 !ParseLegalMessageLine(*single_line, &legal_message_lines_[i])) { | |
| 171 legal_message_lines_.clear(); | |
| 172 return false; | |
| 173 } | |
| 174 } | |
| 175 | |
| 176 return true; | |
| 177 } | |
| 178 | |
| 45 void SaveCardBubbleControllerImpl::ShowBubble(bool user_action) { | 179 void SaveCardBubbleControllerImpl::ShowBubble(bool user_action) { |
| 46 DCHECK(!save_card_callback_.is_null()); | 180 DCHECK(!save_card_callback_.is_null()); |
| 47 | 181 |
| 48 // Need to create location bar icon before bubble, otherwise bubble will be | 182 // Need to create location bar icon before bubble, otherwise bubble will be |
| 49 // unanchored. | 183 // unanchored. |
| 50 UpdateIcon(); | 184 UpdateIcon(); |
| 51 | 185 |
| 52 Browser* browser = chrome::FindBrowserWithWebContents(web_contents()); | 186 Browser* browser = chrome::FindBrowserWithWebContents(web_contents()); |
| 53 save_card_bubble_view_ = browser->window()->ShowSaveCreditCardBubble( | 187 save_card_bubble_view_ = browser->window()->ShowSaveCreditCardBubble( |
| 54 web_contents(), this, user_action); | 188 web_contents(), this, user_action); |
| (...skipping 18 matching lines...) Expand all Loading... | |
| 73 void SaveCardBubbleControllerImpl::OnSaveButton() { | 207 void SaveCardBubbleControllerImpl::OnSaveButton() { |
| 74 save_card_callback_.Run(); | 208 save_card_callback_.Run(); |
| 75 save_card_callback_.Reset(); | 209 save_card_callback_.Reset(); |
| 76 } | 210 } |
| 77 | 211 |
| 78 void SaveCardBubbleControllerImpl::OnCancelButton() { | 212 void SaveCardBubbleControllerImpl::OnCancelButton() { |
| 79 save_card_callback_.Reset(); | 213 save_card_callback_.Reset(); |
| 80 } | 214 } |
| 81 | 215 |
| 82 void SaveCardBubbleControllerImpl::OnLearnMoreClicked() { | 216 void SaveCardBubbleControllerImpl::OnLearnMoreClicked() { |
| 83 web_contents()->OpenURL(content::OpenURLParams( | 217 OpenUrl(GURL(kHelpURL)); |
| 84 GURL(kHelpURL), content::Referrer(), NEW_FOREGROUND_TAB, | 218 } |
| 85 ui::PAGE_TRANSITION_LINK, false)); | 219 |
| 220 void SaveCardBubbleControllerImpl::OnLegalMessageLinkClicked(const GURL& url) { | |
| 221 OpenUrl(url); | |
| 86 } | 222 } |
| 87 | 223 |
| 88 void SaveCardBubbleControllerImpl::OnBubbleClosed() { | 224 void SaveCardBubbleControllerImpl::OnBubbleClosed() { |
| 89 save_card_bubble_view_ = nullptr; | 225 save_card_bubble_view_ = nullptr; |
| 90 UpdateIcon(); | 226 UpdateIcon(); |
| 91 } | 227 } |
| 92 | 228 |
| 229 const SaveCardBubbleController::LegalMessageLines& | |
| 230 SaveCardBubbleControllerImpl::GetLegalMessageLines() const { | |
| 231 return legal_message_lines_; | |
| 232 } | |
| 233 | |
| 93 void SaveCardBubbleControllerImpl::UpdateIcon() { | 234 void SaveCardBubbleControllerImpl::UpdateIcon() { |
| 94 Browser* browser = chrome::FindBrowserWithWebContents(web_contents()); | 235 Browser* browser = chrome::FindBrowserWithWebContents(web_contents()); |
| 95 LocationBar* location_bar = browser->window()->GetLocationBar(); | 236 LocationBar* location_bar = browser->window()->GetLocationBar(); |
| 96 location_bar->UpdateSaveCreditCardIcon(); | 237 location_bar->UpdateSaveCreditCardIcon(); |
| 97 } | 238 } |
| 98 | 239 |
| 240 void SaveCardBubbleControllerImpl::OpenUrl(const GURL& url) { | |
| 241 web_contents()->OpenURL( | |
| 242 content::OpenURLParams(url, content::Referrer(), NEW_FOREGROUND_TAB, | |
| 243 ui::PAGE_TRANSITION_LINK, false)); | |
| 244 } | |
| 245 | |
| 99 void SaveCardBubbleControllerImpl::DidNavigateMainFrame( | 246 void SaveCardBubbleControllerImpl::DidNavigateMainFrame( |
| 100 const content::LoadCommittedDetails& details, | 247 const content::LoadCommittedDetails& details, |
| 101 const content::FrameNavigateParams& params) { | 248 const content::FrameNavigateParams& params) { |
| 102 // Nothing to do if there's no bubble available. | 249 // Nothing to do if there's no bubble available. |
| 103 if (save_card_callback_.is_null()) | 250 if (save_card_callback_.is_null()) |
| 104 return; | 251 return; |
| 105 | 252 |
| 106 // Don't react to in-page (fragment) navigations. | 253 // Don't react to in-page (fragment) navigations. |
| 107 if (details.is_in_page) | 254 if (details.is_in_page) |
| 108 return; | 255 return; |
| 109 | 256 |
| 110 // Don't do anything if a navigation occurs before a user could reasonably | 257 // Don't do anything if a navigation occurs before a user could reasonably |
| 111 // interact with the bubble. | 258 // interact with the bubble. |
| 112 if (timer_->Elapsed() < | 259 if (timer_->Elapsed() < |
| 113 base::TimeDelta::FromSeconds(kSurviveNavigationSeconds)) | 260 base::TimeDelta::FromSeconds(kSurviveNavigationSeconds)) |
| 114 return; | 261 return; |
| 115 | 262 |
| 116 // Otherwise, get rid of the bubble and icon. | 263 // Otherwise, get rid of the bubble and icon. |
| 117 save_card_callback_.Reset(); | 264 save_card_callback_.Reset(); |
| 118 if (save_card_bubble_view_) { | 265 if (save_card_bubble_view_) { |
| 119 save_card_bubble_view_->Hide(); | 266 save_card_bubble_view_->Hide(); |
| 120 OnBubbleClosed(); | 267 OnBubbleClosed(); |
| 121 } else { | 268 } else { |
| 122 UpdateIcon(); | 269 UpdateIcon(); |
| 123 } | 270 } |
| 124 } | 271 } |
| 125 | 272 |
| 126 } // namespace autofill | 273 } // namespace autofill |
| OLD | NEW |