1 // Copyright 2012 The Chromium Authors
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "ui/web_dialogs/web_dialog_ui.h"
7 #include "base/functional/bind.h"
8 #include "base/functional/callback_helpers.h"
9 #include "base/lazy_instance.h"
10 #include "base/memory/ptr_util.h"
11 #include "base/memory/raw_ptr.h"
12 #include "base/values.h"
13 #include "content/public/browser/render_frame_host.h"
14 #include "content/public/browser/web_contents.h"
15 #include "content/public/browser/web_ui.h"
16 #include "content/public/browser/web_ui_message_handler.h"
17 #include "content/public/common/bindings_policy.h"
18 #include "ui/web_dialogs/web_dialog_delegate.h"
20 using content::RenderFrameHost;
21 using content::WebUIMessageHandler;
27 const char kWebDialogDelegateUserDataKey[] = "WebDialogDelegateUserData";
29 class WebDialogDelegateUserData : public base::SupportsUserData::Data {
31 explicit WebDialogDelegateUserData(WebDialogDelegate* delegate)
32 : delegate_(delegate) {}
33 ~WebDialogDelegateUserData() override {}
34 WebDialogDelegate* delegate() { return delegate_; }
37 raw_ptr<WebDialogDelegate> delegate_; // unowned
43 void WebDialogUIBase::SetDelegate(content::WebContents* web_contents,
44 WebDialogDelegate* delegate) {
45 web_contents->SetUserData(
46 &kWebDialogDelegateUserDataKey,
47 std::make_unique<WebDialogDelegateUserData>(delegate));
50 WebDialogUIBase::WebDialogUIBase(content::WebUI* web_ui) : web_ui_(web_ui) {}
52 // Don't unregister our user data. During the teardown of the WebContents, this
53 // will be deleted, but the WebContents will already be destroyed.
55 // This object is owned indirectly by the WebContents. WebUIs can change, so
56 // it's scary if this WebUI is changed out and replaced with something else,
57 // since the user data will still point to the old delegate. But the delegate is
58 // itself the owner of the WebContents for a dialog so will be in scope, and the
59 // HTML dialogs won't swap WebUIs anyway since they don't navigate.
60 WebDialogUIBase::~WebDialogUIBase() = default;
62 void WebDialogUIBase::CloseDialog(const base::Value::List& args) {
66 WebDialogDelegate* WebDialogUIBase::GetDelegate(
67 content::WebContents* web_contents) {
68 WebDialogDelegateUserData* user_data =
69 static_cast<WebDialogDelegateUserData*>(
70 web_contents->GetUserData(&kWebDialogDelegateUserDataKey));
72 return user_data ? user_data->delegate() : NULL;
75 void WebDialogUIBase::HandleRenderFrameCreated(
76 RenderFrameHost* render_frame_host) {
77 // Hook up the javascript function calls, also known as chrome.send("foo")
78 // calls in the HTML, to the actual C++ functions.
79 web_ui_->RegisterMessageCallback(
80 "dialogClose", base::BindRepeating(&WebDialogUIBase::OnDialogClosed,
81 base::Unretained(this)));
83 // Pass the arguments to the renderer supplied by the delegate.
84 std::string dialog_args;
85 std::vector<WebUIMessageHandler*> handlers;
86 WebDialogDelegate* delegate = GetDelegate(web_ui_->GetWebContents());
88 dialog_args = delegate->GetDialogArgs();
89 delegate->GetWebUIMessageHandlers(&handlers);
92 if (content::BINDINGS_POLICY_NONE !=
93 (web_ui_->GetBindings() & content::BINDINGS_POLICY_WEB_UI)) {
94 render_frame_host->SetWebUIProperty("dialogArguments", dialog_args);
96 for (WebUIMessageHandler* handler : handlers)
97 web_ui_->AddMessageHandler(base::WrapUnique(handler));
100 delegate->OnDialogShown(web_ui_);
103 void WebDialogUIBase::OnDialogClosed(const base::Value::List& args) {
104 WebDialogDelegate* delegate = GetDelegate(web_ui_->GetWebContents());
106 std::string json_retval;
108 if (args[0].is_string())
109 json_retval = args[0].GetString();
111 NOTREACHED() << "Could not read JSON argument";
114 delegate->OnDialogCloseFromWebUI(json_retval);
118 WebDialogUI::WebDialogUI(content::WebUI* web_ui)
119 : WebDialogUIBase(web_ui), content::WebUIController(web_ui) {}
121 WebDialogUI::~WebDialogUI() = default;
123 void WebDialogUI::WebUIRenderFrameCreated(RenderFrameHost* render_frame_host) {
124 HandleRenderFrameCreated(render_frame_host);
127 // Note: chrome.send() must always be enabled for dialogs, since dialogs rely on
128 // chrome.send() to notify their handlers that the dialog should be closed. See
129 // the "dialogClose" message handler above in
130 // WebDialogUIBase::HandleRenderFrameCreated().
131 MojoWebDialogUI::MojoWebDialogUI(content::WebUI* web_ui)
132 : WebDialogUIBase(web_ui),
133 MojoWebUIController(web_ui, /*enable_chrome_send=*/true) {}
135 MojoWebDialogUI::~MojoWebDialogUI() = default;
137 void MojoWebDialogUI::WebUIRenderFrameCreated(
138 content::RenderFrameHost* render_frame_host) {
139 content::WebUIController::WebUIRenderFrameCreated(render_frame_host);
140 HandleRenderFrameCreated(render_frame_host);