javascriptactionscript-3externalinterface

Requiring confirmation from user before browser close _iff_ a Flex variable is true


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 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


Solution

  • 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.