Модальное поле

Published: 14.07.2011

Все знакомы с таким понятием, как модальная форма - когда при выводе её на экран приложение блокируется, пока эта форма не будет закрыта. Для JQuery существует множество плагинов для создания модальных форм. Вот, к примеру, демо-страница плагина jQuery BlockUI Plugin. Как видите, плагин обладает неплохим функционалом для создания модальных форм.

Вот к нему-то я и обратился за помощью, когда возникла необходимость реализовать модальное поле. Но что такое "модальное поле"? Ну, это моё условное обозначение того, что я сделал. Нобелевку мне! Ладно, суть задачи такова: есть форма, в ней - определённое текстовое поле. Надо, чтобы при начале набора текста или изменении уже введённого, вся остальная форма блокировалась, за исключением этого самого поля, в котором пользователь беспрепятственно продолжает редактировать текст.

Итак, есть форма:

<form id="blocked1">
  <span>Наше модальное поле</span>
  <div id="modalField_wrapper" class="wrapper">
    <input id="modalfield" type="text" value="change me"/>
  </div>
  <span>А это поле должно быть заблокировано</span>
  <div class="wrapper">
    <input type="text" value="it will blocked"/>
  </div>
</form>

Когда пользователь изменяет текст нужного нам поля, форма блокируется следующим образом (например):

$('#blocked1').block({ message: null });

Плагин помещает в форму блочный элемент, который растягивается на всю форму, имеет значение css-атрибута z-index: 1000, поэтому оказывается "выше" всех остальных элементов формы, перекрывая к ним доступ. Довольно просто, но беда в том, что и наше поле тоже блокируется, так как принадлежит блокируемой форме. Что нужно сделать? Решение очевидно: средствами JavaScript переместить наше поле в DOM-структуре на более высокий уровень по сравнению с блокирующим div'ом, например в <body>, одновременно установив значение z-index больше, чем у блокирующего элемента, например, z-index: 2000.

Вот и всё, теперь соберём всё в кучу:

  1. $(function() {
  2.   var modalfield_val;
  3.   var flag = true; // признак блокировки формы
  4.   var coord;
  5.  
  6.   // нажимаем клавишу
  7.   $('#modalfield').keydown(function(event) {
  8.     // запоминаем значение поля
  9.     modalfield_val = $('#modalfield').val();
  10.   });
  11.  
  12.   // отпускаем клавишу
  13.   $('#modalfield').keyup(function(event) {
  14.     // по нажатии "Enter" снимаем блокировку, возвращаем элемент обратно в форму
  15.     if (event.which == 13) {
  16.       $('#blocked1').unblock();    
  17.       $('#modalfield').detach().appendTo('#modalField_wrapper').offset(coord).focus();  
  18.       flag = true;
  19.       return true;
  20.     }
  21.     // если форма не заблокирована и содержание поля изменилось,
  22.     // запоминаем координаты поля, и переносим поле в body в те же координаты
  23.     // блокируем форму
  24.     if (flag == true && modalfield_val != $('#modalfield').val()) {  
  25.       coord = $('#modalfield').offset();
  26.       $('#modalfield').detach().appendTo('body').offset(coord).focus();
  27.       flag = false;
  28.       $('#blocked1').block({ message: null });
  29.     }
  30.   });
  31. });

Здесь можно посмотреть, что получилось: посмотреть

Скачать архив с исходниками.

Я намеренно оставил небольшую недоработку, потому что это касается не только нашего примера. Если открыть страницу с примером в Internet Explorer версии 7 или 8, то вы увидите, что при перемещении поле ввода теряет фокус, вернее, функция focus() не работает для элементов, которые были добавлены в DOM-структуру с помощью JS. Чтобы это исправить, нужно после строчек 17 и 26 вставить следующий код:

if ($.browser.msie) {
  var modalfield = $('#modalfield');
  modalfield.blur().focus().val(modalfield.val());
}