15821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Copyright (c) 2012 The Chromium Authors. All rights reserved.
25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be
35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// found in the LICENSE file.
45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
52a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "chrome/browser/ui/app_modal_dialogs/javascript_dialog_manager.h"
65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
75d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "base/bind.h"
85821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/compiler_specific.h"
95821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/i18n/rtl.h"
105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/memory/singleton.h"
11868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include "base/strings/utf_string_conversions.h"
127dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch#include "chrome/browser/chrome_notification_types.h"
132a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "chrome/browser/ui/app_modal_dialogs/app_modal_dialog.h"
145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/ui/app_modal_dialogs/app_modal_dialog_queue.h"
155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/ui/app_modal_dialogs/javascript_app_modal_dialog.h"
162a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "chrome/browser/ui/app_modal_dialogs/native_app_modal_dialog.h"
175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/common/chrome_constants.h"
181320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci#include "chrome/grit/generated_resources.h"
195d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "content/public/browser/web_contents.h"
205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "content/public/common/content_client.h"
215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "content/public/common/javascript_message_type.h"
225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "net/base/net_util.h"
235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ui/base/l10n/l10n_util.h"
245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
251320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci#if defined(ENABLE_EXTENSIONS)
261320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci#include "extensions/browser/extension_system.h"
271320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci#include "extensions/browser/process_manager.h"
281320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci#endif  // defined(ENABLE_EXTENSIONS)
291320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
30f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)using content::BrowserContext;
312a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)using content::JavaScriptDialogManager;
325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)using content::WebContents;
331320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
341320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci#if defined(ENABLE_EXTENSIONS)
355d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)using extensions::Extension;
361320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci#endif  // defined(ENABLE_EXTENSIONS)
375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace {
395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
401320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci#if defined(ENABLE_EXTENSIONS)
415d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// Returns the ProcessManager for the browser context from |web_contents|.
425d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)extensions::ProcessManager* GetExtensionsProcessManager(
435d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    WebContents* web_contents) {
445d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  return extensions::ExtensionSystem::Get(
455d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      web_contents->GetBrowserContext())->process_manager();
465d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
475d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
485d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// Returns the extension associated with |web_contents| or NULL if there is no
495d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// associated extension (or extensions are not supported).
505d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)const Extension* GetExtensionForWebContents(WebContents* web_contents) {
515d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  extensions::ProcessManager* pm = GetExtensionsProcessManager(web_contents);
525d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  return pm->GetExtensionForRenderViewHost(web_contents->GetRenderViewHost());
535d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
541320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci#endif  // defined(ENABLE_EXTENSIONS)
555d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
565d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// Keeps an |extension| from shutting down its lazy background page. If an
575d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// extension opens a dialog its lazy background page must stay alive until the
585d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// dialog closes.
591320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tuccivoid IncrementLazyKeepaliveCount(WebContents* web_contents) {
601320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci#if defined(ENABLE_EXTENSIONS)
611320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  const Extension* extension = GetExtensionForWebContents(web_contents);
621320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  if (extension == NULL)
631320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    return;
641320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
655d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  DCHECK(web_contents);
665d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  extensions::ProcessManager* pm = GetExtensionsProcessManager(web_contents);
675d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (pm)
685d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    pm->IncrementLazyKeepaliveCount(extension);
691320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci#endif  // defined(ENABLE_EXTENSIONS)
705d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
715d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
725d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// Allows an |extension| to shut down its lazy background page after a dialog
735d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// closes (if nothing else is keeping it open).
741320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tuccivoid DecrementLazyKeepaliveCount(WebContents* web_contents) {
751320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci#if defined(ENABLE_EXTENSIONS)
761320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  const Extension* extension = GetExtensionForWebContents(web_contents);
771320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  if (extension == NULL)
781320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    return;
791320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
805d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  DCHECK(web_contents);
815d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  extensions::ProcessManager* pm = GetExtensionsProcessManager(web_contents);
825d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (pm)
835d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    pm->DecrementLazyKeepaliveCount(extension);
841320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci#endif  // defined(ENABLE_EXTENSIONS)
855d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
865d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
875d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)class ChromeJavaScriptDialogManager : public JavaScriptDialogManager {
885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) public:
892a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  static ChromeJavaScriptDialogManager* GetInstance();
905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  virtual void RunJavaScriptDialog(
925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      WebContents* web_contents,
935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      const GURL& origin_url,
945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      const std::string& accept_lang,
955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      content::JavaScriptMessageType message_type,
96a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      const base::string16& message_text,
97a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      const base::string16& default_prompt_text,
985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      const DialogClosedCallback& callback,
995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      bool* did_suppress_message) OVERRIDE;
1005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  virtual void RunBeforeUnloadDialog(
1025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      WebContents* web_contents,
103a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      const base::string16& message_text,
1045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      bool is_reload,
1055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      const DialogClosedCallback& callback) OVERRIDE;
1065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1072a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  virtual bool HandleJavaScriptDialog(
1082a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      WebContents* web_contents,
1092a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      bool accept,
110a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      const base::string16* prompt_override) OVERRIDE;
1112a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
112a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)  virtual void CancelActiveAndPendingDialogs(
113a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)      WebContents* web_contents) OVERRIDE;
114a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)
115a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)  virtual void WebContentsDestroyed(WebContents* web_contents) OVERRIDE;
1165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) private:
1182a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  friend struct DefaultSingletonTraits<ChromeJavaScriptDialogManager>;
1195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1205d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  ChromeJavaScriptDialogManager();
1215d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  virtual ~ChromeJavaScriptDialogManager();
1225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1235d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  base::string16 GetTitle(WebContents* web_contents,
1245d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                          const GURL& origin_url,
1255d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                          const std::string& accept_lang,
1265d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                          bool is_alert);
1275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Wrapper around a DialogClosedCallback so that we can intercept it before
1295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // passing it onto the original callback.
1305d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  void OnDialogClosed(WebContents* web_contents,
1315d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                      DialogClosedCallback callback,
1325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                      bool success,
133a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)                      const base::string16& user_input);
1345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Mapping between the WebContents and their extra data. The key
1365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // is a void* because the pointer is just a cookie and is never dereferenced.
13790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  JavaScriptAppModalDialog::ExtraDataMap javascript_dialog_extra_data_;
1385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1392a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DISALLOW_COPY_AND_ASSIGN(ChromeJavaScriptDialogManager);
1405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)};
1415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)////////////////////////////////////////////////////////////////////////////////
1432a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// ChromeJavaScriptDialogManager, public:
1445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1455d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)ChromeJavaScriptDialogManager::ChromeJavaScriptDialogManager() {
1465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1482a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)ChromeJavaScriptDialogManager::~ChromeJavaScriptDialogManager() {
1495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// static
1522a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)ChromeJavaScriptDialogManager* ChromeJavaScriptDialogManager::GetInstance() {
1532a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return Singleton<ChromeJavaScriptDialogManager>::get();
1545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1562a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void ChromeJavaScriptDialogManager::RunJavaScriptDialog(
1575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    WebContents* web_contents,
1585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const GURL& origin_url,
1595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const std::string& accept_lang,
1605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    content::JavaScriptMessageType message_type,
161a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    const base::string16& message_text,
162a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    const base::string16& default_prompt_text,
1635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const DialogClosedCallback& callback,
1645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    bool* did_suppress_message)  {
1655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  *did_suppress_message = false;
1665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ChromeJavaScriptDialogExtraData* extra_data =
1685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      &javascript_dialog_extra_data_[web_contents];
1695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (extra_data->suppress_javascript_messages_) {
1715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    *did_suppress_message = true;
1725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
1735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  base::TimeDelta time_since_last_message = base::TimeTicks::Now() -
1765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      extra_data->last_javascript_message_dismissal_;
1775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  bool display_suppress_checkbox = false;
1785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Show a checkbox offering to suppress further messages if this message is
179d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  // being displayed within kJavaScriptMessageExpectedDelay of the last one.
1805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (time_since_last_message <
1815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      base::TimeDelta::FromMilliseconds(
182d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)          chrome::kJavaScriptMessageExpectedDelay)) {
1835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    display_suppress_checkbox = true;
184a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)  } else {
185a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)    display_suppress_checkbox = false;
1865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  bool is_alert = message_type == content::JAVASCRIPT_MESSAGE_TYPE_ALERT;
1895d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  base::string16 dialog_title =
1905d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      GetTitle(web_contents, origin_url, accept_lang, is_alert);
1915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1921320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  IncrementLazyKeepaliveCount(web_contents);
1935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  AppModalDialogQueue::GetInstance()->AddDialog(new JavaScriptAppModalDialog(
1955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      web_contents,
19690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)      &javascript_dialog_extra_data_,
1975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      dialog_title,
1985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      message_type,
1995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      message_text,
2005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      default_prompt_text,
2015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      display_suppress_checkbox,
2025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      false,  // is_before_unload_dialog
2035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      false,  // is_reload
2042a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      base::Bind(&ChromeJavaScriptDialogManager::OnDialogClosed,
2055d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                 base::Unretained(this), web_contents, callback)));
2065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2082a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void ChromeJavaScriptDialogManager::RunBeforeUnloadDialog(
2095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    WebContents* web_contents,
210a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    const base::string16& message_text,
2115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    bool is_reload,
2125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const DialogClosedCallback& callback) {
213a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  const base::string16 title = l10n_util::GetStringUTF16(is_reload ?
2145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      IDS_BEFORERELOAD_MESSAGEBOX_TITLE : IDS_BEFOREUNLOAD_MESSAGEBOX_TITLE);
215a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  const base::string16 footer = l10n_util::GetStringUTF16(is_reload ?
2165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      IDS_BEFORERELOAD_MESSAGEBOX_FOOTER : IDS_BEFOREUNLOAD_MESSAGEBOX_FOOTER);
2175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2185d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  base::string16 full_message =
2195d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      message_text + base::ASCIIToUTF16("\n\n") + footer;
2205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2211320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  IncrementLazyKeepaliveCount(web_contents);
2225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  AppModalDialogQueue::GetInstance()->AddDialog(new JavaScriptAppModalDialog(
2245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      web_contents,
22590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)      &javascript_dialog_extra_data_,
2265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      title,
2275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      content::JAVASCRIPT_MESSAGE_TYPE_CONFIRM,
2285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      full_message,
229a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      base::string16(),  // default_prompt_text
2305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      false,       // display_suppress_checkbox
2315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      true,        // is_before_unload_dialog
2325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      is_reload,
2332a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      base::Bind(&ChromeJavaScriptDialogManager::OnDialogClosed,
2345d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                 base::Unretained(this), web_contents, callback)));
2355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2372a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)bool ChromeJavaScriptDialogManager::HandleJavaScriptDialog(
2382a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    WebContents* web_contents,
2392a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    bool accept,
240a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    const base::string16* prompt_override) {
2412a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  AppModalDialogQueue* dialog_queue = AppModalDialogQueue::GetInstance();
2422a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (!dialog_queue->HasActiveDialog() ||
2432a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      !dialog_queue->active_dialog()->IsJavaScriptModalDialog() ||
2442a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      dialog_queue->active_dialog()->web_contents() != web_contents) {
2452a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return false;
2462a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
2472a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  JavaScriptAppModalDialog* dialog = static_cast<JavaScriptAppModalDialog*>(
2482a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      dialog_queue->active_dialog());
2492a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (accept) {
2502a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    if (prompt_override)
2512a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      dialog->SetOverridePromptText(*prompt_override);
2522a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    dialog->native_dialog()->AcceptAppModalDialog();
2532a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  } else {
2542a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    dialog->native_dialog()->CancelAppModalDialog();
2552a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
2562a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return true;
2572a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
2582a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
259a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)void ChromeJavaScriptDialogManager::WebContentsDestroyed(
2605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    WebContents* web_contents) {
261a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)  CancelActiveAndPendingDialogs(web_contents);
2625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  javascript_dialog_extra_data_.erase(web_contents);
2635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2655d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)base::string16 ChromeJavaScriptDialogManager::GetTitle(
2665d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    WebContents* web_contents,
2675d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    const GURL& origin_url,
2685d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    const std::string& accept_lang,
2695d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    bool is_alert) {
2705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // If the URL hasn't any host, return the default string.
2715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!origin_url.has_host()) {
2725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return l10n_util::GetStringUTF16(
2735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          is_alert ? IDS_JAVASCRIPT_ALERT_DEFAULT_TITLE
2745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                   : IDS_JAVASCRIPT_MESSAGEBOX_DEFAULT_TITLE);
2755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2770529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  // For extensions, show the extension name, but only if the origin of
2780529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  // the alert matches the top-level WebContents.
2791320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci#if defined(ENABLE_EXTENSIONS)
2805d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  const Extension* extension = GetExtensionForWebContents(web_contents);
2810529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  if (extension &&
2820529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch      web_contents->GetLastCommittedURL().GetOrigin() == origin_url) {
2835d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    return base::UTF8ToUTF16(extension->name());
2840529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  }
2851320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci#endif  // defined(ENABLE_EXTENSIONS)
2865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Otherwise, return the formatted URL.
2885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // In this case, force URL to have LTR directionality.
289a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  base::string16 url_string = net::FormatUrl(origin_url, accept_lang);
2905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return l10n_util::GetStringFUTF16(
2915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      is_alert ? IDS_JAVASCRIPT_ALERT_TITLE
2925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      : IDS_JAVASCRIPT_MESSAGEBOX_TITLE,
2935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      base::i18n::GetDisplayStringInLTRDirectionality(url_string));
2945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
296a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)void ChromeJavaScriptDialogManager::CancelActiveAndPendingDialogs(
2975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    WebContents* web_contents) {
2985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  AppModalDialogQueue* queue = AppModalDialogQueue::GetInstance();
2995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  AppModalDialog* active_dialog = queue->active_dialog();
3005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (active_dialog && active_dialog->web_contents() == web_contents)
3015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    active_dialog->Invalidate();
3025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (AppModalDialogQueue::iterator i = queue->begin();
3035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)       i != queue->end(); ++i) {
3045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if ((*i)->web_contents() == web_contents)
3055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      (*i)->Invalidate();
3065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
3075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3092a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void ChromeJavaScriptDialogManager::OnDialogClosed(
3105d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    WebContents* web_contents,
3115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    DialogClosedCallback callback,
3125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    bool success,
313a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    const base::string16& user_input) {
3145d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // If an extension opened this dialog then the extension may shut down its
3155d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // lazy background page after the dialog closes. (Dialogs are closed before
3165d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // their WebContents is destroyed so |web_contents| is still valid here.)
3171320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  DecrementLazyKeepaliveCount(web_contents);
3185d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
3195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  callback.Run(success, user_input);
3205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}  // namespace
3235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3242a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)content::JavaScriptDialogManager* GetJavaScriptDialogManagerInstance() {
3252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return ChromeJavaScriptDialogManager::GetInstance();
3265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
327