1// Copyright (c) 2012 The Chromium Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#include "ui/web_dialogs/web_dialog_ui.h"
6
7#include "base/bind.h"
8#include "base/bind_helpers.h"
9#include "base/lazy_instance.h"
10#include "base/values.h"
11#include "content/public/browser/render_view_host.h"
12#include "content/public/browser/web_contents.h"
13#include "content/public/browser/web_ui.h"
14#include "content/public/browser/web_ui_message_handler.h"
15#include "content/public/common/bindings_policy.h"
16#include "ui/web_dialogs/web_dialog_delegate.h"
17
18using content::RenderViewHost;
19using content::WebUIMessageHandler;
20
21namespace ui {
22
23namespace {
24
25const char kWebDialogDelegateUserDataKey[] = "WebDialogDelegateUserData";
26
27class WebDialogDelegateUserData : public base::SupportsUserData::Data {
28 public:
29  explicit WebDialogDelegateUserData(WebDialogDelegate* delegate)
30      : delegate_(delegate) {}
31  virtual ~WebDialogDelegateUserData() {}
32  WebDialogDelegate* delegate() { return delegate_; }
33
34 private:
35  WebDialogDelegate* delegate_;  // unowned
36};
37
38}  // namespace
39
40WebDialogUI::WebDialogUI(content::WebUI* web_ui)
41    : WebUIController(web_ui) {
42}
43
44WebDialogUI::~WebDialogUI() {
45  // Don't unregister our user data. During the teardown of the WebContents,
46  // this will be deleted, but the WebContents will already be destroyed.
47  //
48  // This object is owned indirectly by the WebContents. WebUIs can change, so
49  // it's scary if this WebUI is changed out and replaced with something else,
50  // since the user data will still point to the old delegate. But the delegate
51  // is itself the owner of the WebContents for a dialog so will be in scope,
52  // and the HTML dialogs won't swap WebUIs anyway since they don't navigate.
53}
54
55void WebDialogUI::CloseDialog(const base::ListValue* args) {
56  OnDialogClosed(args);
57}
58
59// static
60void WebDialogUI::SetDelegate(content::WebContents* web_contents,
61                              WebDialogDelegate* delegate) {
62  web_contents->SetUserData(&kWebDialogDelegateUserDataKey,
63                            new WebDialogDelegateUserData(delegate));
64}
65
66////////////////////////////////////////////////////////////////////////////////
67// Private:
68
69WebDialogDelegate* WebDialogUI::GetDelegate(
70    content::WebContents* web_contents) {
71  WebDialogDelegateUserData* user_data =
72      static_cast<WebDialogDelegateUserData*>(
73          web_contents->GetUserData(&kWebDialogDelegateUserDataKey));
74
75  return user_data ? user_data->delegate() : NULL;
76}
77
78
79void WebDialogUI::RenderViewCreated(RenderViewHost* render_view_host) {
80  // Hook up the javascript function calls, also known as chrome.send("foo")
81  // calls in the HTML, to the actual C++ functions.
82  web_ui()->RegisterMessageCallback("dialogClose",
83      base::Bind(&WebDialogUI::OnDialogClosed, base::Unretained(this)));
84
85  // Pass the arguments to the renderer supplied by the delegate.
86  std::string dialog_args;
87  std::vector<WebUIMessageHandler*> handlers;
88  WebDialogDelegate* delegate = GetDelegate(web_ui()->GetWebContents());
89  if (delegate) {
90    dialog_args = delegate->GetDialogArgs();
91    delegate->GetWebUIMessageHandlers(&handlers);
92  }
93
94  if (0 != (web_ui()->GetBindings() & content::BINDINGS_POLICY_WEB_UI))
95    render_view_host->SetWebUIProperty("dialogArguments", dialog_args);
96  for (std::vector<WebUIMessageHandler*>::iterator it = handlers.begin();
97       it != handlers.end(); ++it) {
98    web_ui()->AddMessageHandler(*it);
99  }
100
101  if (delegate)
102    delegate->OnDialogShown(web_ui(), render_view_host);
103}
104
105void WebDialogUI::OnDialogClosed(const base::ListValue* args) {
106  WebDialogDelegate* delegate = GetDelegate(web_ui()->GetWebContents());
107  if (delegate) {
108    std::string json_retval;
109    if (args && !args->empty() && !args->GetString(0, &json_retval))
110      NOTREACHED() << "Could not read JSON argument";
111
112    delegate->OnDialogCloseFromWebUI(json_retval);
113  }
114}
115
116ExternalWebDialogUI::ExternalWebDialogUI(content::WebUI* web_ui)
117    : WebDialogUI(web_ui) {
118  // Non-file based UI needs to not have access to the Web UI bindings
119  // for security reasons. The code hosting the dialog should provide
120  // dialog specific functionality through other bindings and methods
121  // that are scoped in duration to the dialogs existence.
122  web_ui->SetBindings(web_ui->GetBindings() & ~content::BINDINGS_POLICY_WEB_UI);
123}
124
125ExternalWebDialogUI::~ExternalWebDialogUI() {
126}
127
128}  // namespace ui
129