How to implement CefJSDialogHandler?

Having problems with building or using CEF's C/C++ APIs? This forum is here to help. Please do not post bug reports or feature requests here.

How to implement CefJSDialogHandler?

Postby rkcef » Wed Apr 21, 2021 11:20 am

Hello everyone,

I'm fairly new to CEF in general. I'm using the C++ example project "cefclient" to build my own desktop application for Windows 10. So far it seems to work fine. I'm using the CEF version "90.5.4+gc6a4331+chromium-90.0.4430.72".

Right now I'm trying to override (of if possible to hide altogether) the default Javascript prompt for the event "onbeforeunload" when the application window gets closed (for example by clicking on the top right "X" button).

I'm trying to extend the class "ClientHandler" (cefclient\browser\client_handler.h) with the class "CefJSDialogHandler" (cef\include\cef_jsdialog_handler.h) to implement the two methods "OnJSDialog" and "OnBeforeUnloadDialog".
This seems to be the right place because there's already a method called "GetJSDialogHandler()" that returns "CefRefPtr<CefJSDialogHandler>" (for linux, but still).

The issue I'm facing is, when I extend "ClientHandler" with "CefJSDialogHandler" and recompile everything, the application crashes immediately after I double click the EXE file. When I call the EXE file from the Terminal, it still crashes but I get the message "Segmentation fault".

Code: Select all
class ClientHandler : public CefClient,
                      ...,
                      public CefJSDialogHandler    // <-- I've added it at the end of the list
{
...
bool OnJSDialog(CefRefPtr<CefBrowser> browser,
                          const CefString& origin_url,
                          JSDialogType dialog_type,
                          const CefString& message_text,
                          const CefString& default_prompt_text,
                          CefRefPtr<CefJSDialogCallback> callback,
                          bool& suppress_message) OVERRIDE;

bool OnBeforeUnloadDialog(CefRefPtr<CefBrowser> browser,
                                    const CefString& message_text,
                                    bool is_reload,
                                    CefRefPtr<CefJSDialogCallback> callback) OVERRIDE;
}


I've tried to search the forum but couldn't find anything that would help me.

I also tried to create a custom Class that extends "CefJSDialogHandler" like described in this thread: https://magpcss.org/ceforum/viewtopic.php?f=14&t=13169&p=26551
but unfortunately I wasn't successful.

To clearify what I'm trying to do: I would like to suppress the default javascript prompt (and automatically return the same signal as if the user had clicked on "cancel" in the prompt) and instead show a custom notification inside the web application. Right now, when I try to close the window, I get the default prompt with the message "Is it OK to leave/reload this page?". If I click on "OK" the window will be closed right away, but if I on "Cancel" only the prompt closes and my custom notification will be shown instead. That is what I want but of course without the default prompt ever be shown.

What is the right way to implement "CefJSDialogHandler"?

Hopefully someone can point me in the right direction. :)

Thanks very much.
rkcef
Techie
 
Posts: 27
Joined: Fri Feb 26, 2021 9:11 am

Re: How to implement CefJSDialogHandler?

Postby rkcef » Thu Apr 22, 2021 9:43 am

rkcef wrote:Hello everyone,
I also tried to create a custom Class that extends "CefJSDialogHandler" like described in this thread: https://magpcss.org/ceforum/viewtopic.php?f=14&t=13169&p=26551
but unfortunately I wasn't successful.


I've tried again to implement a custom class that extends CefJSDialogHandler. Here's the header file (my_js_dialog_handler.h):

Code: Select all
#include "include/cef_jsdialog_handler.h"

namespace mynamespace
{
  class MyJsDialogHandler : public CefJSDialogHandler
  {
    private:
      IMPLEMENT_REFCOUNTING(MyJsDialogHandler);

    public:
      MyJsDialogHandler(void);

      bool OnJSDialog(CefRefPtr<CefBrowser> browser,
                      const CefString& origin_url,
                      JSDialogType dialog_type,
                      const CefString& message_text,
                      const CefString& default_prompt_text,
                      CefRefPtr<CefJSDialogCallback> callback,
                      bool& suppress_message) OVERRIDE;

      bool OnBeforeUnloadDialog(CefRefPtr<CefBrowser> browser,
                                const CefString& message_text,
                                bool is_reload,
                                CefRefPtr<CefJSDialogCallback> callback) OVERRIDE;
  };

} // namespace mynamespace


And here's the implementation file (my_js_dialog_handler.cpp):

Code: Select all
#include "my_js_dialog_handler.h"

#include "include/wrapper/cef_helpers.h"

namespace mynamespace
{
  MyJsDialogHandler::MyJsDialogHandler(void)
  {
  }

  bool MyJsDialogHandler::OnJSDialog(CefRefPtr<CefBrowser> browser,
                                    const CefString& origin_url,
                                    JSDialogType dialog_type,
                                    const CefString& message_text,
                                    const CefString& default_prompt_text,
                                    CefRefPtr<CefJSDialogCallback> callback,
                                    bool& suppress_message)
  {
    CEF_REQUIRE_UI_THREAD();

    suppress_message = true;
    callback->Continue(false, "");
    return false;
  }

  bool MyJsDialogHandler::OnBeforeUnloadDialog(CefRefPtr<CefBrowser> browser,
                                            const CefString& message_text,
                                            bool is_reload,
                                            CefRefPtr<CefJSDialogCallback> callback)
  {
    CEF_REQUIRE_UI_THREAD();

    callback->Continue(false, "");
    return true;
  }

} // namespace mynamespace


In the ClientHandler header file (cefclient\browser\client_handler.h) I've included the above mentioned header file (my_js_dialog_handler.h). In the "public" section of the class ClientHandler I've added the method definition to override GetJSDialogHandler. In the "private" section I've added a class member myJsDialogHandler to hold an instance of the custom class from above (MyJsDialogHandler).

Code: Select all
...
#include "../my_js_dialog_handler.h"
...
namespace client {

class ClientHandler : public CefClient,
                                ... {

  public:
    ...
    CefRefPtr<CefJSDialogHandler> GetJSDialogHandler() OVERRIDE;
    ...

  private:
    ...
    CefRefPtr<mynamespace::MyJsDialogHandler> myJsDialogHandler;
    ....

}
}


And here's the implementation part of the method GetJSDialogHandler in ClientHandler (cefclient\browser\client_handler.cc):

Create instance in constructor:
Code: Select all
ClientHandler::ClientHandler(...) : ... {
  ...
  // Initialize instance
  this->myJsDialogHandler = new mynamespace::MyJsDialogHandler();
  ..
}

Return CefJSDialogHandler instance:
Code: Select all
CefRefPtr<CefJSDialogHandler> ClientHandler::GetJSDialogHandler()
{
  return this->myJsDialogHandler;
}


I tried to debug this code with break points in Visual Studio 2019. I've discovered that the overriden method GetJSDialogHandler never gets called! Instead the original version of this method in the class CefClient (cef\include\cef_client.h) is called and only a nullpointer is returned. So my custom class MyJsDialogHandler never gets executed.

I don't understand why the overriden method is not called. Maybe I need to register/implement it somewhere else? In the whole code base of the cefclient example project, there's no other mentioning of GetJSDialogHandler or anything that could belong to it.

If it is not enough override GetJSDialogHandler in ClientHandler? What else is there to do?

It would be great if someone could help me out! :)
rkcef
Techie
 
Posts: 27
Joined: Fri Feb 26, 2021 9:11 am

Re: How to implement CefJSDialogHandler?

Postby magreenblatt » Thu Apr 22, 2021 10:10 am

Did you rebuild cefclient with your changes? Was the build successful? Are you running the new executable that you built?
magreenblatt
Site Admin
 
Posts: 12382
Joined: Fri May 29, 2009 6:57 pm

Re: How to implement CefJSDialogHandler?

Postby rkcef » Thu Apr 22, 2021 10:35 am

Hello magreenblatt,

thanks for your reply. Yes, I've rebuild the source code (in debug and release mode) and I'm sure that I tested it with the right executable (running it from inside Visual Studio 2019 in debug mode) as well as double clicking the release version and running it from the terminal.

The build was always successful. I was able to execute it as usual. The only thing not working is to execute the overriden method GetJSDialogHandler.

Is there anything in my source code that is wrong or that I've missed?

Thanks again for your help :)
rkcef
Techie
 
Posts: 27
Joined: Fri Feb 26, 2021 9:11 am

Re: How to implement CefJSDialogHandler?

Postby magreenblatt » Thu Apr 22, 2021 11:39 am

What you've posted above looks correct. Are you triggering the dialog using alert('test') or similar JS code?
magreenblatt
Site Admin
 
Posts: 12382
Joined: Fri May 29, 2009 6:57 pm

Re: How to implement CefJSDialogHandler?

Postby rkcef » Fri Apr 23, 2021 3:27 am

magreenblatt wrote:What you've posted above looks correct. Are you triggering the dialog using alert('test') or similar JS code?


Hello magreenblatt,

I've tested a bunch of stuff and finally found the issue.

My project is structured in such a way, that I've copied the directory from the example project "cefclient" to another location and used the copy as the basis for my own project. The issue was that the header files from the "cefclient" example project include other header files with the prefix path "tests/cefclient/browser/...". So, when I edited the header file "cefclient/browser/client_handler.h" in my own project directory, it was never included by the other header files because they still pointed to the original one inside the "libs/cef/.../tests/cefclient/browser/client_handler.h" directory. My project structure looks something like this:

  • my_root_project_dir/
    • src/
      • cefclient/browser/client_handler.h
      • my-project-code/
        • ...
    • libs/
      • cef/cef_binary_90.5.4+gc6a4331+chromium-90.0.4430.72_windows64/tests/cefclient/browser/client_handler.h

After changing all necessary references from "tests/cefclient/browser/..." to my own project's path, if finally works! :D

Thanks again for your help! :)
rkcef
Techie
 
Posts: 27
Joined: Fri Feb 26, 2021 9:11 am


Return to Support Forum

Who is online

Users browsing this forum: No registered users and 38 guests