5

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?

Rob Kennedy
  • 161,384
  • 21
  • 275
  • 467
LeeAttila
  • 75
  • 1
  • 6
  • I don't understand. You can call `Application.Minimize` at any time. You don't need to wait until someone types a magic URL into the address bar. What's your real question? – Rob Kennedy Feb 21 '14 at 05:29
  • Application.Minimize call when someone press on the Minimize button in html document.Minimize button - . When I press on this button,my app minimize and url changes to file:///data/minimize.min. – LeeAttila Feb 21 '14 at 05:36
  • I see. You asked how to minimize the program, but that's not really what you want to know; you already know how to do that. What you really want is a less destructive way to detect click events in the browser control. I've edited your question accordingly. – Rob Kennedy Feb 21 '14 at 05:55
  • Sure, thank you! Sorry for my English! – LeeAttila Feb 21 '14 at 06:01

1 Answers1

4

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.

TLama
  • 75,147
  • 17
  • 214
  • 392
  • OnExploreDOM not executing.I check it through put ShowMessage('OnExploreDOM') after DOMNode := Document.GetElementById('minimize'); – LeeAttila Feb 22 '14 at 05:52
  • The problem is most probably in the version of DCEF you are using. I remember that a few of them (more recent versions) had a bug when the DOM couldn't be explored at all. That's a [`known issue`](http://stackoverflow.com/q/15598776/960757). The only solution to use this technique was to use a different version (older versions of DCEF1 had this working, or maybe now (it that was fixed) on the new platform based [`DCEF 3`](https://code.google.com/p/dcef3/)). – TLama Feb 22 '14 at 11:46
  • I use Delphi 7 and CEF3 – LeeAttila Feb 22 '14 at 12:09
  • @TLama Is it possible to click `ICefDomNode` ? We can edit the value and attributes but can we click? – user3060326 May 16 '14 at 15:56
  • @user3060326, the same answer as before; I don't think so, but I can't tell you that for sure... Sorry. – TLama May 16 '14 at 16:01
  • @Downvoter, if this solution didn't work for you, it is possible that you are using DCEF version where DOM visiting is completely broken. That's a known issue. – TLama Mar 28 '15 at 12:51
  • 3
    @TLama: this answer doesn't work with dcef3 (AddEventListenerProc doesn't exist anymore in dcef3). Is there a solution for dcef3? Thanks – boggy Apr 23 '16 at 08:40
  • @costa Confirmed in the latest build. Still missing. – Jerry Dodge May 19 '17 at 03:25
  • Actually, I just figured it out: http://stackoverflow.com/a/44061210/988445 – Jerry Dodge May 19 '17 at 04:01