Sep
16
2010

Flash detecting browser window close

Despite what the title of this article says, flash itself can't detect if the user closes browser. But with help of JavaScript onbeforeunload event and Flash externalInterface we can make it working.

 

I came across this problem when working on a flash application that requires users to save all changes to a database. Knowing life enough, it's not uncommon to work on something couple of hours and then accidently close a browser or open a new website in the same window without saving changes in application.

So what I wanted to achieve was preventing the user from closing a browser by showing a pop-up message saying that changes have to be saved and at the same time show a dialog in flash application to save his/her work.

Click on this link to see the example project: http://sierakowski.eu/examples/closeBrowser/. Tick or untick the checkbox to enable or disable popup message and then try to close tab or whole browser window or simply try to refresh the website to see it in action.

This can be done with a little help of JavaScript and onbeforeunload event. This event is fired before the browser unloads the document and provides a possibility to display a confirmation dialog, where the user can confirm whether he wants to stay or leave the current page. So I created an event handler in JavaScript that calls a flash function "askBeforeQuit" that returns true or false depending on whether the user's changes/work was saved or not.

Below is a JavaScript code that is to be placed in the head section of the standard HTML file that you get when publishing your flash project from Flash CS4.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
<script>
function getFlashMovie(movieName) 
{
   var isIE = navigator.appName.indexOf("Microsoft") != -1;   
   return (isIE) ? window[movieName] : document[movieName];  
}

window.onbeforeunload = function (evt)
{ 
   if(getFlashMovie("askBeforeQuitExample").askBeforeQuit("MSG from JS :)"))
   {
      var message = 'You didn\'t save your changes to database.
                     Do you really want to quit?'; 
      return message;
   }
}
</script>

 

The "getFlashMovie" function detects which browser the website is running on. Internet Explorer uses ActiveX control to play flash content with <object> tag while other browsers use Netscape plugin technology with <embed> tag. For that reason JavaScript "gets" to embedded flash object in different way - window.askBeforeQuitExample for IE and document.askBeforeQuitExample for others. The "askBeforeQuitExample" is basically the name of my example flash project and it has to be the same as "id" parameter in the <object> and "name" parameter in the <embed> tags.

The "onbeforeunload" function handler invokes Flash's askBeforeQuit function passing the string "MSG from JS :)". You may not need to pass anything to Flash as you basically may want to only check if window can be closed or not. Next flash function returns true or false, if it's true, a popup window will be generated with message "You didn't save your changes to database. Do you really want to quit?", if it's false browser will just close or change website.

Note that you can't actually define the look of this popup window. Internet Explorer and FireFox add they own message to yours and generate OK and Cancel button while Chrome displays only your message:

Chrome:

chromePopUp

FireFox:

FireFox Pop Up

InternetExplorer:

Internet Explorer PopUp

That's everything about JavaScript now let's look at the ActionScript code:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
var askBeforeQuitFlag:Boolean = true;
checkBox.addEventListener(MouseEvent.CLICK, enableDisableQuitting);
 
function enableDisableQuitting(e:MouseEvent):void
{
	askBeforeQuitFlag = checkBox.selected;
}
 
if (ExternalInterface.available)
{
	try
	{
		ExternalInterface.addCallback("askBeforeQuit", askBeforeQuit);
	}
	catch(error:Error)
	{
		textArea.appendText("Error: " + error);
	}
	catch(secError:SecurityError)
	{
		textArea.appendText("Security error: " + secError);
	}
}
else
{
	textArea.text = "ExternalInterface is not available";
}
 
function askBeforeQuit(msg:String):Boolean
{
	textArea.text = msg;
	return askBeforeQuitFlag;
}

 

CheckBox is my stage component to enable/disable close-browser popup and textArea is used to show message from JavaScript and/or to display possible runtime errors.

So first I check if ExternalInterface is available, in other words if flash is embedded in the correct HTML container (object and embed tags), rather that played as standalone projector (exe) or AIR. The addCallback's first parameter is a string that represents function name that will be called from JavaScript and the second one points to ActionScript function/method that will handle this JavaScrip request.

I'm doing this in try/catch to catch any errors that may occur and may be invisible to you as they will happen at the runtime. The error that most likely can be thrown is security sandbox error #2060. This will happen if you test this example locally from your machine rather than a web server. To overcome that, change "allowScriptAccess" parameter in both <object> and <embed> tags in your HTML file from "sameDomain" to "always".

The askBeforeQuit function returns true/false to JavaScript depending on status of my checkbox. Of course in more complex application it would be some flag indicating if changes have been synchronised with database or not. Also I'm displaying message from JavaScript in textArea component but you can invoke some Save dialog box or something like that.

 

Comments 

 
0 #6 Hosting Best 2011-05-25 16:15
Iv been wondering how sites have been doing this, started with Wordpress protecting you and now seems to moved onto crappy sales sites not wanting you to leave there sites. I reckon its going to turn into one of those things that is an annoyance that will get removed or software will be developed to stop it working.
Quote
 
 
+1 #5 sigman 2010-12-27 14:33
@Dani, for the example that is linked at the beginning of this article I just used standard Publish to HTML option of Flash CS4. But I also used the same JS code with swfobject and it worked without any problem.
This script may not work when tested locally. Try to upload your files to a webserver and test again. Also make sure JavaScript is not disabled in browser settings or by some third party plugin.
Quote
 
 
0 #4 dani 2010-12-22 03:08
Hi, thanks for this post it was very useful for me, but i have a question. This works me fine on Internet Explorer (using the default publish method of Flash Professional CS5) but it's not working on firefox and chrome. Trying to get to the root of the problem i realize that it was when connecting to the flash and i think it is due to the way the swf is embedded.

I tried with the "swfobject" javascript library and i get it working with IE and Firefox but not with Chrome. Noticing that your app works as expected with Chrome too, could you share the way that you add your object to the html page?

Thank you very much!!! And sry for my poor english!
Quote
 
 
0 #3 sigman 2010-11-29 09:36
@bigdaddy. Try first to see if JavaScript code works for you. Replace that line if(getFlashMovi e("askBeforeQuitEx ample").askBeforeQuit("MSG from JS :)")) with just if(1). This will make JS showing this message without checking with Flash. If that works than you know that there is something with communication with Flash. Make sure that you put correct Flash ID in this JS call: getFlashMovie("askBeforeQuitEx ample").
Quote
 
 
0 #2 bigdaddy 2010-11-29 03:49
i already try this script but not work in me... there is no notification in me while i close the browser... can you help me???
Quote
 
 
0 #1 dj 2010-11-16 22:52
Thanks for posting this!
Quote
 

AS3 Tips

Follow me on Twitter