sdleihssirhc sdleihssirhc - 7 months ago 27
Javascript Question

How to detect `focusin` support?

Thanks to Perfection kills, we can use the following JavaScript to detect event support:

function hasEvent(ev) {
var elem = document.createElement('a'),
type = 'on' + ev,
supported = elem[type] !== undefined;
if (!supported) {
elem.setAttribute(type, 'return;');
supported = typeof elem[type] === 'function';
}
elem = null;
return supported;
}


This works for about the only time I need it: detecting
mouseenter
support;
hasEvent('mouseenter')
will return false in Chrome, Firefox, etc., as it should.

But now I'm trying to "fix" browsers that don't support the
focusin
and
focusout
events. According to PPK, that's basically just Firefox. Unfortunately, Chrome and Safari are listed as having "incomplete" support, for the following reason:


Safari and Chrome fire these events only with addEventListener; not with traditional registration.


In general, that's fine; I'd only be using
addEventListener
anyway. It does mean, however, that detecting support via
elem.onfocusin !== undefined
won't work. I tested it out, and it's true:

<p>Do I support <a href="#">focusin</a>?</p>

<script>
var elem = document.getElementsByTagName('p')[0];

// hasEvent method defined here
function listener() {
var response = hasEvent('focusin') ? 'Yes!' : 'No...';
alert(response);
}

elem.addEventListener('focusin', listener, false);
</script>


The above alerts
No...
in Chrome!! Is there any way to detect whether the browser supports
focusin
, without using browser sniffing?

Answer

This uses the fact that calling focus() triggers focusin: http://jsfiddle.net/pimvdb/YXeD3/.

The element must be visible and inserted into the DOM, otherwise focusin is not fired for some reason.

var result = (function() {
    var hasIt = false;

    function swap() {
        hasIt = true; // when fired, set hasIt to true
    }

    var a = document.createElement('a'); // create test element
    a.href = "#"; // to make it focusable
    a.addEventListener('focusin', swap, false); // bind focusin

    document.body.appendChild(a); // append
    a.focus(); // focus
    document.body.removeChild(a); // remove again

    return hasIt; // should be true if focusin is fired
})();