1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145
|
// 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 (web_ui_->GetBindings().Has(content::BindingsPolicyValue::kWebUi)) {
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) {
content::WebUIController::WebUIRenderFrameCreated(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)
: WebDialogUI(web_ui),
ui::EnableMojoWebUI(web_ui, /*enable_chrome_send=*/true) {}
MojoWebDialogUI::~MojoWebDialogUI() = default;
void MojoWebDialogUI::WebUIRenderFrameCreated(
content::RenderFrameHost* render_frame_host) {
WebDialogUI::WebUIRenderFrameCreated(render_frame_host);
}
} // namespace ui
|