RE: Proposal: Detecting when the user leaves a page due to hitting the back button or typing in a URL or going to a favorite

Thank you for your comments.  I agree with your objection concerning
loss of browsing history.  One other objection I had was that it still
would not be possible to recreate the typical desktop application
behavior of asking the user if they wish to save changes/cancel when
closing the application (providing a YES/NO/CANCEL dialog whereby YES
saves the changes and exits, NO does not save the changes and exits, and
CANCEL cancels the exit).

I would like to submit a revised proposal that addresses these 2
objections, and a few additional objections that are best illustrated
with 4 brief web page examples.


EXAMPLE #1
------------ 
In this example, tested with Internet Explorer 7, the page has the name
'test.htm'.  One may test it by saving it to disk and opening it in a
browser.  This page will block all navigation by redirecting the browser
to itself in the unload event handler.  IE 7 however, allows the user to
close the page.  Effectively, the user has lost their browsing history.
 
<html>
<head>
<script>
function exitPageCheck()
{
  window.location = 'test.htm';
}
</script>
</head>
<body onunload='exitPageCheck()'>
Test
</body>
</html>


EXAMPLE #2
------------ 
In this second example, I added an alert() before the redirect.  The
alert displays when the user closes the page.  This shows that the
unload event handler is fired when the user closes the page, but in
spite of the redirect, the browser closes the page.  

<html>
<head>
<script>
function exitPageCheck()
{
  alert('blocking');

  window.location = 'test.htm';
}
</script>
</head>
<body onunload='exitPageCheck()'>
Test
</body>
</html>


EXAMPLE #3
------------
In this example, the code displays a confirm dialog prior to the
redirect rather than an alert.  When the user closes the page, the tab
is given an orange color, focus switches to a different tab, but
tab/page does not close yet.  If the user clicks on the orange tab, they
will see the confirm dialog, however, hitting cancel does not stop the
page from finally closing (at which point the tab will disappear).
<html>
<head>
<script>
function exitPageCheck()
{
  var answer = confirm('There are unsaved changes, are you sure you wish
to leave?');

  if (answer)
    return;

  window.location = 'test.htm';
}
</script>
</head>
<body onunload='exitPageCheck()'>
Test
</body>
</html>


EXAMPLE #4
------------
In this last example, the code display 10,000 confirm dialogs in the
unload event handler.  When the user closes the page, IE changes the tab
color to orange and gives focus to 
a different tab, however, if the user clicks on the orange tab
(returning focus to the malicious page), IE becomes modal and the user
cannot do anything with IE (such as giving focus to another tab) until
going through 10000 confirm dialogs (effectively the browser is
crashed).

<html>
<head>
<script>
function exitPageCheck()
{
  for (var i = 0; i < 10000; ++i)
    var answer = confirm('There are unsaved changes, are you sure you
wish to leave?');

  if (answer)
    return;

  window.location = 'test.htm';
}
</script>
</head>
<body onunload='exitPageCheck()'>
Hello
</body>
</html>


Revised proposal follows that addresses all these issues.  This
obsoletes & replaces the previous proposal.

1. Allow the unload event to be cancellable from script.  This will
allow web designers to recreate the modal flavor of desktop apps like MS
Excel that prompt with "Yes/No Cancel" when there are unsaved changes.
As to how the cancel is accomplished, this could be a method of the
event object such as .cancel(), with another method such as
.isCanceled() to address situations where that are multiple event
listeners registered, and a previous one has already canceled the unload
event.  For example, suppose there are 2 unload event listeners.  The
2nd event listener to be called would not want to display another
confirm dialog to the user, if the first event handler had already done
so and canceled the unload.

2. In the unload event, distinguish between closes and navigating away,
by adding a property to the event object such as getUnloadType() which
returns an enumerated type with one of these values:
  WINDOW_IS_CLOSING = 1
  WINDOW_IS_NAVIGATING_TO_NEW_PAGE = 2
(Since javascript doesn't have an enumerated type that I am aware of,
this could be an integer, or even two separate methods like
.isClosing()and .isNavigatingAway() which return booleans).

It may be helpful to know for WINDOW_IS_NAVIGATING_TO_NEW_PAGE events
what the new URL is, however, this may violate security, and I can't
think of a benefit to knowing that information at the moment, so it may
be best to not provide that information.

3. Warn user with information style bar (similar to what IE already uses
when it blocks a file download) if page cancels unload event (it will
disappears after a few seconds without user interaction to avoid
annoying the user with having to close it).  The text in the bar might
be (for page closures):
  "This page has blocked closure.  Click here to override." 
Or
  "This page is blocked navigation to the new url.  Click here to
override." For navigating away.

  If the bar is clicked on, then a popup-like window (hereafter referred
to as the OVERRIDE CONTROL will overlay the page and show navigation
history in a list, allowing the user to override the script and
forcefully navigate to a page in history.  In addition the OVERRIDE
CONTROL will have an edit box for typing in a new URL and a means to go
to a bookmark.  The implementation details could be made more specific
or done differently, I just suggest an implementation design to
illustrate.

4.  The OVERRIDE CONTROL will be available to the user at any time
(maybe as a button near the back/forward buttons, not just when an
unload event is blocked by script.  This will address the 10000 confirm
dialog problem given as an example above.

5.  If the OVERRIDE CONTROL is used, the page will not receive any
further events or have the opportunity to run any more script.  This is
not such a problem for benevolent developers, who have to design for
electric power failures anyways.

6. In a tabbed browser, do NOT allow a modal state to affect the other
windows.  In the 10000 confirm dialog problem mentioned above, the
browser entered a modal state and did not allow the user to go to any of
the other tabs.

Andrew Shropshire
-----Original Message-----
From: Boris Zbarsky [mailto:bzbarsky@MIT.EDU] 
Sent: Friday, January 02, 2009 3:13 PM
To: Shropshire, Andrew A
Cc: public-webapps@w3.org
Subject: Re: Proposal: Detecting when the user leaves a page due to
hitting the back button or typing in a URL or going to a favorite

Shropshire, Andrew A wrote:
> 4)    Should a web page designer cancel all navigations away from the 
> page just to be malicious, the user can still close the page (since 
> closing the page does not fire the onNavigateToNewPage event).

That loses the user's navigation history in that window, so doesn't seem

acceptable to me, as a user.

In fact, preventing backwards navigation in history, to before the 
malicious site was entered, if nothing else, is also not acceptable.

-Boris

Received on Monday, 5 January 2009 12:30:55 UTC