You’ll be familiar with FocusManager and how it manages focus around text input controls, right? Well, once again, the browsers have hit back…
It seems, at least in Internet Explorer 7, that if you hit tab on a text box, it will allow Flex to process the keydown, but then it will merrily move focus off the Flash Player altogether. In other words IE captures the tab key to move around its own controls. If your Flex app has forms made up of text boxes, that’s something you really don’t want.
The only way I’ve found to get around this is a JavaScript hack in the wrapper HTML. It basically sets up a listener for keyboard events and passes the tab key down to the Flash Player.
In addition, if your Flex app starts up showing a text box (e.g. a login form) then that won’t get focus. The reason for this is that Flash Player itself doesn’t automatically get focus. If you click anywhere on the Flex App, you’ll find that the first textbox gets focus as you might expect.
This little hack fixes both these issues in Internet Explorer. I tried these fixes in Firefox as well, but although it fixes the issue with tabbing around forms, I just could not make Firefox give Flash Player the focus on startup.
In the wrapper HTML, I’ve added some extra JavaScript – setupKeyListener() is executed on load, and it sets up the listener, and then tries to set focus to the Flash Player. Note that I’ve named the object mainApp – this has to match the id field passed to the AC_FL_RunContent() function, or the id of the <object> tag.
<script language="Javascript" type="text/javascript"> function setupKeyListener() { // Add the event handler detectEvent on the keydown event document.onkeydown = detectEvent; if (isIE) { // force the focus var flashPlayer = document.mainApp || window.mainApp; flashPlayer.focus(); } else { // For Firefox, it's just not worth bothering...it won't work. } } // this is the detectEvent event handler function detectEvent(e) { var evt = e || window.event; // check for the TAB key if (evt.keyCode == 9) { // call the actionscript function to pass it the SHIFT key pressed mainApp.handleExternalTabKey(evt.shiftKey); // prevent the browser the default actions for the key pressing return false; } else { return true; } } </script> <body scroll="no" onload="setupKeyListener()"> ...etc
In your main application class, you’ll need to export the handleExternalTabKey() function something like this:
private function onCreationComplete(event:FlexEvent):void { ...stuff... ExternalInterface.addCallback("handleExternalTabKey", handleExternalTabKey); } private function handleExternalTabKey(name:String):void { if (name == "false") { // only the TAB key has been pressed focusManager.getNextFocusManagerComponent().setFocus(); } else { // the combination of SHIFT+TAB has been pressed focusManager.getNextFocusManagerComponent(true).setFocus(); } }
Update
In response to Daniel’s comment below, I had another look at the issue with setting focus to the Flex app at startup in Firefox. I’m happy to say that I found a solution that seems to work at least on our app. Here’s the new version of setupKeyListener()…
function setupKeyListener() { // Add the event handler detectEvent on the keydown event document.onkeydown = detectEvent; setTimeout('mainApp.focus()', 100); }
It seems that in IE you can go right ahead and set focus to the Flash instance and it works fine. But it occurred to me that in Firefox the Flash instance might not have loaded fully at the point I called focus(). So just for a lark I put the focus() call on the end of a timer, and it seems to work. I’ve just got an arbitrary value of 100ms in the code above. I guess it could be anything because all I’ve really done is allow control to return from the setupKeyListener() function so that Firefox can finish whatever it’s doing and then call the focus() at some later time. Incidentally, the code above now seems to work for IE and Firefox.
Hopefully this is some use (particularly to Daniel) and I’m certainly going to add this fix to a bunch of our apps.
Thanks to Daniel for prompting me to have another look at this…
5 Comments
23 March 2009 at 7:40 am
you write “I tried these fixes in Firefox as well, but although it fixes the issue with tabbing around forms, I just could not make Firefox give Flash Player the focus on startup”
were you able to find a sln to this?
23 March 2009 at 10:22 am
Hi Daniel,
In response to your comment I had another look at the Firefox thing. It must have been the fact that I was taking a totally fresh look at this problem as I tried something different and it seemed to work. I’ve updated the post with my solution.
Thanks for commenting.
26 March 2009 at 10:28 am
I have a minor question regarding this very good solution.
Since we are adding a javascript into the HTML wrapper, is it not possible that the browser does not executes the javascript depending upon the browser settings.
26 March 2009 at 12:10 pm
Hi Dan,
Yes I think most, if not all, browsers can be set to ignore any javascript. However, if someone did actually do this, I suspect that most of the websites on the planet would not run properly because they would need at least some javascript to provide the functionality. So I don’t believe it would reasonable for a user of your website to switch off javascript and expect either yours or anybody else’s web apps to run. For that reason, we just take it for granted that the javascript will run.
I hope that answers your question…..
Cheers,
Ed.
19 October 2009 at 9:42 pm
Thank you for a very helpful post. In my testing I came up with a variation that may be a bit easier to maintain, as it embeds the JavaScript code in the Flex app so there is no need to modify index.template.html.
I added the following to my application tag:
creationComplete=”ExternalInterface.call(‘function(){window.document.’+this.id+’.focus();}’)”
By having Flex call the JavaScript once the application finishes loading, there is no need for a timer delay. It worked for me in both IE and Firefox.