Detecting the exit button click in a browser dialog's JavaScript

Does anyone remember how to detect the exit button click in a browser dialog’s JavaScript ?

window.onclose

… does not seem to fire on MSIE WebBrowser Control under SU2016.

maybe…

window.onbeforeunload
window.onunload

Just tried window.onbeforeunload and document.onbeforeunload … but neither work.

It also needs to be a cancellable event so onunload is not appropriate.

Some more idea…

Thank you, but I’ve been through all this web searching search already, and read the various stack overflow ideas.

ADD: I’m asking if a SketchUp developer knows what the solution is (if there is one.)

The #set_can_close method is used to attach a block that is executed just before closing, this block has to return a boolean, if the block returns false the close will be canceled.

(1) That is for UI::HtmlDialog on SU2017 +, … but as I said in the initial post …
I need something that works on SU2016 in a UI::WebDialog window.

(2) I need something that fires INSIDE the dialog because the blocks for state change methods have never fired on the Mac, (if I remember correctly.) So I do not believe there is a Ruby-side solution unless I abandon the idea of supporting SU2016 on the Mac.

(3) It is not the generic state of closing or having been closed that I need to trap.
I need to know if the user closed the dialog by clicking the red X button in the titlebar of the window specificially.

And I did check Thomas’ Sketchup WebDialogs - The Lost Manual … but it has no mention of this challenge.

Sorry, I’m afraid my knowledge is limited here… I hope you will get a solution.
However I still did some test to learn… (W7, SU2014Pro, ie11)

This one is giving the alert in SU:

window.onunload = function () {
  alert('mes');
};

Interestingly this one working if you open and try to close the html in IE, but doing nothing in SU:

window.onbeforeunload = function (foo) {
  mes = "Are you sure ?";
  foo.returnValue = mes;
  return mes;
};

Neither of those are firing for me in SU2016 web dialog w/ document mode set to IE11 (or IE9.)

I gave up on the JavaScript close / beforeunload / unload event trapping.

WebDialogs: The Lost Manual > JavaScript events and functions > window.close says:

This works in Safari, but not in Internet Explorer.

So, I suppose if the method does not work, we cannot expect the event of the same name to either.
(Note this manual refers to dialogs in browser frames embedded in a SketchUp process, not to a standalone browser instance.)


This is the Ruby-side solution I am using …

I have a result variable (@result) that is set to 0 initially before the dialog is created.

If the user acts normally, and either uses the ESC or ENTER keys, or clicks on of the dialog’s buttons, the "clicked" dialog’s callback fires setting the @result variable to a button integer code (can be -1 or > 1.)

The "clicked" callback will close the dialog after setting @closed_by_callback to true and @result to the button code, … then do cleanup work.

If the dialog window is closed by the X button, then @closed_by_callback will still be false and @result will still be 0, so I’ll use a Ruby-side closure handler block …

@window.set_on_close {
  if !@closed_by_callback && @result == 0
    # User must have clicked the X button, therefore ...
    @result = IDCANCEL # which is 2
    # This block gets called TWICE by SketchUp because of a bug,
    #   so prevent tasks from executing more than once ...
    @closed_by_callback = true
    # Do other cleanup tasks that the normal callbacks do
    #   when the user clicks a button or presses ESC key.
  end
}

This will allow my code to proceed as if the Cancel button was clicked, or the ESC key was pressed. This is important as the code calling the dialog creation method needs to react to the result.


The following was disproved by Steve and Gordon (below) …

IF … it turns out that the UI::WebDialog # set_on_close() block is not being called on the Mac for SketchUp 2016 specifically, then I just will not support Mac for v 16. (Simple as this.)

@slbaumgartner Do you know (or remember) if SU2016 on Mac will call the set_on_close block when the dialog window is closing ?

Alas I migrated SketchUp 2016 onto an external drive that I didn’t bring with me. But looking at the plugins in the 2016 folder (which needs to stay under my home folder else SketchUp gets confused) I find a lot of them that set that callback and I don’t remember having issues I’d connect with the callback not happening.

1 Like

I just did a quick test on SketchUp 2016 for Mac and set_on_close() seems to work fine. It also works on 2017 and 2018. I’ve never actually used it before as my web dialogs did not require any action when the window was closed. My cancel button callback just closes the webDialog.

The example from the API docs worked fine:

dialog.set_on_close{ UI.messagebox("Closing the webDialog") }
1 Like

In this situation I’d recommend that every ‘change’ to any input box etc, saves that new data via a callback to the Ruby side - as being ‘unconfirmed’…

Then clicking a ‘confirm’ button passes the new data via a callback to the Ruby side - as being ‘confirmed’.

If the [Web] dialog closes - either by the user clicking a ‘close’ button, or the window’s close red-button, then the Ruby side already has all of the relevant data - both confirmed and unconfirmed.
It has an ‘on_close’ block…
The confirmed data is used, and is unquestioned.
The unconfirmed data is only noted if it mismatches the equivalent confirmed data.
If it differs, then you could either ignore it, or accept it, or perhaps [on the Ruby side] ask the user if the changed-but-unconfirmed data is to be discarded or accepted - so even though they haven’t ‘confirmed’ it they could ‘recover’ it…

2 Likes

Thank you for checking …

Oh good! Thank you for testing this. This is a relief. (Last I knew the #show and #show_modal method blocks were not getting called on the Mac for the old UI::WebDialog class, so I was afraid of the #set_on_close as well.)

Yes, no worries there as they’ll be using the new chromium based UI::HtmlDialog class.)

As does mine, … but only if the user uses the cancel button given, or the ESC key set to also call the callback. You’ll run into the same situation someday, when your code needs to know that the dialog was canceled in order to make a decision about how to proceed.

So, when the user dismisses the dialog window via the button nothing happened, … since the “cancel” callback does partly the same thing that the “clicked” callback does, ie, if the calling code (that called the dialog creation method,) had passed in a block to perform asynchronously (expecting whatever result as a block parameter, even code 2,) … that external callback block never got called before I solved it (above) using #set_on_close when the user bypassed the button / keycode callbacks.

Does not exactly apply here. You assume I am asking with regard to an inputbox. I am actually not asking specifically about that, and was trying to solve this for a custom class of messagebox. I have several different kinds of dialogs, of which inputbox type is only one. Yes I do have several inputbox instances, but they are none of them critical data. Simple forms for search, login, plugin options, etc.

I’m not really interested in complicating the workflow. If a user dismisses a dialog window, I take that as a cancel. It is how I myself and everyone else I’ve watch deals with dialogs. They mean to dismiss the task when they just click that “lil’ red x”.

Even so, TIG, your advice does not solve the question of this thread, which would still present a problem, as the code still must know that the dialog has closed (via the button) in order to do this suggested comparison between previous defaults and unconfirmed changes.

I could see the relevance however if this was about large forms for data entry, but it is more generic that this. The solution will be implemented to all the types of dialogs, most of which have no input type controls at all. (But I’ll give a “like” for your effort anyway.)

window.onunload and window.onbeforeunload events fire in the dialog, but it is not a cancellable event. The dialog will then close.

I could not trap them myself.

onunload is not, but onbeforeunload is according to docs.

But again, I had no luck trapping either one.


ADD: @dezmo also partly confirmed this above …

Why do you consider a user’s action of clicking the Close button in the titlebar to be different from pressing ESC or a in-dialog Cancel button?

My “Lost Manual” never touched upon that because I had the need to detect the difference.

Ah, so you want to prompt the user before the dialog is closed?

Who are you asking this question of ?
I certainly do not and explicitly said the opposite, (if it was I you are asking.)

For reference from my statements above …

In fact that is the whole problem here (ie, the reason for this thread,) … when the user clicks the red X button, it bypasses any JS onkey event handlers and all the button callbacks to Ruby.

Huh ? “didn’t have the need” ? “never had the need” ?

And again what is this “difference” you are stressing ? Who said anything about a difference ! Not I.

The problem is not “difference”,… the problem is the red X SILENTLY closes the window.

NO !

(I would have said so if that were the case. I wish y’all would just answer the questions posed, instead of jumping to incorrect assumptions !)

Let me see if I can explain it …

IF (big IF because it failed in practice,) I was able to trap the red X causing the JS beforeunload event, THEN I could cancel it (because it is supposed to be cancellable) and INSTEAD call my dialog instance’s cancel callback, which does tasks needed, and THEN closes the window, and THEN does other needed stuff.

The whole point is that I need the red X button on the title bar, to do the SAME thing that the ESC key does (calls my “cancel” callback,) and that the cancel button does (calls my “cancel” callback,) … which is the thing that actually closes the window from the Ruby-side.

Trying to detect the red X button on the JS-side failed ! Despite desmo saying unload was trappable, it fails for me. Despite @Nick_G saying both fire in a dialog, both fail for me !


I said above that I had solved it, Did you miss this ? (I’ll give myself a solution.)

I’ve moved on to other challenges.