OLD | NEW |
1 // Copyright 2016 The Chromium Authors. All rights reserved. | 1 // Copyright 2016 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/javascript_dialogs/javascript_dialog_tab_helper.h" | 5 #include "chrome/browser/ui/javascript_dialogs/javascript_dialog_tab_helper.h" |
6 | 6 |
7 #include "base/bind.h" | 7 #include "base/bind.h" |
8 #include "base/callback.h" | 8 #include "base/callback.h" |
9 #include "base/feature_list.h" | 9 #include "base/feature_list.h" |
10 #include "base/metrics/histogram_macros.h" | 10 #include "base/metrics/histogram_macros.h" |
11 #include "chrome/browser/engagement/site_engagement_service.h" | 11 #include "chrome/browser/engagement/site_engagement_service.h" |
12 #include "chrome/browser/profiles/profile.h" | 12 #include "chrome/browser/profiles/profile.h" |
13 #include "chrome/browser/ui/browser.h" | 13 #include "chrome/browser/ui/browser.h" |
14 #include "chrome/browser/ui/browser_list.h" | 14 #include "chrome/browser/ui/browser_list.h" |
15 #include "chrome/browser/ui/tab_modal_confirm_dialog.h" | 15 #include "chrome/browser/ui/tab_modal_confirm_dialog.h" |
16 #include "chrome/browser/ui/tabs/tab_strip_model.h" | 16 #include "chrome/browser/ui/tabs/tab_strip_model.h" |
17 #include "chrome/common/chrome_features.h" | |
18 #include "components/app_modal/javascript_dialog_manager.h" | 17 #include "components/app_modal/javascript_dialog_manager.h" |
19 #include "content/public/browser/navigation_handle.h" | 18 #include "content/public/browser/navigation_handle.h" |
20 #include "content/public/browser/render_frame_host.h" | 19 #include "content/public/browser/render_frame_host.h" |
21 #include "ui/gfx/text_elider.h" | 20 #include "ui/gfx/text_elider.h" |
22 | 21 |
23 DEFINE_WEB_CONTENTS_USER_DATA_KEY(JavaScriptDialogTabHelper); | 22 DEFINE_WEB_CONTENTS_USER_DATA_KEY(JavaScriptDialogTabHelper); |
24 | 23 |
25 namespace { | 24 namespace { |
26 | 25 |
27 bool IsEnabled() { | |
28 return base::FeatureList::IsEnabled(features::kAutoDismissingDialogs); | |
29 } | |
30 | |
31 app_modal::JavaScriptDialogManager* AppModalDialogManager() { | 26 app_modal::JavaScriptDialogManager* AppModalDialogManager() { |
32 return app_modal::JavaScriptDialogManager::GetInstance(); | 27 return app_modal::JavaScriptDialogManager::GetInstance(); |
33 } | 28 } |
34 | 29 |
35 bool IsWebContentsForemost(content::WebContents* web_contents) { | 30 bool IsWebContentsForemost(content::WebContents* web_contents) { |
36 Browser* browser = BrowserList::GetInstance()->GetLastActive(); | 31 Browser* browser = BrowserList::GetInstance()->GetLastActive(); |
37 DCHECK(browser); | 32 DCHECK(browser); |
38 return browser->tab_strip_model()->GetActiveWebContents() == web_contents; | 33 return browser->tab_strip_model()->GetActiveWebContents() == web_contents; |
39 } | 34 } |
40 | 35 |
(...skipping 85 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
126 UMA_HISTOGRAM_BOOLEAN("JSDialogs.IsForemost.Alert", foremost); | 121 UMA_HISTOGRAM_BOOLEAN("JSDialogs.IsForemost.Alert", foremost); |
127 break; | 122 break; |
128 case content::JAVASCRIPT_DIALOG_TYPE_CONFIRM: | 123 case content::JAVASCRIPT_DIALOG_TYPE_CONFIRM: |
129 UMA_HISTOGRAM_BOOLEAN("JSDialogs.IsForemost.Confirm", foremost); | 124 UMA_HISTOGRAM_BOOLEAN("JSDialogs.IsForemost.Confirm", foremost); |
130 break; | 125 break; |
131 case content::JAVASCRIPT_DIALOG_TYPE_PROMPT: | 126 case content::JAVASCRIPT_DIALOG_TYPE_PROMPT: |
132 UMA_HISTOGRAM_BOOLEAN("JSDialogs.IsForemost.Prompt", foremost); | 127 UMA_HISTOGRAM_BOOLEAN("JSDialogs.IsForemost.Prompt", foremost); |
133 break; | 128 break; |
134 } | 129 } |
135 | 130 |
136 if (IsEnabled()) { | 131 if (!IsWebContentsForemost(parent_web_contents) && |
137 if (!IsWebContentsForemost(parent_web_contents) && | 132 dialog_type == content::JAVASCRIPT_DIALOG_TYPE_PROMPT) { |
138 dialog_type == content::JAVASCRIPT_DIALOG_TYPE_PROMPT) { | 133 // Don't allow "prompt" dialogs to steal the user's focus. TODO(avi): |
139 // Don't allow "prompt" dialogs to steal the user's focus. TODO(avi): | 134 // Eventually, for subsequent phases of http://bit.ly/project-oldspice, |
140 // Eventually, for subsequent phases of http://bit.ly/project-oldspice, | 135 // turn off focus stealing for other dialog types. |
141 // turn off focus stealing for other dialog types. | 136 *did_suppress_message = true; |
142 *did_suppress_message = true; | 137 alerting_web_contents->GetMainFrame()->AddMessageToConsole( |
143 alerting_web_contents->GetMainFrame()->AddMessageToConsole( | 138 content::CONSOLE_MESSAGE_LEVEL_WARNING, |
144 content::CONSOLE_MESSAGE_LEVEL_WARNING, | 139 "A window.prompt() dialog generated by this page was suppressed " |
145 "A window.prompt() dialog generated by this page was suppressed " | 140 "because this page is not the active tab of the front window. " |
146 "because this page is not the active tab of the front window. " | 141 "Please make sure your dialogs are triggered by user interactions " |
147 "Please make sure your dialogs are triggered by user interactions " | 142 "to avoid this situation. " |
148 "to avoid this situation. " | 143 "https://www.chromestatus.com/feature/5637107137642496"); |
149 "https://www.chromestatus.com/feature/5637107137642496"); | 144 return; |
150 return; | 145 } |
151 } | |
152 | 146 |
153 if (dialog_) { | 147 if (dialog_) { |
154 // There's already a dialog up; clear it out. | 148 // There's already a dialog up; clear it out. |
155 CloseDialog(false, base::string16(), | 149 CloseDialog(false, base::string16(), |
156 DismissalCause::SUBSEQUENT_DIALOG_SHOWN); | 150 DismissalCause::SUBSEQUENT_DIALOG_SHOWN); |
157 } | 151 } |
158 | 152 |
159 // Enforce sane sizes. ElideRectangleString breaks horizontally, which isn't | 153 // Enforce sane sizes. ElideRectangleString breaks horizontally, which isn't |
160 // strictly needed, but it restricts the vertical size, which is crucial. | 154 // strictly needed, but it restricts the vertical size, which is crucial. |
161 // This gives about 2000 characters, which is about the same as the | 155 // This gives about 2000 characters, which is about the same as the |
162 // AppModalDialogManager provides, but allows no more than 24 lines. | 156 // AppModalDialogManager provides, but allows no more than 24 lines. |
163 const int kMessageTextMaxRows = 24; | 157 const int kMessageTextMaxRows = 24; |
164 const int kMessageTextMaxCols = 80; | 158 const int kMessageTextMaxCols = 80; |
165 const size_t kDefaultPromptMaxSize = 2000; | 159 const size_t kDefaultPromptMaxSize = 2000; |
166 base::string16 truncated_message_text; | 160 base::string16 truncated_message_text; |
167 gfx::ElideRectangleString(message_text, kMessageTextMaxRows, | 161 gfx::ElideRectangleString(message_text, kMessageTextMaxRows, |
168 kMessageTextMaxCols, false, | 162 kMessageTextMaxCols, false, |
169 &truncated_message_text); | 163 &truncated_message_text); |
170 base::string16 truncated_default_prompt_text; | 164 base::string16 truncated_default_prompt_text; |
171 gfx::ElideString(default_prompt_text, kDefaultPromptMaxSize, | 165 gfx::ElideString(default_prompt_text, kDefaultPromptMaxSize, |
172 &truncated_default_prompt_text); | 166 &truncated_default_prompt_text); |
173 | 167 |
174 base::string16 title = | 168 base::string16 title = |
175 AppModalDialogManager()->GetTitle(alerting_web_contents, origin_url); | 169 AppModalDialogManager()->GetTitle(alerting_web_contents, origin_url); |
176 dialog_callback_ = callback; | 170 dialog_callback_ = callback; |
177 dialog_type_ = dialog_type; | 171 dialog_type_ = dialog_type; |
178 dialog_ = JavaScriptDialog::Create( | 172 dialog_ = JavaScriptDialog::Create( |
179 parent_web_contents, alerting_web_contents, title, dialog_type, | 173 parent_web_contents, alerting_web_contents, title, dialog_type, |
180 truncated_message_text, truncated_default_prompt_text, | 174 truncated_message_text, truncated_default_prompt_text, |
181 base::Bind(&JavaScriptDialogTabHelper::OnDialogClosed, | 175 base::Bind(&JavaScriptDialogTabHelper::OnDialogClosed, |
182 base::Unretained(this), callback)); | 176 base::Unretained(this), callback)); |
183 | 177 |
184 BrowserList::AddObserver(this); | 178 BrowserList::AddObserver(this); |
185 | 179 |
186 // Message suppression is something that we don't give the user a checkbox | 180 // Message suppression is something that we don't give the user a checkbox |
187 // for any more. It was useful back in the day when dialogs were app-modal | 181 // for any more. It was useful back in the day when dialogs were app-modal |
188 // and clicking the checkbox was the only way to escape a loop that the page | 182 // and clicking the checkbox was the only way to escape a loop that the page |
189 // was doing, but now the user can just close the page. | 183 // was doing, but now the user can just close the page. |
190 *did_suppress_message = false; | 184 *did_suppress_message = false; |
191 | 185 |
192 if (!dialog_shown_.is_null()) { | 186 if (!dialog_shown_.is_null()) { |
193 dialog_shown_.Run(); | 187 dialog_shown_.Run(); |
194 dialog_shown_.Reset(); | 188 dialog_shown_.Reset(); |
195 } | |
196 } else { | |
197 AppModalDialogManager()->RunJavaScriptDialog( | |
198 alerting_web_contents, origin_url, dialog_type, message_text, | |
199 default_prompt_text, callback, did_suppress_message); | |
200 } | 189 } |
201 | 190 |
202 if (did_suppress_message) { | 191 if (did_suppress_message) { |
203 UMA_HISTOGRAM_COUNTS("JSDialogs.CharacterCountUserSuppressed", | 192 UMA_HISTOGRAM_COUNTS("JSDialogs.CharacterCountUserSuppressed", |
204 message_length); | 193 message_length); |
205 } | 194 } |
206 } | 195 } |
207 | 196 |
208 namespace { | 197 namespace { |
209 | 198 |
(...skipping 139 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
349 dialog_callback_.Run(success, user_input); | 338 dialog_callback_.Run(success, user_input); |
350 | 339 |
351 ClearDialogInfo(); | 340 ClearDialogInfo(); |
352 } | 341 } |
353 | 342 |
354 void JavaScriptDialogTabHelper::ClearDialogInfo() { | 343 void JavaScriptDialogTabHelper::ClearDialogInfo() { |
355 dialog_.reset(); | 344 dialog_.reset(); |
356 dialog_callback_.Reset(); | 345 dialog_callback_.Reset(); |
357 BrowserList::RemoveObserver(this); | 346 BrowserList::RemoveObserver(this); |
358 } | 347 } |
OLD | NEW |