diff --git a/atom/atom_resources.grd b/atom/atom_resources.grd
index 8b9b516c8b..11a80df735 100644
--- a/atom/atom_resources.grd
+++ b/atom/atom_resources.grd
@@ -17,8 +17,6 @@
-
-
diff --git a/atom/browser/api/atom_api_web_contents.cc b/atom/browser/api/atom_api_web_contents.cc
index fde1e361f3..b874f8b66e 100644
--- a/atom/browser/api/atom_api_web_contents.cc
+++ b/atom/browser/api/atom_api_web_contents.cc
@@ -468,9 +468,16 @@ void WebContents::AddNewContents(content::WebContents* source,
v8::Locker locker(isolate());
v8::HandleScope handle_scope(isolate());
+ auto source_api_contents = CreateFrom(isolate(), source);
auto new_api_contents = CreateFrom(isolate(), new_contents);
+ if (source_api_contents->GetType() == BACKGROUND_PAGE) {
+ user_gesture = true;
+ }
+
std::unique_ptr options(new base::DictionaryValue);
+ options->SetString("openerUrl", source_api_contents->GetURL().spec());
+ options->SetInteger("openerTabId", source_api_contents->GetID());
options->SetBoolean("userGesture", user_gesture);
auto url_params = new_api_contents->delayed_load_url_params_.get();
diff --git a/atom/browser/common_web_contents_delegate.cc b/atom/browser/common_web_contents_delegate.cc
index 80e4d23972..f857d42791 100644
--- a/atom/browser/common_web_contents_delegate.cc
+++ b/atom/browser/common_web_contents_delegate.cc
@@ -9,7 +9,6 @@
#include
#include "atom/browser/atom_browser_context.h"
-#include "atom/browser/atom_javascript_dialog_manager.h"
#include "atom/browser/atom_security_state_model_client.h"
#include "atom/browser/browser.h"
#include "atom/browser/native_window.h"
@@ -19,6 +18,7 @@
#include "atom/common/atom_constants.h"
#include "base/files/file_util.h"
#include "base/strings/utf_string_conversions.h"
+#include "brave/browser/brave_javascript_dialog_manager.h"
#include "chrome/browser/custom_handlers/protocol_handler_registry.h"
#include "chrome/browser/custom_handlers/protocol_handler_registry_factory.h"
#include "chrome/browser/printing/print_preview_message_handler.h"
@@ -427,10 +427,7 @@ bool CommonWebContentsDelegate::CanOverscrollContent() const {
content::JavaScriptDialogManager*
CommonWebContentsDelegate::GetJavaScriptDialogManager(
content::WebContents* source) {
- if (!dialog_manager_)
- dialog_manager_.reset(new AtomJavaScriptDialogManager);
-
- return dialog_manager_.get();
+ return brave::BraveJavaScriptDialogManager::GetInstance();
}
content::ColorChooser* CommonWebContentsDelegate::OpenColorChooser(
diff --git a/atom/browser/common_web_contents_delegate.h b/atom/browser/common_web_contents_delegate.h
index 632db0ec10..4f3dd94cb0 100644
--- a/atom/browser/common_web_contents_delegate.h
+++ b/atom/browser/common_web_contents_delegate.h
@@ -20,7 +20,6 @@ using brightray::DevToolsFileSystemIndexer;
namespace atom {
class AtomBrowserContext;
-class AtomJavaScriptDialogManager;
class NativeWindow;
class WebDialogHelper;
@@ -163,7 +162,6 @@ class CommonWebContentsDelegate
bool native_fullscreen_;
std::unique_ptr web_dialog_helper_;
- std::unique_ptr dialog_manager_;
scoped_refptr devtools_file_system_indexer_;
// Make sure BrowserContext is alwasys destroyed after WebContents.
diff --git a/atom/common/api/event_emitter_caller.h b/atom/common/api/event_emitter_caller.h
index a2567da9d1..2c08b9662e 100644
--- a/atom/common/api/event_emitter_caller.h
+++ b/atom/common/api/event_emitter_caller.h
@@ -7,6 +7,7 @@
#include
+#include "gin/converter.h"
#include "native_mate/converter.h"
namespace mate {
@@ -28,7 +29,7 @@ v8::Local EmitEvent(v8::Isolate* isolate,
v8::Local obj,
const StringType& name,
const internal::ValueVector& args) {
- internal::ValueVector concatenated_args = { StringToV8(isolate, name) };
+ internal::ValueVector concatenated_args = { gin::StringToV8(isolate, name) };
concatenated_args.reserve(1 + args.size());
concatenated_args.insert(concatenated_args.end(), args.begin(), args.end());
return internal::CallEmitWithArgs(isolate, obj, &concatenated_args);
@@ -42,7 +43,7 @@ v8::Local EmitEvent(v8::Isolate* isolate,
const StringType& name,
const Args&... args) {
internal::ValueVector converted_args = {
- StringToV8(isolate, name),
+ gin::StringToV8(isolate, name),
ConvertToV8(isolate, args)...,
};
return internal::CallEmitWithArgs(isolate, obj, &converted_args);
diff --git a/atom/common/api/resources/ipc_bindings.js b/atom/common/api/resources/ipc_bindings.js
deleted file mode 100644
index cec845f7cb..0000000000
--- a/atom/common/api/resources/ipc_bindings.js
+++ /dev/null
@@ -1,33 +0,0 @@
-const ipc = require('ipc_utils')
-
-exports.didCreateDocumentElement = function() {
- // don't try to run if there is no window object
- if (!window)
- return
-
- window.alert = function(message, title) {
- return ipc.send('window-alert', message, title)
- }
-
- window.confirm = function(message, title) {
- return ipc.sendSync('window-confirm', message, title)
- }
-
- window.prompt = function(text, defaultText) {
- return ipc.sendSync('window-prompt', text, defaultText)
- }
-
- if (window.chrome && window.chrome.tabs && window.chrome.tabs.create)
- window.open = function(url, name, specs, replace) {
- if (name !== undefined) {
- throw new Error('name of window.open is not supported yet')
- }
- if (specs !== undefined) {
- throw new Error('specs of window.open is not supported yet')
- }
- if (replace !== undefined) {
- throw new Error('replace of window.open is not supported yet')
- }
- return window.chrome.tabs.create({url: url})
- }
-}
diff --git a/atom/renderer/extensions/atom_extensions_dispatcher_delegate.cc b/atom/renderer/extensions/atom_extensions_dispatcher_delegate.cc
index d5a5f5ad28..84003897cf 100644
--- a/atom/renderer/extensions/atom_extensions_dispatcher_delegate.cc
+++ b/atom/renderer/extensions/atom_extensions_dispatcher_delegate.cc
@@ -169,7 +169,6 @@ void AtomExtensionsDispatcherDelegate::PopulateSourceMap(
source_map->RegisterSource("event_emitter", IDR_ATOM_EVENT_EMITTER_JS);
source_map->RegisterSource("ipcRenderer", IDR_BRAVE_IPC_RENDERER_JS);
source_map->RegisterSource("ipc_utils", IDR_ATOM_IPC_INTERNAL_JS);
- source_map->RegisterSource("windowDialogs", IDR_ATOM_IPC_WINDOW_DIALOGS_JS);
source_map->RegisterSource("webFrame",
IDR_ATOM_WEB_FRAME_BINDINGS_JS);
source_map->RegisterSource("remote",
diff --git a/atom/renderer/extensions/atom_extensions_renderer_client.cc b/atom/renderer/extensions/atom_extensions_renderer_client.cc
index 5ec8740064..714f7012ae 100644
--- a/atom/renderer/extensions/atom_extensions_renderer_client.cc
+++ b/atom/renderer/extensions/atom_extensions_renderer_client.cc
@@ -39,31 +39,6 @@ bool IsStandaloneExtensionProcess() {
extensions::switches::kExtensionProcess);
}
-void DidCreateDocumentElement(content::RenderFrame* render_frame) {
- v8::Isolate* isolate = blink::mainThreadIsolate();
- v8::HandleScope handle_scope(isolate);
-
- v8::Local context =
- render_frame->GetWebFrame()->mainWorldScriptContext();
- v8::Context::Scope context_scope(context);
-
- auto script_context =
- extensions::ScriptContextSet::GetContextByV8Context(context);
-
- if (script_context) {
- extensions::ModuleSystem::NativesEnabledScope
- natives_enabled(script_context->module_system());
- script_context->module_system()
- ->CallModuleMethod("windowDialogs", "didCreateDocumentElement");
- }
-
- // reschedule the callback because a new render frame
- // is not always created when navigating
- extensions::ExtensionFrameHelper::Get(render_frame)
- ->ScheduleAtDocumentStart(base::Bind(DidCreateDocumentElement,
- render_frame));
-}
-
} // namespace
namespace extensions {
@@ -127,9 +102,6 @@ void AtomExtensionsRendererClient::RenderFrameCreated(
new extensions::ExtensionFrameHelper(render_frame,
extension_dispatcher_.get());
extension_dispatcher_->OnRenderFrameCreated(render_frame);
- ExtensionFrameHelper::Get(render_frame)
- ->ScheduleAtDocumentStart(base::Bind(DidCreateDocumentElement,
- render_frame));
}
void AtomExtensionsRendererClient::RenderViewCreated(
diff --git a/brave/browser/BUILD.gn b/brave/browser/BUILD.gn
index 24ba32dca4..afbda0577f 100644
--- a/brave/browser/BUILD.gn
+++ b/brave/browser/BUILD.gn
@@ -25,6 +25,8 @@ source_set("browser") {
"brave_browser_context.cc",
"brave_content_browser_client.h",
"brave_content_browser_client.cc",
+ "brave_javascript_dialog_manager.h",
+ "brave_javascript_dialog_manager.cc",
"brave_permission_manager.h",
"brave_permission_manager.cc",
"renderer_preferences_helper.h",
diff --git a/brave/browser/brave_javascript_dialog_manager.cc b/brave/browser/brave_javascript_dialog_manager.cc
new file mode 100644
index 0000000000..0dc892d589
--- /dev/null
+++ b/brave/browser/brave_javascript_dialog_manager.cc
@@ -0,0 +1,408 @@
+// Copyright 2016 The Brave Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "brave/browser/brave_javascript_dialog_manager.h"
+
+#include
+#include
+
+#include "base/bind.h"
+#include "base/i18n/rtl.h"
+#include "base/macros.h"
+#include "base/metrics/histogram_macros.h"
+#include "base/strings/utf_string_conversions.h"
+#include "components/url_formatter/elide_url.h"
+#include "content/public/browser/web_contents.h"
+#include "content/public/common/javascript_message_type.h"
+#include "gin/converter.h"
+#include "gin/try_catch.h"
+#include "grit/components_strings.h"
+#include "ui/base/l10n/l10n_util.h"
+#include "ui/gfx/font_list.h"
+
+#include "atom/common/api/event_emitter_caller.h"
+#include "atom/common/native_mate_converters/callback.h"
+#include "atom/common/native_mate_converters/content_converter.h"
+#include "atom/common/native_mate_converters/string16_converter.h"
+#include "atom/common/node_includes.h"
+#include "native_mate/converter.h"
+#include "native_mate/dictionary.h"
+
+namespace mate {
+
+template<>
+struct Converter {
+ static v8::Local ToV8(v8::Isolate* isolate,
+ brave::JavaScriptDialogExtraData* val) {
+ if (!val)
+ return v8::Null(isolate);
+
+ mate::Dictionary dict = mate::Dictionary::CreateEmpty(isolate);
+ dict.Set("suppressJavascriptMessages", val->suppress_javascript_messages_);
+ dict.Set("dialogCount", val->dialog_count_);
+ dict.Set("suppressedDialogCount", val->suppressed_dialog_count_);
+ return dict.GetHandle();
+ }
+};
+
+}
+
+namespace brave {
+
+namespace {
+
+// Keep in sync with kDefaultMessageWidth, but allow some space for the rest of
+// the text.
+const int kUrlElideWidth = 350;
+
+bool ShouldDisplaySuppressCheckbox(
+ JavaScriptDialogExtraData* extra_data) {
+ return extra_data->dialog_count_ > 0;
+}
+
+void LogUMAMessageLengthStats(const base::string16& message) {
+ UMA_HISTOGRAM_COUNTS("JSDialogs.CountOfJSDialogMessageCharacters",
+ static_cast(message.length()));
+
+ int32_t newline_count =
+ std::count_if(message.begin(), message.end(),
+ [](const base::char16& c) { return c == '\n'; });
+ UMA_HISTOGRAM_COUNTS("JSDialogs.CountOfJSDialogMessageNewlines",
+ newline_count);
+}
+
+} // namespace
+
+JavaScriptDialogExtraData::JavaScriptDialogExtraData()
+ : dialog_count_(0),
+ suppress_javascript_messages_(false),
+ suppressed_dialog_count_(0) {}
+
+////////////////////////////////////////////////////////////////////////////////
+// BraveJavaScriptDialogManager, public:
+
+// static
+BraveJavaScriptDialogManager* BraveJavaScriptDialogManager::GetInstance() {
+ return base::Singleton::get();
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// BraveJavaScriptDialogManager, private:
+
+BraveJavaScriptDialogManager::BraveJavaScriptDialogManager() {
+}
+
+BraveJavaScriptDialogManager::~BraveJavaScriptDialogManager() {
+}
+
+void BraveJavaScriptDialogManager::RunJavaScriptDialog(
+ content::WebContents* web_contents,
+ const GURL& origin_url,
+ content::JavaScriptMessageType message_type,
+ const base::string16& message_text,
+ const base::string16& default_prompt_text,
+ const DialogClosedCallback& callback,
+ bool* did_suppress_message) {
+ *did_suppress_message = false;
+
+ JavaScriptDialogExtraData* extra_data =
+ &javascript_dialog_extra_data_[web_contents];
+
+ if (extra_data->suppress_javascript_messages_) {
+ // If a page tries to open dialogs in a tight loop, the number of
+ // suppressions logged can grow out of control. Arbitrarily cap the number
+ // logged at 100. That many suppressed dialogs is enough to indicate the
+ // page is doing something very hinky.
+ if (extra_data->suppressed_dialog_count_ < 100) {
+ // Log a suppressed dialog as one that opens and then closes immediately.
+ UMA_HISTOGRAM_MEDIUM_TIMES(
+ "JSDialogs.FineTiming.TimeBetweenDialogCreatedAndSameDialogClosed",
+ base::TimeDelta());
+
+ // Only increment the count if it's not already at the limit, to prevent
+ // overflow.
+ extra_data->suppressed_dialog_count_++;
+ }
+
+ *did_suppress_message = true;
+ return;
+ }
+
+ base::TimeTicks now = base::TimeTicks::Now();
+ if (!last_creation_time_.is_null()) {
+ // A new dialog has been created: log the time since the last one was
+ // created.
+ UMA_HISTOGRAM_MEDIUM_TIMES(
+ "JSDialogs.FineTiming.TimeBetweenDialogCreatedAndNextDialogCreated",
+ now - last_creation_time_);
+ }
+ last_creation_time_ = now;
+
+ // Also log the time since a dialog was closed, but only if this is the first
+ // dialog that was opened since the closing.
+ if (!last_close_time_.is_null()) {
+ UMA_HISTOGRAM_MEDIUM_TIMES(
+ "JSDialogs.FineTiming.TimeBetweenDialogClosedAndNextDialogCreated",
+ now - last_close_time_);
+ last_close_time_ = base::TimeTicks();
+ }
+
+ bool is_alert = message_type == content::JAVASCRIPT_MESSAGE_TYPE_ALERT;
+ base::string16 dialog_title = GetTitle(web_contents, origin_url, is_alert);
+
+ LogUMAMessageLengthStats(message_text);
+
+ v8::Isolate* isolate = v8::Isolate::GetCurrent();
+ if (!isolate) {
+ *did_suppress_message = true;
+ return;
+ }
+
+ node::Environment* env = node::Environment::GetCurrent(isolate);
+ if (!env) {
+ *did_suppress_message = true;
+ return;
+ }
+
+ gin::TryCatch try_catch(isolate);
+ mate::EmitEvent(isolate,
+ env->process_object(),
+ GetEventName(message_type),
+ web_contents,
+ extra_data,
+ dialog_title,
+ message_text,
+ default_prompt_text,
+ ShouldDisplaySuppressCheckbox(extra_data),
+ false, // is_before_unload_dialog
+ false, // is_reload
+ base::Bind(&BraveJavaScriptDialogManager::OnDialogClosed,
+ base::Unretained(this), web_contents, callback));
+ if (try_catch.HasCaught()) {
+ callback.Run(false, base::string16());
+ LOG(ERROR) << "Uncaught exception: " << try_catch.GetStackTrace();
+ } else {
+ if (extra_data->dialog_count_ < 100) {
+ extra_data->dialog_count_++;
+ }
+ }
+}
+
+void BraveJavaScriptDialogManager::RunBeforeUnloadDialog(
+ content::WebContents* web_contents,
+ bool is_reload,
+ const DialogClosedCallback& callback) {
+ JavaScriptDialogExtraData* extra_data =
+ &javascript_dialog_extra_data_[web_contents];
+
+ if (extra_data->suppress_javascript_messages_) {
+ // If a site harassed the user enough for them to put it on mute, then it
+ // lost its privilege to deny unloading.
+ callback.Run(true, base::string16());
+ return;
+ }
+
+ // Build the dialog message. We explicitly do _not_ allow the webpage to
+ // specify the contents of this dialog, because most of the time nowadays it's
+ // used for scams.
+ //
+ // This does not violate the spec. Per
+ // https://html.spec.whatwg.org/#prompt-to-unload-a-document, step 7:
+ //
+ // "The prompt shown by the user agent may include the string of the
+ // returnValue attribute, or some leading subset thereof."
+ //
+ // The prompt MAY include the string. It doesn't any more. Scam web page
+ // authors have abused this, so we're taking away the toys from everyone. This
+ // is why we can't have nice things.
+ const base::string16 title = l10n_util::GetStringUTF16(is_reload ?
+ IDS_BEFORERELOAD_MESSAGEBOX_TITLE : IDS_BEFOREUNLOAD_MESSAGEBOX_TITLE);
+ const base::string16 message =
+ l10n_util::GetStringUTF16(IDS_BEFOREUNLOAD_MESSAGEBOX_MESSAGE);
+
+ v8::Isolate* isolate = v8::Isolate::GetCurrent();
+ if (!isolate) {
+ callback.Run(true, base::string16());
+ return;
+ }
+
+ node::Environment* env = node::Environment::GetCurrent(isolate);
+ if (!env) {
+ callback.Run(true, base::string16());
+ return;
+ }
+
+ gin::TryCatch try_catch(isolate);
+ mate::EmitEvent(isolate,
+ env->process_object(),
+ GetEventName(content::JAVASCRIPT_MESSAGE_TYPE_CONFIRM),
+ web_contents,
+ extra_data,
+ title,
+ message,
+ base::string16(), // default_prompt_text
+ ShouldDisplaySuppressCheckbox(extra_data),
+ true, // is_before_unload_dialog
+ is_reload,
+ base::Bind(&BraveJavaScriptDialogManager::OnBeforeUnloadDialogClosed,
+ base::Unretained(this), web_contents, callback));
+
+ if (try_catch.HasCaught()) {
+ callback.Run(true, base::string16());
+ LOG(ERROR) << "Uncaught exception: " << try_catch.GetStackTrace();
+ } else {
+ if (extra_data->dialog_count_ < 100) {
+ extra_data->dialog_count_++;
+ }
+ }
+}
+
+bool BraveJavaScriptDialogManager::HandleJavaScriptDialog(
+ content::WebContents* web_contents,
+ bool accept,
+ const base::string16* prompt_override) {
+ v8::Isolate* isolate = v8::Isolate::GetCurrent();
+ if (!isolate)
+ return false;
+
+ node::Environment* env = node::Environment::GetCurrent(isolate);
+ if (!env)
+ return false;
+
+ gin::TryCatch try_catch(isolate);
+ mate::EmitEvent(isolate,
+ env->process_object(),
+ "handle-javascript-dialog",
+ web_contents,
+ accept,
+ *prompt_override);
+
+ if (try_catch.HasCaught()) {
+ LOG(ERROR) << "Uncaught exception: " << try_catch.GetStackTrace();
+ return false;
+ } else {
+ return true;
+ }
+}
+
+void BraveJavaScriptDialogManager::ResetDialogState(
+ content::WebContents* web_contents) {
+ v8::Isolate* isolate = v8::Isolate::GetCurrent();
+ if (!isolate)
+ return;
+
+ node::Environment* env = node::Environment::GetCurrent(isolate);
+ if (!env)
+ return;
+
+ gin::TryCatch try_catch(isolate);
+ mate::EmitEvent(isolate,
+ env->process_object(),
+ "reset-javascript-dialog",
+ web_contents);
+ if (try_catch.HasCaught()) {
+ LOG(ERROR) << "Uncaught exception: " << try_catch.GetStackTrace();
+ }
+
+ javascript_dialog_extra_data_.erase(web_contents);
+}
+
+std::string BraveJavaScriptDialogManager::GetEventName(content::JavaScriptMessageType message_type) {
+ switch (message_type) {
+ case content::JAVASCRIPT_MESSAGE_TYPE_ALERT: return "window-alert";
+ case content::JAVASCRIPT_MESSAGE_TYPE_CONFIRM: return "window-confirm";
+ case content::JAVASCRIPT_MESSAGE_TYPE_PROMPT: return "window-prompt";
+ default: return "unknown";
+ }
+}
+
+base::string16 BraveJavaScriptDialogManager::GetTitle(
+ content::WebContents* web_contents,
+ const GURL& origin_url,
+ bool is_alert) {
+ // For extensions, show the extension name, but only if the origin of
+ // the alert matches the top-level WebContents.
+ std::string name;
+ // if (extensions_client_->GetExtensionName(web_contents, origin_url, &name))
+ // return base::UTF8ToUTF16(name);
+
+ // Otherwise, return the formatted URL. For non-standard URLs such as |data:|,
+ // just say "This page".
+ bool is_same_origin_as_main_frame =
+ (web_contents->GetURL().GetOrigin() == origin_url.GetOrigin());
+ if (origin_url.IsStandard() && !origin_url.SchemeIsFile() &&
+ !origin_url.SchemeIsFileSystem()) {
+ base::string16 url_string =
+ url_formatter::ElideHost(origin_url, gfx::FontList(), kUrlElideWidth);
+ return l10n_util::GetStringFUTF16(
+ is_same_origin_as_main_frame ? IDS_JAVASCRIPT_MESSAGEBOX_TITLE
+ : IDS_JAVASCRIPT_MESSAGEBOX_TITLE_IFRAME,
+ base::i18n::GetDisplayStringInLTRDirectionality(url_string));
+ }
+ return l10n_util::GetStringUTF16(
+ is_same_origin_as_main_frame
+ ? IDS_JAVASCRIPT_MESSAGEBOX_TITLE_NONSTANDARD_URL
+ : IDS_JAVASCRIPT_MESSAGEBOX_TITLE_NONSTANDARD_URL_IFRAME);
+}
+
+void BraveJavaScriptDialogManager::CancelActiveAndPendingDialogs(
+ content::WebContents* web_contents) {
+ v8::Isolate* isolate = v8::Isolate::GetCurrent();
+ if (!isolate)
+ return;
+
+ node::Environment* env = node::Environment::GetCurrent(isolate);
+ if (!env)
+ return;
+
+ gin::TryCatch try_catch(isolate);
+ mate::EmitEvent(isolate,
+ env->process_object(),
+ "cancel-all-javascript-dialogs",
+ web_contents);
+ if (try_catch.HasCaught()) {
+ LOG(ERROR) << "Uncaught exception: " << try_catch.GetStackTrace();
+ }
+}
+
+void BraveJavaScriptDialogManager::OnBeforeUnloadDialogClosed(
+ content::WebContents* web_contents,
+ DialogClosedCallback callback,
+ bool success,
+ const base::string16& user_input,
+ bool suppress_javascript_messages = false) {
+ enum class StayVsLeave {
+ STAY = 0,
+ LEAVE = 1,
+ MAX,
+ };
+ UMA_HISTOGRAM_ENUMERATION(
+ "JSDialogs.OnBeforeUnloadStayVsLeave",
+ static_cast(success ? StayVsLeave::LEAVE : StayVsLeave::STAY),
+ static_cast(StayVsLeave::MAX));
+
+ OnDialogClosed(web_contents, callback, success, user_input,
+ suppress_javascript_messages);
+}
+
+void BraveJavaScriptDialogManager::OnDialogClosed(
+ content::WebContents* web_contents,
+ DialogClosedCallback callback,
+ bool success,
+ const base::string16& user_input,
+ bool suppress_javascript_messages = false) {
+ JavaScriptDialogExtraData* extra_data =
+ &javascript_dialog_extra_data_[web_contents];
+ extra_data->suppress_javascript_messages_ = suppress_javascript_messages;
+ // If an extension opened this dialog then the extension may shut down its
+ // lazy background page after the dialog closes. (Dialogs are closed before
+ // their WebContents is destroyed so |web_contents| is still valid here.)
+ // extensions_client_->OnDialogClosed(web_contents);
+
+ last_close_time_ = base::TimeTicks::Now();
+
+ callback.Run(success, user_input);
+}
+
+} // namespace brave
diff --git a/brave/browser/brave_javascript_dialog_manager.h b/brave/browser/brave_javascript_dialog_manager.h
new file mode 100644
index 0000000000..cbc2f6161f
--- /dev/null
+++ b/brave/browser/brave_javascript_dialog_manager.h
@@ -0,0 +1,96 @@
+// Copyright 2016 The Brave Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BRAVE_BROWSER_BRAVE_JAVASCRIPT_DIALOG_MANAGER
+#define BRAVE_BROWSER_BRAVE_JAVASCRIPT_DIALOG_MANAGER
+
+#include