views:

672

answers:

2

Hi All,

I have a Flex application which allows the user to edit a cloud-based document. (Think SlideRocket.) When the user tries to navigate away or close the browser window, I'd like to show them an are-you-sure dialog iff they have unsaved changes.

I'm using the following custom class, which I found at http://stackoverflow.com/questions/1119554/flash-player-notified-on-browser-close-or-change-page-as3. I don't think it is the problem.

package
{
    import flash.external.ExternalInterface;

    public class ExternalInterfaceUtil
    {
        public static function addExternalEventListener(qualifiedEventName:String, callback:Function, callBackAlias:String):void
        {
                // 1. Expose the callback function via the callBackAlias
                ExternalInterface.addCallback( callBackAlias, callback );

                // 2. Build javascript to execute
                var jsExecuteCallBack:String = "document.getElementsByName('"+ExternalInterface.objectID+"')[0]."+callBackAlias+"()";
                var jsBindEvent:String = "function(){"+qualifiedEventName+"= function(){"+jsExecuteCallBack+"};}";

                // 3. Execute the composed javascript to perform the binding of the external event to the specified callBack function
                ExternalInterface.call(jsBindEvent);
        }
    }
}

In my applicationComplete function, I add an event listener to the javascript window.onbeforeunload event, as follows:

ExternalInterfaceUtil.addExternalEventListener("window.onbeforeunload", requestUnloadConfirmation, "unloadConfirmation");

The Actionscript function requestUnloadConfirmation (below) is successfully called when the user tries to close the browser window. However, it does not prevent the browser from closing. (In Chrome, the browser closes and the Actionscript function is called subsequently. In Firefox, the browser stays open for the duration of the function but then closes.)

private function requestUnloadConfirmation():String {
    if (changedSinceSave)
        return "There are unsaved changes. Are you sure you want to leave without saving?";
    else
        return null;
}

Behavior is identical in both debug and release builds, and on the production server as well as the local machine.

Any help would be greatly appreciated,

Dave

A: 

In a regular html/javascript web-app you would use the window.onbeforeunload event to do this.

http://www.4guysfromrolla.com/demos/OnBeforeUnloadDemo1.htm

Perhaps you can use this event, and check some value of your flex app to determine if you should ask the user (not familiar with flex...)?

einarq
+1  A: 

Right now, when the JavaScript event is fired, it is set to call your function in your AS3 code, which it does. The JavaScript function, however, is not returning the value that your AS3 function returns. To get this behaviour, add 'return' to the JavaScript event-handling function created in addExternalEventListener like so:

var jsBindEvent:String = "function(){"+qualifiedEventName+"= function(){return "+jsExecuteCallBack+"};}";

Since the event handler should return a true or false value, your requestUnloadConfirmation function should have a return type of Boolean and return false to cancel the event, and true otherwise. Use the following to get a confirmation dialog box:

private function requestUnloadConfirmation():Boolean {          
    if (changedSinceSave)          
        return ExternalInterface.call("confirm", "There are unsaved changes. Are you sure you want to leave without saving?");
    else          
        return false;          
}

UPDATE: It turns out that returning a string to window.onbeforeunload causes a confirmation dialog box to be shown automatically. The ExternalInterface.call to confirm causes a second dialog box to show; it is redundant. The only change required in the AS3 code is to add the "return" in the generated JavaScript.

Cameron
Adding return to the event-handling function did the trick. Thanks a million for saving the day!For those of you reading this in the future: The proposed change to requestUnloadConfirmation was not required - and, in fact, leads to two confirmation dialogs being shown in succession rather than just the one. This is because returning a string value to window.onbeforeunload causes a confirmation dialog to be shown. You do not need to explicitly request another one.Tested as working in Chrome, Firefox, Safari. I assume it works in IE as Microsoft invented window.onbeforeunload in IE4.
Dave T
Oh, cool! I did not know about the automatic confirmation when returning a string in windows.onbeforeunload. I've only played around with that event once, for fun. I'll edit my answer.
Cameron