I’ve made some code to restrict tab navigation on some elements of my choice. You can see the full code working here : http://jsfiddle.net/M2ELL/2/ it’s working fine.
The thing is I want to “decorate” the parent div where the focus occurs. For that matter I’ve made these event listener :
$('[data-mymodaltabindex]').blur(function () {
$(this).parent().removeClass('highlight');
console.log('blur ' + $(this));
});
$('[data-mymodaltabindex]').focus(function () {
$(this).parent().addClass('highlight');
console.log('highlight ' + $(this));
});
These work as expected when there is only one input per parent div. On the other hand when there is two input per parent div (like the two radios in my example) the focus event occurs always before the blur event. The result is highlighting then removing the highlight on the div which is the opposite that I want.
I would like the blur event to occur before resulting in remove highlight then highlight. How can I achieve that ? Why focus event always occurs before blur event in this case ?
Full Code :
<div>
radio 1
<input type="radio" data-mymodaltabindex="1" />
radio 2
<input type="radio" data-mymodaltabindex="2" />
</div>
<div>
text
<input type="text" data-mymodaltabindex="3" />
</div>
$('[data-mymodaltabindex]').on('keydown', function (e) {
if (e.keyCode == 9 || e.which == 9) {
// define variables
var mytabindex = null;
var maximum = null;
var minimum = null;
var next = null;
var previous = null;
var values = new Array();
// set mytabindex on the actual focused control
var mytabindex = $(this).attr('data-mymodaltabindex');
// put every visible mytabindex into array
$('[data-mymodaltabindex]:visible').each(function () {
values.push(parseInt($(this).attr('data-mymodaltabindex')));
});
//console.log(values);
// look for maximum minimum mytabindex
// for maximum and minimum we filter out null values
// as they are interpreted as 0 with math functions
maximum = Math.max.apply(null, values.filter(function (val) { return val !== null }));
minimum = Math.min.apply(null, values.filter(function (val) { return val !== null }));
// set next and previous using function
next = getModalClosestHighValue(values, mytabindex);
previous = getModalClosestLowValue(values, mytabindex);
// go back to begining / end if
// end / begining is reached
if (!previous) { previous = maximum; }
if (!next) { next = minimum; }
// check if there is shift combination
if (e.shiftKey) {
mytabindex = previous; // focus on the previous item
} else {
mytabindex = next; // focus on the next item
}
// focus on this element
$('[data-mymodaltabindex=' + mytabindex + ']').focus();
console.log('focus set to [data-mymodaltabindex=' + mytabindex + ']');
// stop propagation
return false;
}
});
function getModalClosestHighValue(a, x) {
var hi;
for (var i = a.length; i--; ) {
if (a[i] > x && (hi === undefined || hi > a[i])) hi = a[i];
};
return hi;
}
function getModalClosestLowValue(a, x) {
var lo;
for (var i = a.length; i--; ) {
if (a[i] < x && (lo === undefined || lo < a[i])) lo = a[i];
};
return lo;
}
It turns out that it’s a bug with some jQuery versions that can be solved by using jQuery 1.9.
Works with 1.9 : http://jsfiddle.net/7mfLb/
Doesn’t work with 1.8.3 : http://jsfiddle.net/dHwE5/
If you want to make it work with 1.7.2, then I propose you this workaround :
Demonstration