понедельник, 5 апреля 2010 г.

JavaScript: навигация стрелками и Enter

Убил восемь (!) часов на скорбный труд по созданию этого монстрика.

/**
*
* Keyboard Form Navigation
* Использование: в конце документа исполните KFN.init ('form1');
*
**/

// Фокусируется на элементе
function setFocus(id) {
document.getElementById(id).focus();
setTimeout("document.getElementById('"+id+"').select();", 100);
}

// Возвращает случайный ID, не присутствующий ещё в документе
function randomId (){
do {
var newId = "rnd" + Math.floor((Math.random() * 1000000));
}
while (document.getElementById(newId) != null);
return newId;
}

// Набор функций, обеспечивающий навигацию по стрелкам и Enter
var KFN = {

// Список полей формы, по которым надо перемещаться стрелками
_elements : [],

// Форма субмиттится только если _flag == true
_allow_submit : false,

// Субмитит форму. Нужен, чтобы форма не субмитилась по каждому энтеру
_submit : function () {
if (this._allow_submit)
document.getElementById(this._elements[0]).form.submit();
},

// Инициализирует форму для работы со стрелками и Enter
// Меняет onFocus у всех полей формы.
init : function (formId) {
var thisForm = document.getElementById(formId);
thisForm.setAttribute("autocomplete", "off")
if (thisForm.addEventListener) {
thisForm.addEventListener("submit", function(e) { e.preventDefault(); }, false);
thisForm.addEventListener("keydown", function(e) { KFN.next(e); }, false);
}
else if (thisForm.attachEvent) {
// Ослик вместо preventDefault использует event.returnValue = false;
thisForm.attachEvent("onsubmit", function(e) { e.returnValue = false; });
thisForm.attachEvent("onkeydown", function(e) { KFN.next(e); });
}
for (var i = 0 , e = thisForm.elements, len = e.length; i < len; i++ ) {
if (/text|password|file|checkbox|radio|select/.test (e[i].type)) {
// Если у поля нет id, ставим какой-нибудь
if (!e[i].id) e[i].id = randomId();
this._elements.push (e[i].id);
// Автокомплект должен быть отключён как на форме, так и на всех полях.
e[i].setAttribute("autocomplete", "off")
// Без этих самодельных обработок мы бы не узнали, на каком элементе фокус
e[i].hasFocus=false;
e[i].onfocus=function(){this.hasFocus=true;};
e[i].onblur =function(){this.hasFocus=false;};
} else if (e[i].type == "submit") {
// Обработка нажатия мышью на обычную субмит-кнопку
e[i].onfocus=function(){KFN._allow_submit=true;}
e[i].onblur=function(){KFN._allow_submit=false;}
if (e[i].addEventListener) {
e[i].addEventListener("click", function() { KFN._submit(); }, false);
} else if (e[i].attachEvent) {
e[i].attachEvent("onclick", function() { KFN._submit(); });
}
}
}
// Фокусируемся на первом поле формы
setFocus (this._elements[0]);
},

// Переходит к следующему полю формы
next: function (input) {
// Обрабатываем только три клавиши. 13: Enter, 38: Up, 40: Down
if ((input.keyCode != 13) && (input.keyCode != 38) && (input.keyCode != 40))
return true;
// Находим текущий элемент (по фокусу)
for (var i=0; i<this._elements.length; i++)
if (document.getElementById(this._elements[i]).hasFocus)
var current = i;
if (current === undefined) return true;
// Перемещаем фокус
switch (input.keyCode) {
case 13: // Enter
if ((current + 1) < this._elements.length) {
setFocus (this._elements[1+current]);
} else {
document.getElementById(this._elements[current]).form.submit();
}
break;
case 38: // Вверх
current--;
if (current < 0) current = 0;
setFocus (this._elements[current]);
break;
case 40: // Вниз
current++;
if (current >= this._elements.length) current = this._elements.length - 1;
setFocus (this._elements[current]);
break;
}
return false;
}
}

Комментариев нет:

Отправить комментарий