1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "chrome/browser/ui/app_modal_dialogs/javascript_app_modal_dialog.h"
7 #include "chrome/browser/browser_shutdown.h"
8 #include "chrome/browser/ui/app_modal_dialogs/native_app_modal_dialog.h"
9 #include "content/public/browser/web_contents.h"
10 #include "content/public/browser/web_contents_view.h"
11 #include "ui/gfx/text_elider.h"
14 #include "ui/aura/root_window.h"
15 #include "ui/aura/window.h"
18 using content::JavaScriptDialogManager
;
19 using content::WebContents
;
23 // Control maximum sizes of various texts passed to us from javascript.
24 #if defined(OS_POSIX) && !defined(OS_MACOSX)
25 // 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).
28 const int kMessageTextMaxRows
= 32;
29 const int kMessageTextMaxCols
= 132;
30 const int kDefaultPromptMaxRows
= 24;
31 const int kDefaultPromptMaxCols
= 132;
32 void EnforceMaxTextSize(const base::string16
& in_string
,
33 base::string16
* out_string
) {
34 gfx::ElideRectangleString(in_string
, kMessageTextMaxRows
,
35 kMessageTextMaxCols
, false, out_string
);
37 void EnforceMaxPromptSize(const base::string16
& in_string
,
38 base::string16
* out_string
) {
39 gfx::ElideRectangleString(in_string
, kDefaultPromptMaxRows
,
40 kDefaultPromptMaxCols
, false, out_string
);
43 // One-dimensional eliding. Trust the window system to break the string
44 // appropriately, but limit its overall length to something reasonable.
45 const int kMessageTextMaxSize
= 3000;
46 const int kDefaultPromptMaxSize
= 2000;
47 void EnforceMaxTextSize(const base::string16
& in_string
,
48 base::string16
* out_string
) {
49 gfx::ElideString(in_string
, kMessageTextMaxSize
, out_string
);
51 void EnforceMaxPromptSize(const base::string16
& in_string
,
52 base::string16
* out_string
) {
53 gfx::ElideString(in_string
, kDefaultPromptMaxSize
, out_string
);
59 ChromeJavaScriptDialogExtraData::ChromeJavaScriptDialogExtraData()
60 : suppress_javascript_messages_(false) {
63 JavaScriptAppModalDialog::JavaScriptAppModalDialog(
64 WebContents
* web_contents
,
65 ExtraDataMap
* extra_data_map
,
66 const base::string16
& title
,
67 content::JavaScriptMessageType javascript_message_type
,
68 const base::string16
& message_text
,
69 const base::string16
& default_prompt_text
,
70 bool display_suppress_checkbox
,
71 bool is_before_unload_dialog
,
73 const JavaScriptDialogManager::DialogClosedCallback
& callback
)
74 : AppModalDialog(web_contents
, title
),
75 extra_data_map_(extra_data_map
),
76 javascript_message_type_(javascript_message_type
),
77 display_suppress_checkbox_(display_suppress_checkbox
),
78 is_before_unload_dialog_(is_before_unload_dialog
),
79 is_reload_(is_reload
),
81 use_override_prompt_text_(false) {
82 EnforceMaxTextSize(message_text
, &message_text_
);
83 EnforceMaxPromptSize(default_prompt_text
, &default_prompt_text_
);
86 JavaScriptAppModalDialog::~JavaScriptAppModalDialog() {
89 NativeAppModalDialog
* JavaScriptAppModalDialog::CreateNativeDialog() {
90 gfx::NativeWindow parent_window
=
91 web_contents()->GetView()->GetTopLevelNativeWindow();
94 if (!parent_window
->GetRootWindow()) {
95 // When we are part of a WebContents that isn't actually being displayed on
96 // the screen, we can't actually attach to it.
99 #endif // defined(USE_AURA)
101 return NativeAppModalDialog::CreateNativeJavaScriptPrompt(this,
105 bool JavaScriptAppModalDialog::IsJavaScriptModalDialog() {
109 void JavaScriptAppModalDialog::Invalidate() {
113 AppModalDialog::Invalidate();
114 if (!callback_
.is_null()) {
115 callback_
.Run(false, base::string16());
122 void JavaScriptAppModalDialog::OnCancel(bool suppress_js_messages
) {
123 // We need to do this before WM_DESTROY (WindowClosing()) as any parent frame
124 // will receive its activation messages before this dialog receives
125 // WM_DESTROY. The parent frame would then try to activate any modal dialogs
126 // that were still open in the ModalDialogQueue, which would send activation
127 // back to this one. The framework should be improved to handle this, so this
128 // is a temporary workaround.
131 NotifyDelegate(false, base::string16(), suppress_js_messages
);
134 void JavaScriptAppModalDialog::OnAccept(const base::string16
& prompt_text
,
135 bool suppress_js_messages
) {
136 base::string16 prompt_text_to_use
= prompt_text
;
137 // This is only for testing.
138 if (use_override_prompt_text_
)
139 prompt_text_to_use
= override_prompt_text_
;
142 NotifyDelegate(true, prompt_text_to_use
, suppress_js_messages
);
145 void JavaScriptAppModalDialog::OnClose() {
146 NotifyDelegate(false, base::string16(), false);
149 void JavaScriptAppModalDialog::SetOverridePromptText(
150 const base::string16
& override_prompt_text
) {
151 override_prompt_text_
= override_prompt_text
;
152 use_override_prompt_text_
= true;
155 void JavaScriptAppModalDialog::NotifyDelegate(bool success
,
156 const base::string16
& user_input
,
157 bool suppress_js_messages
) {
161 if (!callback_
.is_null()) {
162 callback_
.Run(success
, user_input
);
166 // The callback_ above may delete web_contents_, thus removing the extra
167 // data from the map owned by ChromeJavaScriptDialogManager. Make sure
168 // to only use the data if still present. http://crbug.com/236476
169 ExtraDataMap::iterator extra_data
= extra_data_map_
->find(web_contents());
170 if (extra_data
!= extra_data_map_
->end()) {
171 extra_data
->second
.last_javascript_message_dismissal_
=
172 base::TimeTicks::Now();
173 extra_data
->second
.suppress_javascript_messages_
= suppress_js_messages
;
176 // On Views, we can end up coming through this code path twice :(.
177 // See crbug.com/63732.
178 AppModalDialog::Invalidate();