views:

727

answers:

2

Short version:

Is it easy/feasible/possible to program modal window in Flash (AS3)? Is there a built-in functionality for it?

Long version:

I’m working on a Flash widget (in AS3), and I would like to be able to show a movie clip in a modal fashion. Essentially, I need a simple modal window inside the wieget. So far I learned that that I need to implement the "modalness" by myself (in AS3). There used to be something in previous versions of Flash and there is something in Flex, but I have not experience with Flax and I’m not sure what it involves.

I proceeded to write it myself without any deep planning upfront and soon and hit some problems. It seems that the root of the problems is that I cannot keep a focus on a movie clip (or an InteractiveObject to be precise). I handle both KEY_FOCUS_CHANGE and MOUSE_FOCUS_CHANGE events while trying to prevent losing focus FocusEvent.preventDefault(). But I still manage to lose the focus by mouse clicking. What’s even weirder is that when I force the focus using the Stage.focus property, I get an ugly looking thick yellow line around my movie clip. In presumably indicates that the movie clips is focused, but normally it’s not anywhere. Does it mean that the object is not focusable, but I somehow force focus it anyway?

I realize that the questions above are not very clear and I don’t expect to actually answer them. But what I’m trying to indicate is that it seems that I’m doing something wrong. So the main question is that: Is there an easy way to get a modal behaviour in Flash? I think programming it from scratch and piping and handling variously little events is something I should not be doing.

The fact that is irritating me the most is that I need this modal widow to handle and display some edge case error messages. And so putting so much effort into it does not seem right. Maybe, there is a completely different way.

I’m aware of the fact that the this question is not perhaps supported by enough research, but I started working on something which I thought would take me half an hour and it has already been several hours. I may do more systematic research and post more concrete questions later.

+1  A: 

Here is a decent alert window implementation that should get you started.

Joel Hooks
Thank you for the link. I think I was able to get that far. I just tested the alert component from the link, and found out that it has the same problem: it does capture keyboard event. This is one of my main problems. I would like to prevent users to generate more keyboard events when the modal window is up (without manually unhooking them and re-attaching them later).
Jan Zich
You are going to have to capture the keyboard events and if( isModal) {preventDefault(); stopImmediatePropagation();} - or something to that affect.
Joel Hooks
I may have a number of independent elements in the stage and each can be hooked up to some keyboard events. I want to be able to steal focus and capture all keyboard events by the alert and stop the propagation there (instead of checking it in each individual key event handler). But it’s turning out that there is no elegant way to do that.
Jan Zich
Your modal should be able to listen for keyboard events at the stage level (global).
Joel Hooks
A: 

After some more experiments and investigations, I think I found a decently clean solution. Most of it is based on the example in the official documentation of the FocusEvent event. In what follows is a simplified version of the implantation.

package
{

    import flash.events.Event;
    import flash.events.MouseEvent;
    import flash.events.FocusEvent;
    import flash.display.Sprite;
    import flash.display.Stage;

    public class Message
    {

        private static var overlay : Sprite;
        private static var dialog : Sprite;

        public static function show(stage : Stage, message : String)
        {

            // Close existing (if any).
            close();

            // Create dialog. They overlay sprite overlays the entire scene.
            overlay = createOverlay();
            dialog = createDialog(message);
            overlay.addChild(dialog);
            stage.addChild(overlay);

            // steal focus
            stage.focus = overlay;

            // Make sure the ugly yellow focus rectangle is hidden. Hiding it seems
            // to have one additional benefit. If we don’t do it, one can still 
            // change the focus using left and right arrow keys. The focus rectangle
            // actually moves to another element in the scene (first time I saw
            // something like this in Flash). If we hide it, the left and right arrow
            // keys actually don’t do anything. I did not find any documentation
            // related to this. So it may change in future. But if it changes,
            // possible workaround could be to simply catch the keyboard events
            // and prevent propagation. Such approach is also used in the official
            // AS3 documentation of the FocusEvent class:
            // 
            //   http://livedocs.adobe.com/
            //       flash/9.0/ActionScriptLangRefV3/flash/events/FocusEvent.html
            //
            stage.stageFocusRect = false;

            // Even though the message overlays the entire stage, if you click
            // on it, it loses focus. My guess is that Flash does not find
            // anything obvious which can be focused (such as a textbox). The
            // following below forces Flash to keep the focus on the message.
            // This approach is also used in an example in the AS3 documentation,
            // of the of the FocusEvent class (see the link above) so it gives it
            // some credibility.
            overlay.addEventListener(MouseEvent.CLICK,
                function(event : MouseEvent) : void { stage.focus = overlay; });

            // In addition, when the entire Flash loses focus and it gets it later 
            // back, the container (browser) does not restore the previously focused
            // element. So we have to do it ourselves.
            stage.addEventListener(Event.ACTIVATE,
                function(event : Event) : void { stage.focus = overlay; });

            // And apparently, swallow all keyboard events.
            overlay.addEventListener(KeyboardEvent.KEY_DOWN,
                function(event : KeyboardEvent) : void { event.stopPropagation(); });

        }

        public static function close() : void
        {
            // snip ...
        }

        private static function createOverlay() : Sprite
        {
            // snip ...
        }

        private static function createDialog(message : String) : Sprite
        {
            // snip ...
        }

    }

}
Jan Zich