Roll src/third_party/WebKit 6b63e20:35e1984 (svn 201060:201061)
[chromium-blink-merge.git] / components / app_modal / javascript_dialog_manager.cc
blob7892b6ce8de4ff1fe289812b8297b2805e7e3e4e
1 // Copyright 2014 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 "components/app_modal/javascript_dialog_manager.h"
7 #include "base/bind.h"
8 #include "base/i18n/rtl.h"
9 #include "base/strings/utf_string_conversions.h"
10 #include "components/app_modal/app_modal_dialog.h"
11 #include "components/app_modal/app_modal_dialog_queue.h"
12 #include "components/app_modal/javascript_app_modal_dialog.h"
13 #include "components/app_modal/javascript_dialog_extensions_client.h"
14 #include "components/app_modal/javascript_native_dialog_factory.h"
15 #include "components/app_modal/native_app_modal_dialog.h"
16 #include "components/url_formatter/url_formatter.h"
17 #include "content/public/common/javascript_message_type.h"
18 #include "grit/components_strings.h"
19 #include "net/base/net_util.h"
20 #include "ui/base/l10n/l10n_util.h"
22 namespace app_modal {
23 namespace {
25 class DefaultExtensionsClient : public JavaScriptDialogExtensionsClient {
26 public:
27 DefaultExtensionsClient() {}
28 ~DefaultExtensionsClient() override {}
30 private:
31 // JavaScriptDialogExtensionsClient:
32 void OnDialogOpened(content::WebContents* web_contents) override {}
33 void OnDialogClosed(content::WebContents* web_contents) override {}
34 bool GetExtensionName(content::WebContents* web_contents,
35 const GURL& origin_url,
36 std::string* name_out) override {
37 return false;
40 DISALLOW_COPY_AND_ASSIGN(DefaultExtensionsClient);
43 bool ShouldDisplaySuppressCheckbox(
44 ChromeJavaScriptDialogExtraData* extra_data) {
45 return extra_data->has_already_shown_a_dialog_;
48 } // namespace
50 ////////////////////////////////////////////////////////////////////////////////
51 // JavaScriptDialogManager, public:
53 // static
54 JavaScriptDialogManager* JavaScriptDialogManager::GetInstance() {
55 return Singleton<JavaScriptDialogManager>::get();
58 void JavaScriptDialogManager::SetNativeDialogFactory(
59 scoped_ptr<JavaScriptNativeDialogFactory> factory) {
60 native_dialog_factory_ = factory.Pass();
63 void JavaScriptDialogManager::SetExtensionsClient(
64 scoped_ptr<JavaScriptDialogExtensionsClient> extensions_client) {
65 extensions_client_ = extensions_client.Pass();
68 ////////////////////////////////////////////////////////////////////////////////
69 // JavaScriptDialogManager, private:
71 JavaScriptDialogManager::JavaScriptDialogManager()
72 : extensions_client_(new DefaultExtensionsClient) {
75 JavaScriptDialogManager::~JavaScriptDialogManager() {
78 void JavaScriptDialogManager::RunJavaScriptDialog(
79 content::WebContents* web_contents,
80 const GURL& origin_url,
81 const std::string& accept_lang,
82 content::JavaScriptMessageType message_type,
83 const base::string16& message_text,
84 const base::string16& default_prompt_text,
85 const DialogClosedCallback& callback,
86 bool* did_suppress_message) {
87 *did_suppress_message = false;
89 ChromeJavaScriptDialogExtraData* extra_data =
90 &javascript_dialog_extra_data_
91 [JavaScriptAppModalDialog::GetSerializedOriginForWebContents(
92 web_contents)];
94 if (extra_data->suppress_javascript_messages_) {
95 *did_suppress_message = true;
96 return;
99 bool is_alert = message_type == content::JAVASCRIPT_MESSAGE_TYPE_ALERT;
100 base::string16 dialog_title =
101 GetTitle(web_contents, origin_url, accept_lang, is_alert);
103 extensions_client_->OnDialogOpened(web_contents);
105 AppModalDialogQueue::GetInstance()->AddDialog(new JavaScriptAppModalDialog(
106 web_contents,
107 &javascript_dialog_extra_data_,
108 dialog_title,
109 message_type,
110 message_text,
111 default_prompt_text,
112 ShouldDisplaySuppressCheckbox(extra_data),
113 false, // is_before_unload_dialog
114 false, // is_reload
115 base::Bind(&JavaScriptDialogManager::OnDialogClosed,
116 base::Unretained(this), web_contents, callback)));
119 void JavaScriptDialogManager::RunBeforeUnloadDialog(
120 content::WebContents* web_contents,
121 const base::string16& message_text,
122 bool is_reload,
123 const DialogClosedCallback& callback) {
124 ChromeJavaScriptDialogExtraData* extra_data =
125 &javascript_dialog_extra_data_
126 [JavaScriptAppModalDialog::GetSerializedOriginForWebContents(
127 web_contents)];
129 if (extra_data->suppress_javascript_messages_) {
130 // If a site harassed the user enough for them to put it on mute, then it
131 // lost its privilege to deny unloading.
132 callback.Run(true, base::string16());
133 return;
136 const base::string16 title = l10n_util::GetStringUTF16(is_reload ?
137 IDS_BEFORERELOAD_MESSAGEBOX_TITLE : IDS_BEFOREUNLOAD_MESSAGEBOX_TITLE);
138 const base::string16 footer = l10n_util::GetStringUTF16(is_reload ?
139 IDS_BEFORERELOAD_MESSAGEBOX_FOOTER : IDS_BEFOREUNLOAD_MESSAGEBOX_FOOTER);
141 base::string16 full_message =
142 message_text + base::ASCIIToUTF16("\n\n") + footer;
144 extensions_client_->OnDialogOpened(web_contents);
146 AppModalDialogQueue::GetInstance()->AddDialog(new JavaScriptAppModalDialog(
147 web_contents,
148 &javascript_dialog_extra_data_,
149 title,
150 content::JAVASCRIPT_MESSAGE_TYPE_CONFIRM,
151 full_message,
152 base::string16(), // default_prompt_text
153 ShouldDisplaySuppressCheckbox(extra_data),
154 true, // is_before_unload_dialog
155 is_reload,
156 base::Bind(&JavaScriptDialogManager::OnDialogClosed,
157 base::Unretained(this), web_contents, callback)));
160 bool JavaScriptDialogManager::HandleJavaScriptDialog(
161 content::WebContents* web_contents,
162 bool accept,
163 const base::string16* prompt_override) {
164 AppModalDialogQueue* dialog_queue = AppModalDialogQueue::GetInstance();
165 if (!dialog_queue->HasActiveDialog() ||
166 !dialog_queue->active_dialog()->IsJavaScriptModalDialog() ||
167 dialog_queue->active_dialog()->web_contents() != web_contents) {
168 return false;
170 JavaScriptAppModalDialog* dialog = static_cast<JavaScriptAppModalDialog*>(
171 dialog_queue->active_dialog());
172 if (accept) {
173 if (prompt_override)
174 dialog->SetOverridePromptText(*prompt_override);
175 dialog->native_dialog()->AcceptAppModalDialog();
176 } else {
177 dialog->native_dialog()->CancelAppModalDialog();
179 return true;
182 void JavaScriptDialogManager::ResetDialogState(
183 content::WebContents* web_contents) {
184 CancelActiveAndPendingDialogs(web_contents);
185 javascript_dialog_extra_data_.erase(
186 JavaScriptAppModalDialog::GetSerializedOriginForWebContents(
187 web_contents));
190 base::string16 JavaScriptDialogManager::GetTitle(
191 content::WebContents* web_contents,
192 const GURL& origin_url,
193 const std::string& accept_lang,
194 bool is_alert) {
195 // If the URL hasn't any host, return the default string.
196 if (!origin_url.has_host()) {
197 return l10n_util::GetStringUTF16(
198 is_alert ? IDS_JAVASCRIPT_ALERT_DEFAULT_TITLE
199 : IDS_JAVASCRIPT_MESSAGEBOX_DEFAULT_TITLE);
202 // For extensions, show the extension name, but only if the origin of
203 // the alert matches the top-level WebContents.
204 std::string name;
205 if (extensions_client_->GetExtensionName(web_contents, origin_url, &name))
206 return base::UTF8ToUTF16(name);
208 // Otherwise, return the formatted URL.
209 // In this case, force URL to have LTR directionality.
210 base::string16 url_string = url_formatter::FormatUrl(origin_url, accept_lang);
211 return l10n_util::GetStringFUTF16(
212 is_alert ? IDS_JAVASCRIPT_ALERT_TITLE
213 : IDS_JAVASCRIPT_MESSAGEBOX_TITLE,
214 base::i18n::GetDisplayStringInLTRDirectionality(url_string));
217 void JavaScriptDialogManager::CancelActiveAndPendingDialogs(
218 content::WebContents* web_contents) {
219 AppModalDialogQueue* queue = AppModalDialogQueue::GetInstance();
220 AppModalDialog* active_dialog = queue->active_dialog();
221 for (AppModalDialogQueue::iterator i = queue->begin();
222 i != queue->end(); ++i) {
223 // Invalidating the active dialog might trigger showing a not-yet
224 // invalidated dialog, so invalidate the active dialog last.
225 if ((*i) == active_dialog)
226 continue;
227 if ((*i)->web_contents() == web_contents)
228 (*i)->Invalidate();
230 if (active_dialog && active_dialog->web_contents() == web_contents)
231 active_dialog->Invalidate();
234 void JavaScriptDialogManager::OnDialogClosed(
235 content::WebContents* web_contents,
236 DialogClosedCallback callback,
237 bool success,
238 const base::string16& user_input) {
239 // If an extension opened this dialog then the extension may shut down its
240 // lazy background page after the dialog closes. (Dialogs are closed before
241 // their WebContents is destroyed so |web_contents| is still valid here.)
242 extensions_client_->OnDialogClosed(web_contents);
244 callback.Run(success, user_input);
247 } // namespace app_modal