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