Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(62)

Side by Side Diff: chrome/browser/ui/autofill/save_card_bubble_controller_impl.cc

Issue 1407093007: Autofill: Add legal message footer to save credit card bubble. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Rebase. Created 5 years, 1 month ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
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 appends results to |message|, |link_ranges|, and
77 // |link_urls|.
78 // Returns false on failure. If false is returned then contents of output
79 // variables are undefined.
80 bool ParseAndAppendToLegalMessage(const base::DictionaryValue& line,
81 base::string16* message,
82 std::vector<gfx::Range>* link_ranges,
83 std::vector<std::string>* link_urls) {
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 for the current message line.
89 const base::ListValue* template_parameters = nullptr;
90 if (line.GetList("template_parameter", &template_parameters)) {
91 for (size_t parameter_index = 0;
92 parameter_index < template_parameters->GetSize(); ++parameter_index) {
93 // Get a single element of the "template_parameter" list.
94 const base::DictionaryValue* single_parameter;
95 if (!template_parameters->GetDictionary(parameter_index,
96 &single_parameter))
97 return false;
98
99 // Read and store the "display_text" string.
100 display_texts.push_back(base::string16());
101 if (!single_parameter->GetString("display_text", &display_texts.back()))
102 return false;
103
104 // Read and store the "url" string.
105 link_urls->push_back(std::string());
106 if (!single_parameter->GetString("url", &link_urls->back()))
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 base::string16 message_line;
121 std::vector<size_t> offsets;
122 if (!ReplaceTemplatePlaceholders(template_icu, display_texts, message_line,
123 offsets))
124 return false;
125
126 // Fill in range values for all links in this line.
127 for (size_t offset_index = 0; offset_index < offsets.size(); ++offset_index) {
128 size_t range_start = message->size() + offsets[offset_index];
129 link_ranges->push_back(gfx::Range(
130 range_start, range_start + display_texts[offset_index].size()));
131 }
132
133 message->append(message_line);
134 return true;
135 }
136
24 } // namespace 137 } // namespace
25 138
26 namespace autofill { 139 namespace autofill {
27 140
28 SaveCardBubbleControllerImpl::SaveCardBubbleControllerImpl( 141 SaveCardBubbleControllerImpl::SaveCardBubbleControllerImpl(
29 content::WebContents* web_contents) 142 content::WebContents* web_contents)
30 : content::WebContentsObserver(web_contents), 143 : content::WebContentsObserver(web_contents),
31 save_card_bubble_view_(nullptr) { 144 save_card_bubble_view_(nullptr) {
32 DCHECK(web_contents); 145 DCHECK(web_contents);
33 } 146 }
34 147
35 SaveCardBubbleControllerImpl::~SaveCardBubbleControllerImpl() { 148 SaveCardBubbleControllerImpl::~SaveCardBubbleControllerImpl() {
36 if (save_card_bubble_view_) 149 if (save_card_bubble_view_)
37 save_card_bubble_view_->ControllerGone(); 150 save_card_bubble_view_->ControllerGone();
38 } 151 }
39 152
40 void SaveCardBubbleControllerImpl::SetCallback( 153 void SaveCardBubbleControllerImpl::SetCallback(
41 const base::Closure& save_card_callback) { 154 const base::Closure& save_card_callback) {
42 save_card_callback_ = save_card_callback; 155 save_card_callback_ = save_card_callback;
43 } 156 }
44 157
158 bool SaveCardBubbleControllerImpl::SetLegalMessage(
159 const base::ListValue& lines) {
160 ClearLegalMessage();
161 base::string16 message;
162 std::vector<gfx::Range> link_ranges;
163 std::vector<std::string> link_urls;
164
165 // Process all lines of the message. See comment in header file for example
166 // of valid |lines| data.
167 for (size_t line_index = 0; line_index < lines.GetSize(); ++line_index) {
168 const base::DictionaryValue* single_line;
169 if (!lines.GetDictionary(line_index, &single_line))
170 return false;
171
172 if (!ParseAndAppendToLegalMessage(*single_line, &message, &link_ranges,
173 &link_urls))
174 return false;
175
176 // If this is not the last line of the message then append a newline.
177 if (line_index + 1 < lines.GetSize())
178 message.push_back('\n');
179 }
180
181 legal_message_ = message;
182 legal_message_link_ranges_ = link_ranges;
183 legal_message_link_urls_ = link_urls;
184 return true;
185 }
186
187 void SaveCardBubbleControllerImpl::ClearLegalMessage() {
188 legal_message_.clear();
189 legal_message_link_ranges_.clear();
190 legal_message_link_urls_.clear();
191 }
192
45 void SaveCardBubbleControllerImpl::ShowBubble() { 193 void SaveCardBubbleControllerImpl::ShowBubble() {
46 DCHECK(!save_card_callback_.is_null()); 194 DCHECK(!save_card_callback_.is_null());
47 195
48 // Need to create location bar icon before bubble, otherwise bubble will be 196 // Need to create location bar icon before bubble, otherwise bubble will be
49 // unanchored. 197 // unanchored.
50 UpdateIcon(); 198 UpdateIcon();
51 199
52 Browser* browser = chrome::FindBrowserWithWebContents(web_contents()); 200 Browser* browser = chrome::FindBrowserWithWebContents(web_contents());
53 save_card_bubble_view_ = 201 save_card_bubble_view_ =
54 browser->window()->ShowSaveCreditCardBubble(web_contents(), this); 202 browser->window()->ShowSaveCreditCardBubble(web_contents(), this);
(...skipping 22 matching lines...) Expand all
77 void SaveCardBubbleControllerImpl::OnSaveButton() { 225 void SaveCardBubbleControllerImpl::OnSaveButton() {
78 save_card_callback_.Run(); 226 save_card_callback_.Run();
79 save_card_callback_.Reset(); 227 save_card_callback_.Reset();
80 } 228 }
81 229
82 void SaveCardBubbleControllerImpl::OnCancelButton() { 230 void SaveCardBubbleControllerImpl::OnCancelButton() {
83 save_card_callback_.Reset(); 231 save_card_callback_.Reset();
84 } 232 }
85 233
86 void SaveCardBubbleControllerImpl::OnLearnMoreClicked() { 234 void SaveCardBubbleControllerImpl::OnLearnMoreClicked() {
87 web_contents()->OpenURL(content::OpenURLParams( 235 OpenUrl(kHelpURL);
88 GURL(kHelpURL), content::Referrer(), NEW_FOREGROUND_TAB, 236 }
89 ui::PAGE_TRANSITION_LINK, false)); 237
238 void SaveCardBubbleControllerImpl::OnLegalMessageLinkClicked(
239 const gfx::Range& link_range) {
240 for (size_t i = 0; i < legal_message_link_ranges_.size(); ++i) {
241 if (legal_message_link_ranges_[i] == link_range) {
242 OpenUrl(legal_message_link_urls_[i]);
243 return;
244 }
245 }
246 // link_range was not found.
247 NOTREACHED();
90 } 248 }
91 249
92 void SaveCardBubbleControllerImpl::OnBubbleClosed() { 250 void SaveCardBubbleControllerImpl::OnBubbleClosed() {
93 save_card_bubble_view_ = nullptr; 251 save_card_bubble_view_ = nullptr;
94 UpdateIcon(); 252 UpdateIcon();
95 } 253 }
96 254
255 const base::string16& SaveCardBubbleControllerImpl::GetLegalMessage() const {
256 return legal_message_;
257 }
258
259 const std::vector<gfx::Range>&
260 SaveCardBubbleControllerImpl::GetLegalMessageLinkRanges() const {
261 return legal_message_link_ranges_;
262 }
263
264 const std::vector<std::string>&
265 SaveCardBubbleControllerImpl::GetLegalMessageLinkUrlsForTesting() const {
266 return legal_message_link_urls_;
267 }
268
97 void SaveCardBubbleControllerImpl::UpdateIcon() { 269 void SaveCardBubbleControllerImpl::UpdateIcon() {
98 Browser* browser = chrome::FindBrowserWithWebContents(web_contents()); 270 Browser* browser = chrome::FindBrowserWithWebContents(web_contents());
99 LocationBar* location_bar = browser->window()->GetLocationBar(); 271 LocationBar* location_bar = browser->window()->GetLocationBar();
100 location_bar->UpdateSaveCreditCardIcon(); 272 location_bar->UpdateSaveCreditCardIcon();
101 } 273 }
102 274
275 void SaveCardBubbleControllerImpl::OpenUrl(const std::string& url) {
276 web_contents()->OpenURL(
277 content::OpenURLParams(GURL(url), content::Referrer(), NEW_FOREGROUND_TAB,
278 ui::PAGE_TRANSITION_LINK, false));
279 }
280
103 void SaveCardBubbleControllerImpl::DidNavigateMainFrame( 281 void SaveCardBubbleControllerImpl::DidNavigateMainFrame(
104 const content::LoadCommittedDetails& details, 282 const content::LoadCommittedDetails& details,
105 const content::FrameNavigateParams& params) { 283 const content::FrameNavigateParams& params) {
106 // Nothing to do if there's no bubble available. 284 // Nothing to do if there's no bubble available.
107 if (save_card_callback_.is_null()) 285 if (save_card_callback_.is_null())
108 return; 286 return;
109 287
110 // Don't react to in-page (fragment) navigations. 288 // Don't react to in-page (fragment) navigations.
111 if (details.is_in_page) 289 if (details.is_in_page)
112 return; 290 return;
113 291
114 // Don't do anything if a navigation occurs before a user could reasonably 292 // Don't do anything if a navigation occurs before a user could reasonably
115 // interact with the bubble. 293 // interact with the bubble.
116 if (timer_->Elapsed() < 294 if (timer_->Elapsed() <
117 base::TimeDelta::FromSeconds(kSurviveNavigationSeconds)) 295 base::TimeDelta::FromSeconds(kSurviveNavigationSeconds))
118 return; 296 return;
119 297
120 // Otherwise, get rid of the bubble and icon. 298 // Otherwise, get rid of the bubble and icon.
121 save_card_callback_.Reset(); 299 save_card_callback_.Reset();
122 if (save_card_bubble_view_) 300 if (save_card_bubble_view_)
123 save_card_bubble_view_->Close(); 301 save_card_bubble_view_->Close();
124 else 302 else
125 UpdateIcon(); 303 UpdateIcon();
126 } 304 }
127 305
128 } // namespace autofill 306 } // namespace autofill
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698