Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do I detect a click in TChromium?

I have a TChromium control in my Delphi application, and on the page I display, there's a link that minimizes the application. Currently, I detect when the user clicks that link by detecting the address change:

procedure TForm1.Chromium1AddressChange(Sender: TObject;const browser: ICefBrowser; const frame: ICefFrame; const url: ustring);
begin
if (url = 'file:///data/exiting.exit') then
Form1.Close;

if (url = 'file:///data/minimize.min') then
Application.Minimize;

end;

However, the side effect is that the browser's URL is changed, which I don't want. How can I detect when the user clicks the link without the URL changing?

like image 861
LeeAttila Avatar asked Oct 02 '22 13:10

LeeAttila


1 Answers

If I get your problem right, you're having a link like this in your HTML document:

<a href="minimize.min">Minimize</a>

And you want to do something in your application when this link is clicked, but you don't want to navigate to that link, since it's just a fake link used only to recognize the action. Well, the OnAddressChange is a wrong event to handle since it's being fired by the display handler when a frame's address has changed. So, it is too late to cancel the navigation to that fake site from there. In DCEF 1 you could write a handler for the OnBeforeBrowse, but even that would not be "so clean" solution, because you'd have to parse the URL to which the frame navigates.

The proper way is to leave the fake site navigation and utilize DOM event listener. Then it doesn't matter what element nor event you use for your interaction. Let's have this minimalistic HTML document:

<html>
  <body>
     <a id="minimize" href="">Minimize</a>
  </body>
</html>

As you can notice, it navigates to nowhere, but it will still be rendered as a link. It also has its own unique id identifier needed for DOM explore identification. Now let's add the listener for the click event for our minimize element. This binding is done as soon as the frame is loaded, which is reported by firing the OnLoadEnd event. There we will explore the DOM tree, find our minimize element and attach the click event listener to it:

unit Unit1;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, cefvcl, ceflib;

type
  TForm1 = class(TForm)
    Chromium1: TChromium;
    procedure FormCreate(Sender: TObject);
    procedure Chromium1LoadEnd(Sender: TObject; const browser: ICefBrowser;
      const frame: ICefFrame; httpStatusCode: Integer; out Result: Boolean);
  private
    { Private declarations }
  public
    { Public declarations }
  end;

var
  Form1: TForm1;

implementation

{$R *.dfm}

procedure TForm1.FormCreate(Sender: TObject);
begin
  Chromium1.Load('C:\File.html');
end;

procedure MinimizeClickEvent(const AEvent: ICefDomEvent);
begin
  ShowMessage('Here the application can be minimized.');
end;

procedure OnExploreDOM(const ADocument: ICefDomDocument);
var
  DOMNode: ICefDomNode;
begin
  // here we attempt to find our "minimize" element
  DOMNode := ADocument.GetElementById('minimize');
  // and if we find it, we attach to its click event our MinimizeClickEvent
  // procedure so whenever the element will be clicked, that procedure will
  // execute
  if Assigned(DOMNode) then
    DOMNode.AddEventListenerProc('click', True, MinimizeClickEvent);
end;

procedure TForm1.Chromium1LoadEnd(Sender: TObject; const browser: ICefBrowser;
  const frame: ICefFrame; httpStatusCode: Integer; out Result: Boolean);
begin
  if Assigned(frame) then
    frame.VisitDomProc(OnExploreDOM);
end;

end.

With small changes in the code or a HTML document you can listen to any event or element you choose, so you can have e.g. a button on your site:

<html>
  <body>
     <button id="minimize" type="button">Minimize</button>
  </body>
</html>

Of course, you can attach event listeners for as much elements as you want.

like image 188
TLama Avatar answered Oct 05 '22 11:10

TLama