blob: dd5808078b05ff3e564dc7f79a5dc1de520f5c64 [file] [log] [blame]
[email protected]fedec012012-01-28 03:09:341// Copyright (c) 2012 The Chromium Authors. All rights reserved.
[email protected]12f74a92010-02-05 22:32:142// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
oshimaf65398422014-11-18 23:30:425#include "components/app_modal/javascript_app_modal_dialog.h"
[email protected]12f74a92010-02-05 22:32:146
joenotcharles850904a2016-02-09 01:50:447#include "base/metrics/histogram_macros.h"
8#include "base/time/time.h"
avibc5337b2015-12-25 23:16:339#include "build/build_config.h"
oshima0929be2a2014-11-19 22:21:0310#include "components/app_modal/javascript_dialog_manager.h"
oshimaf65398422014-11-18 23:30:4211#include "components/app_modal/javascript_native_dialog_factory.h"
[email protected]dbb97ba2013-09-09 22:15:2512#include "ui/gfx/text_elider.h"
[email protected]51da7e32012-01-30 19:24:5213
oshima0929be2a2014-11-19 22:21:0314namespace app_modal {
[email protected]999adfd62010-06-02 19:42:4215namespace {
16
[email protected]416126c52011-03-29 16:28:5717// Control maximum sizes of various texts passed to us from javascript.
[email protected]7be64502011-05-03 17:51:4718#if defined(OS_POSIX) && !defined(OS_MACOSX)
[email protected]416126c52011-03-29 16:28:5719// Two-dimensional eliding. Reformat the text of the message dialog
20// inserting line breaks because otherwise a single long line can overflow
21// the message dialog (and crash/hang the GTK, depending on the version).
[email protected]af4b9df2010-12-22 21:19:0222const int kMessageTextMaxRows = 32;
23const int kMessageTextMaxCols = 132;
[email protected]416126c52011-03-29 16:28:5724const int kDefaultPromptMaxRows = 24;
25const int kDefaultPromptMaxCols = 132;
[email protected]dcd0249872013-12-06 23:58:4526void EnforceMaxTextSize(const base::string16& in_string,
27 base::string16* out_string) {
[email protected]dbb97ba2013-09-09 22:15:2528 gfx::ElideRectangleString(in_string, kMessageTextMaxRows,
[email protected]416126c52011-03-29 16:28:5729 kMessageTextMaxCols, false, out_string);
30}
[email protected]dcd0249872013-12-06 23:58:4531void EnforceMaxPromptSize(const base::string16& in_string,
32 base::string16* out_string) {
[email protected]dbb97ba2013-09-09 22:15:2533 gfx::ElideRectangleString(in_string, kDefaultPromptMaxRows,
[email protected]416126c52011-03-29 16:28:5734 kDefaultPromptMaxCols, false, out_string);
35}
36#else
37// One-dimensional eliding. Trust the window system to break the string
38// appropriately, but limit its overall length to something reasonable.
thestigbbf93ac2016-02-02 00:24:4939const size_t kMessageTextMaxSize = 2000;
40const size_t kDefaultPromptMaxSize = 2000;
[email protected]dcd0249872013-12-06 23:58:4541void EnforceMaxTextSize(const base::string16& in_string,
42 base::string16* out_string) {
[email protected]dbb97ba2013-09-09 22:15:2543 gfx::ElideString(in_string, kMessageTextMaxSize, out_string);
[email protected]416126c52011-03-29 16:28:5744}
[email protected]dcd0249872013-12-06 23:58:4545void EnforceMaxPromptSize(const base::string16& in_string,
46 base::string16* out_string) {
[email protected]dbb97ba2013-09-09 22:15:2547 gfx::ElideString(in_string, kDefaultPromptMaxSize, out_string);
[email protected]416126c52011-03-29 16:28:5748}
49#endif
[email protected]999adfd62010-06-02 19:42:4250
51} // namespace
52
[email protected]3ab9cb82011-06-03 18:02:0753ChromeJavaScriptDialogExtraData::ChromeJavaScriptDialogExtraData()
palmerd8b2ff02015-08-18 00:24:5954 : has_already_shown_a_dialog_(false),
joenotcharles505f4212016-02-11 19:28:5355 suppress_javascript_messages_(false),
56 suppressed_dialog_count_(0) {}
[email protected]3ab9cb82011-06-03 18:02:0757
[email protected]12f74a92010-02-05 22:32:1458JavaScriptAppModalDialog::JavaScriptAppModalDialog(
jochena2afdec2015-01-23 13:09:2259 content::WebContents* web_contents,
[email protected]1f422a7c2013-05-15 17:06:4160 ExtraDataMap* extra_data_map,
[email protected]dcd0249872013-12-06 23:58:4561 const base::string16& title,
avi777ff452017-02-09 19:04:4862 content::JavaScriptDialogType javascript_dialog_type,
[email protected]dcd0249872013-12-06 23:58:4563 const base::string16& message_text,
64 const base::string16& default_prompt_text,
[email protected]12f74a92010-02-05 22:32:1465 bool display_suppress_checkbox,
66 bool is_before_unload_dialog,
[email protected]3b3301f62012-02-29 04:32:3267 bool is_reload,
oshima0929be2a2014-11-19 22:21:0368 const content::JavaScriptDialogManager::DialogClosedCallback& callback)
[email protected]51da7e32012-01-30 19:24:5269 : AppModalDialog(web_contents, title),
[email protected]1f422a7c2013-05-15 17:06:4170 extra_data_map_(extra_data_map),
avi777ff452017-02-09 19:04:4871 javascript_dialog_type_(javascript_dialog_type),
[email protected]12f74a92010-02-05 22:32:1472 display_suppress_checkbox_(display_suppress_checkbox),
73 is_before_unload_dialog_(is_before_unload_dialog),
[email protected]3b3301f62012-02-29 04:32:3274 is_reload_(is_reload),
[email protected]51da7e32012-01-30 19:24:5275 callback_(callback),
joenotcharles850904a2016-02-09 01:50:4476 use_override_prompt_text_(false),
77 creation_time_(base::TimeTicks::Now()) {
[email protected]3ab9cb82011-06-03 18:02:0778 EnforceMaxTextSize(message_text, &message_text_);
79 EnforceMaxPromptSize(default_prompt_text, &default_prompt_text_);
[email protected]12f74a92010-02-05 22:32:1480}
81
82JavaScriptAppModalDialog::~JavaScriptAppModalDialog() {
83}
84
[email protected]160ad3d2010-09-28 15:40:2085NativeAppModalDialog* JavaScriptAppModalDialog::CreateNativeDialog() {
jochena2afdec2015-01-23 13:09:2286 return JavaScriptDialogManager::GetInstance()
87 ->native_dialog_factory()
88 ->CreateNativeJavaScriptDialog(this);
[email protected]160ad3d2010-09-28 15:40:2089}
90
[email protected]16623742011-05-16 20:04:2691bool JavaScriptAppModalDialog::IsJavaScriptModalDialog() {
92 return true;
93}
94
avi6879fcf2017-01-21 05:27:5395void JavaScriptAppModalDialog::Invalidate() {
[email protected]1f422a7c2013-05-15 17:06:4196 if (!IsValid())
[email protected]12f74a92010-02-05 22:32:1497 return;
98
avi6879fcf2017-01-21 05:27:5399 AppModalDialog::Invalidate();
100 CallDialogClosedCallback(false, base::string16());
[email protected]1f422a7c2013-05-15 17:06:41101 if (native_dialog())
[email protected]66711f6f2010-06-23 01:17:35102 CloseModalDialog();
[email protected]12f74a92010-02-05 22:32:14103}
104
[email protected]ab96d312010-10-14 13:38:51105void JavaScriptAppModalDialog::OnCancel(bool suppress_js_messages) {
[email protected]12f74a92010-02-05 22:32:14106 // We need to do this before WM_DESTROY (WindowClosing()) as any parent frame
107 // will receive its activation messages before this dialog receives
108 // WM_DESTROY. The parent frame would then try to activate any modal dialogs
109 // that were still open in the ModalDialogQueue, which would send activation
110 // back to this one. The framework should be improved to handle this, so this
111 // is a temporary workaround.
112 CompleteDialog();
113
[email protected]dcd0249872013-12-06 23:58:45114 NotifyDelegate(false, base::string16(), suppress_js_messages);
[email protected]12f74a92010-02-05 22:32:14115}
116
[email protected]dcd0249872013-12-06 23:58:45117void JavaScriptAppModalDialog::OnAccept(const base::string16& prompt_text,
[email protected]12f74a92010-02-05 22:32:14118 bool suppress_js_messages) {
[email protected]dcd0249872013-12-06 23:58:45119 base::string16 prompt_text_to_use = prompt_text;
[email protected]16623742011-05-16 20:04:26120 // This is only for testing.
121 if (use_override_prompt_text_)
[email protected]3ab9cb82011-06-03 18:02:07122 prompt_text_to_use = override_prompt_text_;
[email protected]16623742011-05-16 20:04:26123
[email protected]12f74a92010-02-05 22:32:14124 CompleteDialog();
[email protected]16623742011-05-16 20:04:26125 NotifyDelegate(true, prompt_text_to_use, suppress_js_messages);
[email protected]12f74a92010-02-05 22:32:14126}
[email protected]7d784302010-04-09 21:41:05127
128void JavaScriptAppModalDialog::OnClose() {
[email protected]dcd0249872013-12-06 23:58:45129 NotifyDelegate(false, base::string16(), false);
[email protected]7d784302010-04-09 21:41:05130}
131
[email protected]16623742011-05-16 20:04:26132void JavaScriptAppModalDialog::SetOverridePromptText(
[email protected]dcd0249872013-12-06 23:58:45133 const base::string16& override_prompt_text) {
[email protected]16623742011-05-16 20:04:26134 override_prompt_text_ = override_prompt_text;
135 use_override_prompt_text_ = true;
136}
137
[email protected]594d0622010-12-07 05:33:07138void JavaScriptAppModalDialog::NotifyDelegate(bool success,
[email protected]dcd0249872013-12-06 23:58:45139 const base::string16& user_input,
[email protected]594d0622010-12-07 05:33:07140 bool suppress_js_messages) {
[email protected]1f422a7c2013-05-15 17:06:41141 if (!IsValid())
[email protected]594d0622010-12-07 05:33:07142 return;
143
joenotcharles850904a2016-02-09 01:50:44144 CallDialogClosedCallback(success, user_input);
[email protected]3ab9cb82011-06-03 18:02:07145
joenotcharles850904a2016-02-09 01:50:44146 // The close callback above may delete web_contents_, thus removing the extra
oshima0929be2a2014-11-19 22:21:03147 // data from the map owned by ::JavaScriptDialogManager. Make sure
[email protected]1f422a7c2013-05-15 17:06:41148 // to only use the data if still present. http://crbug.com/236476
avid79a673c2016-02-19 00:20:03149 ExtraDataMap::iterator extra_data = extra_data_map_->find(web_contents());
[email protected]1f422a7c2013-05-15 17:06:41150 if (extra_data != extra_data_map_->end()) {
palmerd8b2ff02015-08-18 00:24:59151 extra_data->second.has_already_shown_a_dialog_ = true;
[email protected]1f422a7c2013-05-15 17:06:41152 extra_data->second.suppress_javascript_messages_ = suppress_js_messages;
153 }
[email protected]594d0622010-12-07 05:33:07154
155 // On Views, we can end up coming through this code path twice :(.
156 // See crbug.com/63732.
avi6879fcf2017-01-21 05:27:53157 AppModalDialog::Invalidate();
[email protected]7d784302010-04-09 21:41:05158}
oshima0929be2a2014-11-19 22:21:03159
joenotcharles850904a2016-02-09 01:50:44160void JavaScriptAppModalDialog::CallDialogClosedCallback(bool success,
161 const base::string16& user_input) {
162 // TODO(joenotcharles): Both the callers of this function also check IsValid
163 // and call AppModalDialog::Invalidate, but in different orders. If the
164 // difference is not significant, more common code could be moved here.
165 UMA_HISTOGRAM_MEDIUM_TIMES(
166 "JSDialogs.FineTiming.TimeBetweenDialogCreatedAndSameDialogClosed",
167 base::TimeTicks::Now() - creation_time_);
168 if (!callback_.is_null()) {
169 callback_.Run(success, user_input);
170 callback_.Reset();
171 }
172}
173
oshima0929be2a2014-11-19 22:21:03174} // namespace app_modal