Опубликован: 10.12.2007 | Доступ: свободный | Студентов: 822 / 20 | Оценка: 5.00 / 5.00 | Длительность: 58:33:00
Лекция 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() для простой регулярной проверки состояния. При использовании таких асинхронных запросов пользователю могут не требоваться уведомления о состоянии. Тем не менее, программист должен позаботиться о том, чтобы последующие действия пользователя не повлияли на обработку ответа, когда он появится. Например, пользователи, покупающие акции, не должны иметь возможность опустошить свои банковские счета во время процесса покупки акций.