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

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: Address estade@ comments for patch set 14. 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
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
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
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698