Home | History | Annotate | Download | only in web_dialogs
      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 
     18 using content::RenderViewHost;
     19 using content::WebUIMessageHandler;
     20 
     21 namespace ui {
     22 
     23 namespace {
     24 
     25 const char kWebDialogDelegateUserDataKey[] = "WebDialogDelegateUserData";
     26 
     27 class 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 
     40 WebDialogUI::WebDialogUI(content::WebUI* web_ui)
     41     : WebUIController(web_ui) {
     42 }
     43 
     44 WebDialogUI::~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 
     55 void WebDialogUI::CloseDialog(const base::ListValue* args) {
     56   OnDialogClosed(args);
     57 }
     58 
     59 // static
     60 void WebDialogUI::SetDelegate(content::WebContents* web_contents,
     61                               WebDialogDelegate* delegate) {
     62   web_contents->SetUserData(&kWebDialogDelegateUserDataKey,
     63                             new WebDialogDelegateUserData(delegate));
     64 }
     65 
     66 ////////////////////////////////////////////////////////////////////////////////
     67 // Private:
     68 
     69 WebDialogDelegate* 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 
     79 void 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 
    105 void WebDialogUI::OnDialogClosed(const 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 
    116 ExternalWebDialogUI::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 
    125 ExternalWebDialogUI::~ExternalWebDialogUI() {
    126 }
    127 
    128 }  // namespace ui
    129