blob: f745c62d906a83cea72b9e609dd32a6f357ac24a [file] [log] [blame]
// Copyright 2012 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "ui/web_dialogs/web_dialog_ui.h"
#include "base/functional/bind.h"
#include "base/functional/callback_helpers.h"
#include "base/lazy_instance.h"
#include "base/memory/ptr_util.h"
#include "base/memory/raw_ptr.h"
#include "base/values.h"
#include "content/public/browser/render_frame_host.h"
#include "content/public/browser/web_contents.h"
#include "content/public/browser/web_ui.h"
#include "content/public/browser/web_ui_message_handler.h"
#include "content/public/common/bindings_policy.h"
#include "ui/web_dialogs/web_dialog_delegate.h"
using content::RenderFrameHost;
using content::WebUIMessageHandler;
namespace ui {
namespace {
const char kWebDialogDelegateUserDataKey[] = "WebDialogDelegateUserData";
class WebDialogDelegateUserData : public base::SupportsUserData::Data {
public:
explicit WebDialogDelegateUserData(WebDialogDelegate* delegate)
: delegate_(delegate) {}
~WebDialogDelegateUserData() override {}
WebDialogDelegate* delegate() { return delegate_; }
private:
raw_ptr<WebDialogDelegate> delegate_; // unowned
};
} // namespace
// static
void WebDialogUIBase::SetDelegate(content::WebContents* web_contents,
WebDialogDelegate* delegate) {
web_contents->SetUserData(
&kWebDialogDelegateUserDataKey,
std::make_unique<WebDialogDelegateUserData>(delegate));
}
WebDialogUIBase::WebDialogUIBase(content::WebUI* web_ui) : web_ui_(web_ui) {}
// Don't unregister our user data. During the teardown of the WebContents, this
// will be deleted, but the WebContents will already be destroyed.
//
// This object is owned indirectly by the WebContents. WebUIs can change, so
// it's scary if this WebUI is changed out and replaced with something else,
// since the user data will still point to the old delegate. But the delegate is
// itself the owner of the WebContents for a dialog so will be in scope, and the
// HTML dialogs won't swap WebUIs anyway since they don't navigate.
WebDialogUIBase::~WebDialogUIBase() = default;
void WebDialogUIBase::CloseDialog(const base::Value::List& args) {
OnDialogClosed(args);
}
WebDialogDelegate* WebDialogUIBase::GetDelegate(
content::WebContents* web_contents) {
WebDialogDelegateUserData* user_data =
static_cast<WebDialogDelegateUserData*>(
web_contents->GetUserData(&kWebDialogDelegateUserDataKey));
return user_data ? user_data->delegate() : NULL;
}
void WebDialogUIBase::HandleRenderFrameCreated(
RenderFrameHost* render_frame_host) {
// Hook up the javascript function calls, also known as chrome.send("foo")
// calls in the HTML, to the actual C++ functions.
web_ui_->RegisterMessageCallback(
"dialogClose", base::BindRepeating(&WebDialogUIBase::OnDialogClosed,
base::Unretained(this)));
// Pass the arguments to the renderer supplied by the delegate.
std::string dialog_args;
std::vector<WebUIMessageHandler*> handlers;
WebDialogDelegate* delegate = GetDelegate(web_ui_->GetWebContents());
if (delegate) {
dialog_args = delegate->GetDialogArgs();
delegate->GetWebUIMessageHandlers(&handlers);
}
if (content::BINDINGS_POLICY_NONE !=
(web_ui_->GetBindings() & content::BINDINGS_POLICY_WEB_UI)) {
render_frame_host->SetWebUIProperty("dialogArguments", dialog_args);
}
for (WebUIMessageHandler* handler : handlers)
web_ui_->AddMessageHandler(base::WrapUnique(handler));
if (delegate)
delegate->OnDialogShown(web_ui_);
}
void WebDialogUIBase::OnDialogClosed(const base::Value::List& args) {
WebDialogDelegate* delegate = GetDelegate(web_ui_->GetWebContents());
if (delegate) {
std::string json_retval;
if (!args.empty()) {
if (args[0].is_string())
json_retval = args[0].GetString();
else
NOTREACHED() << "Could not read JSON argument";
}
delegate->OnDialogCloseFromWebUI(json_retval);
}
}
WebDialogUI::WebDialogUI(content::WebUI* web_ui)
: WebDialogUIBase(web_ui), content::WebUIController(web_ui) {}
WebDialogUI::~WebDialogUI() = default;
void WebDialogUI::WebUIRenderFrameCreated(RenderFrameHost* render_frame_host) {
HandleRenderFrameCreated(render_frame_host);
}
// Note: chrome.send() must always be enabled for dialogs, since dialogs rely on
// chrome.send() to notify their handlers that the dialog should be closed. See
// the "dialogClose" message handler above in
// WebDialogUIBase::HandleRenderFrameCreated().
MojoWebDialogUI::MojoWebDialogUI(content::WebUI* web_ui)
: WebDialogUIBase(web_ui),
MojoWebUIController(web_ui, /*enable_chrome_send=*/true) {}
MojoWebDialogUI::~MojoWebDialogUI() = default;
void MojoWebDialogUI::WebUIRenderFrameCreated(
content::RenderFrameHost* render_frame_host) {
content::WebUIController::WebUIRenderFrameCreated(render_frame_host);
HandleRenderFrameCreated(render_frame_host);
}
} // namespace ui