blob: 04aefb5590083f865c8851f6f72a3aca872eb829 [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
Avi Drissmane04d3992017-10-05 15:11:367#include <utility>
8
joenotcharles850904a2016-02-09 01:50:449#include "base/metrics/histogram_macros.h"
10#include "base/time/time.h"
avibc5337b2015-12-25 23:16:3311#include "build/build_config.h"
avi373e72a2017-05-26 20:33:5212#include "components/app_modal/app_modal_dialog_queue.h"
oshima0929be2a2014-11-19 22:21:0313#include "components/app_modal/javascript_dialog_manager.h"
oshimaf65398422014-11-18 23:30:4214#include "components/app_modal/javascript_native_dialog_factory.h"
avi373e72a2017-05-26 20:33:5215#include "components/app_modal/native_app_modal_dialog.h"
[email protected]dbb97ba2013-09-09 22:15:2516#include "ui/gfx/text_elider.h"
[email protected]51da7e32012-01-30 19:24:5217
oshima0929be2a2014-11-19 22:21:0318namespace app_modal {
[email protected]999adfd62010-06-02 19:42:4219namespace {
20
avi373e72a2017-05-26 20:33:5221AppModalDialogObserver* app_modal_dialog_observer = nullptr;
22
[email protected]416126c52011-03-29 16:28:5723// Control maximum sizes of various texts passed to us from javascript.
[email protected]7be64502011-05-03 17:51:4724#if defined(OS_POSIX) && !defined(OS_MACOSX)
[email protected]416126c52011-03-29 16:28:5725// Two-dimensional eliding. Reformat the text of the message dialog
26// inserting line breaks because otherwise a single long line can overflow
27// the message dialog (and crash/hang the GTK, depending on the version).
[email protected]af4b9df2010-12-22 21:19:0228const int kMessageTextMaxRows = 32;
29const int kMessageTextMaxCols = 132;
[email protected]416126c52011-03-29 16:28:5730const int kDefaultPromptMaxRows = 24;
31const int kDefaultPromptMaxCols = 132;
[email protected]dcd0249872013-12-06 23:58:4532void EnforceMaxTextSize(const base::string16& in_string,
33 base::string16* out_string) {
[email protected]dbb97ba2013-09-09 22:15:2534 gfx::ElideRectangleString(in_string, kMessageTextMaxRows,
[email protected]416126c52011-03-29 16:28:5735 kMessageTextMaxCols, false, out_string);
36}
[email protected]dcd0249872013-12-06 23:58:4537void EnforceMaxPromptSize(const base::string16& in_string,
38 base::string16* out_string) {
[email protected]dbb97ba2013-09-09 22:15:2539 gfx::ElideRectangleString(in_string, kDefaultPromptMaxRows,
[email protected]416126c52011-03-29 16:28:5740 kDefaultPromptMaxCols, false, out_string);
41}
42#else
43// One-dimensional eliding. Trust the window system to break the string
44// appropriately, but limit its overall length to something reasonable.
thestigbbf93ac2016-02-02 00:24:4945const size_t kMessageTextMaxSize = 2000;
46const size_t kDefaultPromptMaxSize = 2000;
[email protected]dcd0249872013-12-06 23:58:4547void EnforceMaxTextSize(const base::string16& in_string,
48 base::string16* out_string) {
[email protected]dbb97ba2013-09-09 22:15:2549 gfx::ElideString(in_string, kMessageTextMaxSize, out_string);
[email protected]416126c52011-03-29 16:28:5750}
[email protected]dcd0249872013-12-06 23:58:4551void EnforceMaxPromptSize(const base::string16& in_string,
52 base::string16* out_string) {
[email protected]dbb97ba2013-09-09 22:15:2553 gfx::ElideString(in_string, kDefaultPromptMaxSize, out_string);
[email protected]416126c52011-03-29 16:28:5754}
55#endif
[email protected]999adfd62010-06-02 19:42:4256
57} // namespace
58
[email protected]3ab9cb82011-06-03 18:02:0759ChromeJavaScriptDialogExtraData::ChromeJavaScriptDialogExtraData()
palmerd8b2ff02015-08-18 00:24:5960 : has_already_shown_a_dialog_(false),
joenotcharles505f4212016-02-11 19:28:5361 suppress_javascript_messages_(false),
62 suppressed_dialog_count_(0) {}
[email protected]3ab9cb82011-06-03 18:02:0763
[email protected]12f74a92010-02-05 22:32:1464JavaScriptAppModalDialog::JavaScriptAppModalDialog(
jochena2afdec2015-01-23 13:09:2265 content::WebContents* web_contents,
[email protected]1f422a7c2013-05-15 17:06:4166 ExtraDataMap* extra_data_map,
[email protected]dcd0249872013-12-06 23:58:4567 const base::string16& title,
avi777ff452017-02-09 19:04:4868 content::JavaScriptDialogType javascript_dialog_type,
[email protected]dcd0249872013-12-06 23:58:4569 const base::string16& message_text,
70 const base::string16& default_prompt_text,
[email protected]12f74a92010-02-05 22:32:1471 bool display_suppress_checkbox,
72 bool is_before_unload_dialog,
[email protected]3b3301f62012-02-29 04:32:3273 bool is_reload,
Avi Drissmane04d3992017-10-05 15:11:3674 content::JavaScriptDialogManager::DialogClosedCallback callback)
avi373e72a2017-05-26 20:33:5275 : title_(title),
76 completed_(false),
77 valid_(true),
78 native_dialog_(nullptr),
79 web_contents_(web_contents),
[email protected]1f422a7c2013-05-15 17:06:4180 extra_data_map_(extra_data_map),
avi777ff452017-02-09 19:04:4881 javascript_dialog_type_(javascript_dialog_type),
[email protected]12f74a92010-02-05 22:32:1482 display_suppress_checkbox_(display_suppress_checkbox),
83 is_before_unload_dialog_(is_before_unload_dialog),
[email protected]3b3301f62012-02-29 04:32:3284 is_reload_(is_reload),
Avi Drissmane04d3992017-10-05 15:11:3685 callback_(std::move(callback)),
joenotcharles850904a2016-02-09 01:50:4486 use_override_prompt_text_(false),
87 creation_time_(base::TimeTicks::Now()) {
[email protected]3ab9cb82011-06-03 18:02:0788 EnforceMaxTextSize(message_text, &message_text_);
89 EnforceMaxPromptSize(default_prompt_text, &default_prompt_text_);
[email protected]12f74a92010-02-05 22:32:1490}
91
92JavaScriptAppModalDialog::~JavaScriptAppModalDialog() {
avi373e72a2017-05-26 20:33:5293 CompleteDialog();
[email protected]12f74a92010-02-05 22:32:1494}
95
avi373e72a2017-05-26 20:33:5296void JavaScriptAppModalDialog::ShowModalDialog() {
97 native_dialog_ = JavaScriptDialogManager::GetInstance()
98 ->native_dialog_factory()
99 ->CreateNativeJavaScriptDialog(this);
100 native_dialog_->ShowAppModalDialog();
101 if (app_modal_dialog_observer)
102 app_modal_dialog_observer->Notify(this);
[email protected]160ad3d2010-09-28 15:40:20103}
104
avi373e72a2017-05-26 20:33:52105void JavaScriptAppModalDialog::ActivateModalDialog() {
106 DCHECK(native_dialog_);
107 native_dialog_->ActivateAppModalDialog();
108}
109
110void JavaScriptAppModalDialog::CloseModalDialog() {
111 DCHECK(native_dialog_);
112 native_dialog_->CloseAppModalDialog();
113}
114
115void JavaScriptAppModalDialog::CompleteDialog() {
116 if (!completed_) {
117 completed_ = true;
118 AppModalDialogQueue::GetInstance()->ShowNextDialog();
119 }
120}
121
122bool JavaScriptAppModalDialog::IsValid() {
123 return valid_;
[email protected]16623742011-05-16 20:04:26124}
125
avi6879fcf2017-01-21 05:27:53126void JavaScriptAppModalDialog::Invalidate() {
avi373e72a2017-05-26 20:33:52127 if (!valid_)
[email protected]12f74a92010-02-05 22:32:14128 return;
129
avi373e72a2017-05-26 20:33:52130 valid_ = false;
avi6879fcf2017-01-21 05:27:53131 CallDialogClosedCallback(false, base::string16());
avi373e72a2017-05-26 20:33:52132 if (native_dialog_)
[email protected]66711f6f2010-06-23 01:17:35133 CloseModalDialog();
[email protected]12f74a92010-02-05 22:32:14134}
135
[email protected]ab96d312010-10-14 13:38:51136void JavaScriptAppModalDialog::OnCancel(bool suppress_js_messages) {
[email protected]12f74a92010-02-05 22:32:14137 // We need to do this before WM_DESTROY (WindowClosing()) as any parent frame
138 // will receive its activation messages before this dialog receives
139 // WM_DESTROY. The parent frame would then try to activate any modal dialogs
140 // that were still open in the ModalDialogQueue, which would send activation
141 // back to this one. The framework should be improved to handle this, so this
142 // is a temporary workaround.
143 CompleteDialog();
144
[email protected]dcd0249872013-12-06 23:58:45145 NotifyDelegate(false, base::string16(), suppress_js_messages);
[email protected]12f74a92010-02-05 22:32:14146}
147
[email protected]dcd0249872013-12-06 23:58:45148void JavaScriptAppModalDialog::OnAccept(const base::string16& prompt_text,
[email protected]12f74a92010-02-05 22:32:14149 bool suppress_js_messages) {
[email protected]dcd0249872013-12-06 23:58:45150 base::string16 prompt_text_to_use = prompt_text;
[email protected]16623742011-05-16 20:04:26151 // This is only for testing.
152 if (use_override_prompt_text_)
[email protected]3ab9cb82011-06-03 18:02:07153 prompt_text_to_use = override_prompt_text_;
[email protected]16623742011-05-16 20:04:26154
[email protected]12f74a92010-02-05 22:32:14155 CompleteDialog();
[email protected]16623742011-05-16 20:04:26156 NotifyDelegate(true, prompt_text_to_use, suppress_js_messages);
[email protected]12f74a92010-02-05 22:32:14157}
[email protected]7d784302010-04-09 21:41:05158
159void JavaScriptAppModalDialog::OnClose() {
[email protected]dcd0249872013-12-06 23:58:45160 NotifyDelegate(false, base::string16(), false);
[email protected]7d784302010-04-09 21:41:05161}
162
[email protected]16623742011-05-16 20:04:26163void JavaScriptAppModalDialog::SetOverridePromptText(
[email protected]dcd0249872013-12-06 23:58:45164 const base::string16& override_prompt_text) {
[email protected]16623742011-05-16 20:04:26165 override_prompt_text_ = override_prompt_text;
166 use_override_prompt_text_ = true;
167}
168
[email protected]594d0622010-12-07 05:33:07169void JavaScriptAppModalDialog::NotifyDelegate(bool success,
[email protected]dcd0249872013-12-06 23:58:45170 const base::string16& user_input,
[email protected]594d0622010-12-07 05:33:07171 bool suppress_js_messages) {
avi373e72a2017-05-26 20:33:52172 if (!valid_)
[email protected]594d0622010-12-07 05:33:07173 return;
174
joenotcharles850904a2016-02-09 01:50:44175 CallDialogClosedCallback(success, user_input);
[email protected]3ab9cb82011-06-03 18:02:07176
joenotcharles850904a2016-02-09 01:50:44177 // The close callback above may delete web_contents_, thus removing the extra
oshima0929be2a2014-11-19 22:21:03178 // data from the map owned by ::JavaScriptDialogManager. Make sure
[email protected]1f422a7c2013-05-15 17:06:41179 // to only use the data if still present. http://crbug.com/236476
avi373e72a2017-05-26 20:33:52180 ExtraDataMap::iterator extra_data = extra_data_map_->find(web_contents_);
[email protected]1f422a7c2013-05-15 17:06:41181 if (extra_data != extra_data_map_->end()) {
palmerd8b2ff02015-08-18 00:24:59182 extra_data->second.has_already_shown_a_dialog_ = true;
[email protected]1f422a7c2013-05-15 17:06:41183 extra_data->second.suppress_javascript_messages_ = suppress_js_messages;
184 }
[email protected]594d0622010-12-07 05:33:07185
186 // On Views, we can end up coming through this code path twice :(.
187 // See crbug.com/63732.
avi373e72a2017-05-26 20:33:52188 valid_ = false;
[email protected]7d784302010-04-09 21:41:05189}
oshima0929be2a2014-11-19 22:21:03190
joenotcharles850904a2016-02-09 01:50:44191void JavaScriptAppModalDialog::CallDialogClosedCallback(bool success,
192 const base::string16& user_input) {
193 // TODO(joenotcharles): Both the callers of this function also check IsValid
avi373e72a2017-05-26 20:33:52194 // and call Invalidate, but in different orders. If the difference is not
195 // significant, more common code could be moved here.
joenotcharles850904a2016-02-09 01:50:44196 UMA_HISTOGRAM_MEDIUM_TIMES(
197 "JSDialogs.FineTiming.TimeBetweenDialogCreatedAndSameDialogClosed",
198 base::TimeTicks::Now() - creation_time_);
Avi Drissmane04d3992017-10-05 15:11:36199 if (!callback_.is_null())
200 std::move(callback_).Run(success, user_input);
joenotcharles850904a2016-02-09 01:50:44201}
202
avi373e72a2017-05-26 20:33:52203AppModalDialogObserver::AppModalDialogObserver() {
204 DCHECK(!app_modal_dialog_observer);
205 app_modal_dialog_observer = this;
206}
207
208AppModalDialogObserver::~AppModalDialogObserver() {
209 DCHECK(app_modal_dialog_observer);
210 app_modal_dialog_observer = nullptr;
211}
212
oshima0929be2a2014-11-19 22:21:03213} // namespace app_modal