Опубликован: 10.12.2007 | Уровень: специалист | Доступ: платный
Лекция 7:

Формы и меню

7.3.3. Отправка форм

XUL не связывает элементы форм с целевым URL так, как это делает HTML, но все же цель заполнения формы - отправить куда-то информацию. В Mozilla возможности хранения данных так же универсальны и разнообразны, как и в любых других средах программирования. Это не очень удобно, если вы хотите быстро создать работающий прототип. Mozilla предоставляет два варианта эффективной отправки данных XUL-формы на web-сервер.

7.3.3.1. Отправка данных XUL-форм с помощью HTML

Первый метод отправки данных XUL-формы, очень быстрый и не самый аккуратный, подразумевает использование пространств имен XML. Можно создать документ, который начинается с XUL, но включает все функции HTML. В листинге 7.1 показан такой документ.

<?xml version="1.0"?> 
<!DOCTYPE window> 
<window xmlns="http://www.mozilla.org/keymaster/
 gatekeeper/there.is.only.xul" 
  xmlns:html="http://www.w3.org/1999/xhtml"> 
  <vbox> 
<script> 
  function copy() { 
    var getID = document.getElementByID; 
    getID("h1").value = getID("x1").value; 
    getID("h2").value = getID("x2").value; 
    return true; 
} 
</script> 
<html:form action="test.cgi" method="GET" 
  enctype="application/x-www-form-urlencoded"> 
<html:input id="h1" type="hidden"/> 
<html:input id="h2" type="hidden"/> 
<radiogroup> 
  <button id="x1" label="Кнопка 1" type="radio"/> 
  <button id="x2" label="Кнопка 2" type="radio"/> 
</radiogroup> 
<html:input type="submit" onsubmit="return copy();"> 
</html:form> 
</vbox> 
</window>
Листинг 7.1. Смесь HTML- и XUL-форм

Этот документ отображает форму, состоящую из двух XUL-кнопок и одной XHTML-кнопки для отправки данных. В обычном XHTML нельзя поместить кнопки в группу переключателей, но здесь это допустимо, так как Mozilla поддерживает сочетание XUL и HTML. XHTML-элементы формы связываются с процессом отправки данных формы, но XUL-элементы - нет. Простая функция на JavaScript копирует необходимые данные в скрытые поля перед отправкой информации.

Можно создать действительный документ из XHTML+XUL, не прибегая к пространствам имен xmlns. Для этого нужно начать с "чистого" XHTML-документа (или XUL-документа) и добавить DTD-сущности для XUL- приложения (или XHTML-приложения) в объявление <!DOCTYPE>. Такой документ не использует особый механизм xmlns, с помощью которого Mozilla определяет тип документа. Это значит, что для таких дополнительных тегов не будет использоваться никакая дополнительная обработка (поддержка). Это отсутствие определения типов - причина того, что добавление тега <A> в XUL-документ не приводит к созданию XHTML-ссылки.

7.3.3.2. Объект XMLHttpRequest

Во второй методике отправки данных XUL-формы используется объект XMLHttpRequest. Это доступный из скриптов AOM-объект, применимый во всех XML-документах, как, например, объект Image в HTML-документах. Он позволяет отправлять HTTP-запросы напрямую из JavaScript. Ответ сервера на такой запрос не замещает текущий отображаемый документ. Такой ответный документ просто читается как одна большая строка. Объект XMLHttpRequest основывается на следующем XPCOM-компоненте:

@mozilla.org/xmlextras/xmlhttprequest;1

Этот компонент реализует XPCOM-интерфейсы nsIXMLHttpRequest и nsIJSXMLHttpRequest, которые хорошо объясняются в файлах определений. Эти интерфейсы позволяют отправлять HTTP-запросы синхронно и асинхронно. Синхронная отправка означает, что скрипт приостанавливает свою работу, пока не будет получен полный ответ. Асинхронная отправка - аналог самонаводящегося снаряда, только этот запрос можно отслеживать, а конечный результат - забрать. В листинге 7.2 показано, как работают синхронные запросы.

var req = new XMLHttpRequest(); 
// Запрос 
var res = null; 
// Ответ 
var params = encodeURI("param1=value1;param2=value2");
// -- GET-запрос
req.open("GET", "test.cgi" + "?" + params); 
req.send(""); 
if ( req.status / 100 == 2 ) 
// Ответ HTTP 2xx? 
res = req.responseText;
// -- POST-запрос
req.open("POST", "test.cgi"); 
req.send(params); 
if ( req.status / 100 == 2 ) 
// Ответ HTTP 2xx? 
res = req.responseText;
Листинг 7.2. Примеры синхронных запросов XMLHttpRequest

Функция encodeURI() - аналог escape() для ECMAScript ; поддерживаются обе. Второй аргумент open() - любой корректный URL. Так как send() не возвращает ничего, пока пара запрос-ответ не будет полной, программист должен предоставить пользователю какой-нибудь индикатор вроде "Ожидается..." сразу перед вызовом send(), чтобы пользователь знал, что приложение продолжает работу, а не просто "зависло".

Асинхронная отправка данных форм полезна, когда нужно выполнить несколько HTTP-запросов. Более эффективно отправить все запросы за раз, а затем время от времени проверять их состояние. Простейший способ выполнить асинхронную отправку - поместить ее в функцию и запланировать с помощью setTimeout(). В листинге 7.3 показан более формальный и структурированный подход с использованием интерфейса nsIXMLHttpRequest.

var req = new XMLHttpRequest(); // Запрос var res = null; 
  // Ответ var url = "test.cgi?text1=value1";
// Часть, специфичная для асинхронных запросов
function finished() {
  res = req.responseText; 
} 
function inprogress() { 
  if ( req.readyState != req.COMPLETED ) { 
    res = "Waiting ..."; 
    setTimeout(inprogress, 100); 
  } 
} 

req.COMPLETED = 4; 
// из интерфейса 
req.onload = finished; 

// -- GET-запрос (POST аналогичен)
req.open("GET", url, false); 
// false == асинхронный req.send(); 

// следующая инструкция выполняется немедленно 
setTimeout(inprogress,100);
Листинг 7.3. Пример асинхронного запроса XMLHttpRequest

В этом примере метод send() возвращает ? почти сразу, оставляя HTTP-запрос в обработке. Функция finished() создана как обработчик событий, который запускается, когда ответ наконец-то получен полностью. Между этими двумя точками во времени используется setTimeout() для простой регулярной проверки состояния. При использовании таких асинхронных запросов пользователю могут не требоваться уведомления о состоянии. Тем не менее, программист должен позаботиться о том, чтобы последующие действия пользователя не повлияли на обработку ответа, когда он появится. Например, пользователи, покупающие акции, не должны иметь возможность опустошить свои банковские счета во время процесса покупки акций.

Дмитрий Гуменюк
Дмитрий Гуменюк
Россия, Звенигород
Konstantin Grishko
Konstantin Grishko
Россия, Москва, Московский финансово-промышленный университет "Синергия", Москва