1

There are a few good questions on here regarding how to determine where focus goes 'concurrent' to a textarea onblur.

But I haven't found a good cross-browser way to determine which anchor tag has been clicked which caused a textarea to fire onblur, setTimeout or no. document.activeElement looked promising, but, answers seemingly to the contrary, without a setTimeout, activeElement is unreliable. I keep getting the body returned as the activeElement in some browsers.

For example: jsFiddle-ige #1:

HTML

<form>
    <input onblur="blurHandler();" type="text" id="spam1" 
        value="immediate blur check">
    <input onblur="blurHandlerTimeout();" type="text" id="spam2" 
        value="delayed blur check"> 
    <a href="#" id="spam3">X</a>
    <br>
</form>
<br>
<hr>
<br>
<div id="logs"></div>

JavaScript

var logs = document.getElementById('logs');

function blurHandler() {
    logit(document.activeElement.outerHTML.substr(0, 80));
}

function blurHandlerTimeout() {
    setTimeout(function () {
        logit(document.activeElement.outerHTML.substr(0, 80));
    }, 10);
}

function logit(msg) {
    try {
        var e = document.createTextNode(msg), // probably a better way, but this does allow html as text
            f = document.createElement('div');

        logs.insertBefore(e, logs.firstChild);
        logs.insertBefore(f, logs.firstChild);
    } catch (err) {
        alert(err);
    }
}

Body element for blur from the immediate blur check textbox occurs every time for the following:

  • Safari 5.1.7 (which doesn't let me focus on the anchor at all, tabbing or clicking)
  • Firefox 18.0.1
  • Chrome 24.0.1312.56 m,

Setting focus to the delayed blur check box and clicking/tabbing into the anchor gives me:

  • Chrome: the body if click the anchor
  • Chrome: the anchor if I tab into it
  • Safari: the body either way
  • Firefox: the anchor no matter what

IE8 gives me the anchor every time for each textbox, delayed handler or no.

So admittedly there are ways to have the anchor set a boolean at a shared scope level (eg, a global) and have a setTimeout from the blur event query that boolean to see if the anchor [recently] got focus, but man oh man that's kludgey.

That said, I did it, give or take, here: jsFiddle-ige #2 Seems to work okay there in all four, though I'm afraid it's going to be edge-case crazy.

Is there better way to do this? jQuery's fine, I guess, though I'd prefer a clean JavaScript solution -- which is to say that a clean jQuery solution is better than convoluted JavaScript fix.

Brian Tompsett - 汤莱恩
  • 5,753
  • 72
  • 57
  • 129
ruffin
  • 16,507
  • 9
  • 88
  • 138

1 Answers1

1

The delayed check for document.activeElement works in all browsers as long as you specify a tabindex attribute on the anchor tag. a, by default, has no tabbing order, so I'd argue that those browsers that are able to "focus" the a at all without that attribute are misbehaving.

Per the HTML5 spec:

The tabindex content attribute allows authors to control whether an element is supposed to be focusable, whether it is supposed to be reachable using sequential focus navigation, and what is to be the relative order of the element for the purposes of sequential focus navigation.

(Emphasis mine)

<form>
    <input onblur="blurHandler();" type="text" id="spam1" 
        value="immediate blur check">
    <input onblur="blurHandlerTimeout();" type="text" id="spam2" 
        value="delayed blur check"> 
    <a href="#" id="spam3" tabindex='1'>X</a>
    <br>
</form>
<br>
<hr>
<br>
<div id="logs"></div>

Updated fiddle: http://jsfiddle.net/Y5kcp/4/

Tested in IE8/9, FF 18.0.1, Chrome 24.0.1312.56 m, Safari 5.17

This is pure speculation, but maybe IE was behaving nicely because the HTML4 spec for tabindex doesn't mention "focusability" as a feature:

This attribute specifies the position of the current element in the tabbing order for the current document.

In that case, maybe browsers adhering to the HTML 4 specification are okay allowing the anchor tag to be focusable with or without the tabindex attribute.

It's also worth noting that document.activeElement was a proprietary IE4 feature (see Notes on the MDN article for document.activeElement). Maybe that's why it'll function without the timeout in Internet Explorer.

Andrew Whitaker
  • 124,656
  • 32
  • 289
  • 307