views:

2091

answers:

4

Note: A possible solution needs only work in Firefox 3.0, my app doesn't allow access from IE! =)

I have a link that, when clicked, will display a lightbox to the user:

<a href="#" onclick="show_lightbox();return false;">show lightbox</a>

My problem is that when the lightbox is displayed, the focus remains on the link. So if the user presses the up or down keys, they end up scrolling the main document, not the lightbox that is displayed!

I've tried to set the focus to the lightbox element using code like this

function focus_on_lightbox() {
  document.getElementById('lightbox_content').focus(); 
}

This works fine if I type it in the firebug console, but will not work if I include it at the end of the onclick snippet. It appears as though I can't change the focus away from the link from code executed inside the onclick event?


-- Update 1 I've tried something like this before

<a href="#" onclick="show_lightbox();focus_on_lightbox();return false;">show lightbox</a>

and I've modified function to add some debugging output, as follows

function focus_on_lightbox() {
  console.log('hihi');
  console.log(document.activeElement);
  document.getElementById('lightbox_content').focus(); 
  console.log(document.activeElement);
}

The output is as follows

hihi
<a onclick="closePopup();lightbox('apartment_detail','11619');focus_on_lightbox();return false;" href="#">
<a onclick="closePopup();lightbox('apartment_detail','11619');focus_on_lightbox();return false;" href="#">

So the focus before I did anything was on the link and after I tried to change the focus it still remained on the link?

Not sure if it matters, but I use ajax to load the lightbox, as follows

  new Ajax.Updater(lightbox_content_id, url, {asynchronous:true, evalScripts:true, onLoading:show_lightbox_loading(), onComplete:focus_on_lightbox() });

I tried to set the focus after the ajax complete, but also, no luck.

What am I missing?


I've been trying to make a solution work that was suggested below by trying to set the focus, seeing if I succeeded by checking document.activeElement, if not, wait 100 milliseconds and try again. If I use the following function, it will work

function focus_on_lightbox() {
  var seconds_waited = 0
  pause(100);
  var current_focus = document.activeElement
  while (document.getElementById(lightbox_content_id) != current_focus && seconds_waited < 2000)
  {
    document.getElementById(lightbox_content_id).focus(); 
    console.log(document.activeElement);
    pause(100);
    current_focus = document.activeElement
    seconds_waited += 100;
  }
}

However, if I remove the firebug debugging statment console.log, the function stops working!! I have no idea why this would be the case?? Why would outputting a variable to the firebug console affect weather focus is moved to the element or not? Does the console.log statement affect focus? perhaps by bringing the focus to the console debugging window?

+3  A: 

I think your problem is calling your focus method after return false. your code should be like that :

<a href="#" 
    onclick="show_lightbox();focus_on_lightbox();return false;">
    show lightbox
</a>
Canavar
if i wasn't busy editing the original post, i would have said this.
Triptych
Actually that was one of the first things I tried and it didn't work. I'll edit the original question with more details.
Janak
A: 

In my experience, focus issues can sometimes be timing-related (e.g., focus() executes before the element is fully ready to be focused). I'm assuming that the lightbox markup is created dynamically when the show_lightbox function is called? If that's the case you could try adding a slight delay before attempting to focus to see if that's the issue, something like:

setTimeout("focus_on_lightbox();", 10);
bmoeskau
Okay, the timeout idea does seem to work, but it doesn't solve my problem. In order to get it to work I had to set my timeout to 1500, a full second and a half. This is going to give my users inconsistent behavior. Is there anyway to test to see if a element is ready to receive focus?
Janak
A: 

Make the element focus itself. On the element's load event, set a timeout of a few ms and then call this.focus();

Else try jQuery.

Antony Carthy
A: 

Here is the function that finally worked

function focus_on_lightbox(seconds) {
  var seconds_waited
  seconds_waited = seconds
  document.getElementById(lightbox_content_id).focus(); 
  seconds_waited += 100;

  if (document.getElementById(lightbox_content_id) != document.activeElement && seconds_waited < 2000)
    setTimeout("focus_on_lightbox(" + seconds_waited + ");", 100);
  {
  }
}

So why did console.log seem to affect setting the focus? Before I was using this function to pause between attempts of changing the focus.

function pause(milliseconds) {
    var dt = new Date();
    while ((new Date()) - dt <= milliseconds) { /* Do nothing */ }
}

This causes javascript to constantly be doing something and I think it wasn't giving the document time to render or update or something. The console.log seemed to break this lock and give the page a chance to change its focus.

When I changed approaches to using the timeout to pause between attempts, console.log was no longer needed!

Thanks bmoeskau for pointing me in the right direction.

Janak