- •Введение
- •Несколько слов о книге
- •Глава 1. Каким должен бытъ Web-интерфейс
- •Действия пользователя при работе с приложением
- •Накладные расходы при работе в сети
- •Асинхронное взаимодействие
- •Независимый и переходный образы использования
- •Четыре основных принципа Ajax
- •Браузер имеет дело с приложением, а не с содержимым
- •Сервер доставляет данные, а не содержимое
- •Реальное кодирование требует порядка
- •Применение богатых клиентов Ajax
- •Системы, созданные с использованием Ajax
- •Google Maps
- •Альтернативные технологии
- •Macromedia Flash
- •Java Web Start
- •Резюме
- •Ресурсы
- •Основные элементы Ajax
- •JavaScript изучался не зря
- •Определение внешнего вида с помощью CSS
- •Селекторы CSS
- •Свойства стилей
- •Простой пример использования CSS
- •Обработка DOM с помощью JavaScript
- •Поиск узла DOM
- •Создание узла DOM
- •Добавление стилей к документу
- •Свойство innerHTML
- •Асинхронная загрузка с использованием XML
- •Элементы IFrame
- •Объекты XmlDocument и XMLHttpRequest
- •Использование фуниции обратного вызова для контроля запроса
- •Жизненный цикл процедуры поддержки запроса
- •Отличия Ajax от классических технологий
- •Резюме
- •Ресурсы
- •Порядок из хаоса
- •Образы разработки
- •Реструктуризация и Ajax
- •Во всем надо знать меру
- •Реструктуризация в действии
- •Варианты применения реструктуризации
- •Несоответствие браузеров: образы разработки Fagade и Adapter
- •Управление обработчиками событий: образ разработки Observer
- •Повторное использование обработчиков событий: образ разработки Command
- •Обеспечение единственной ссылки на ресурс: образ разработки Singleton
- •"Модель-представление-контроллер "
- •Серверная программа Ajax, созданная без применения образов разработки
- •Реструктуризация модели
- •Разделение содержимого и представления
- •Библиотеки независимых производителей
- •Библиотеки, обеспечивающие работу с различными браузерами
- •Компоненты и наборы компонентов
- •Элементы, располагаемые на стороне сервера
- •Резюме
- •Ресурсы
- •Применение архитектуры MVC к программам различных уровней
- •Применение архитектуры MVC к объектам, присутствующим в среде браузера
- •Представление в составе Ajax-приложения
- •Отделение логики от представления
- •Отделение представления от логики
- •Контроллер в составе Ajax-приложения
- •Классические JavaScript-обработчики
- •Модель обработки событий W3C
- •Реализация гибкой модели событий в JavaScript
- •Модель в составе Ajax-приложения
- •Использование JavaScript для моделирования предметной области
- •Взаимодействие с сервером
- •Генерация представления на основе модели
- •Отражение объектов JavaScript
- •Обработка массивов и объектов
- •Включение контроллера
- •Резюме
- •Ресурсы
- •Программы, выполняемые на сервере
- •Создание программ на стороне сервера
- •N-уровневые архитектуры
- •Управление моделью предметной области на стороне клиента и на стороне сервера
- •Принципы создания программ на сервере
- •Серверные программы, не соответствующие основным принципам разработки
- •Использование архитектуры Model!
- •Использование архитектуры на базе компонентов
- •Архитектуры, ориентированные на использование Web-служб
- •Частные решения: обмен данными
- •Взаимодействие, затрагивающее только клиентскую программу
- •Пример отображения информации о планетах
- •Взаимодействие, ориентированное на содержимое
- •Взаимодействие, ориентированное на сценарий
- •Передача данных серверу
- •Использование HTML-форм
- •Использование объекта XMLHttpRequest
- •Управление обновлением модели
- •Резюме
- •Ресурсы
- •Создание качественного приложения
- •Отклик программы
- •Надежность
- •Согласованность
- •Простота
- •Как получить результат
- •Предоставление сведений пользователю
- •Поддержка ответов на собственные запросы
- •Обработка обновлений, выполненных другими пользователями
- •Создание системы оповещения
- •Основные принципы оповещения
- •Реализация базовых средств оповещения
- •Отображение пиктограмм в строке состояния
- •Отображение подробных сообщений
- •Формирование готовой системы
- •Предоставление информации в запросах
- •Информация о новизне данных
- •Простой способ выделения данных
- •Выделение данных с использованием библиотеки Scriptaculous
- •Резюме
- •Ресурсы
- •JavaScript и защита браузера
- •Политика "сервера-источника"
- •Особенности выполнения сценариев в Ajax-приложении
- •Проблемы с поддоменами
- •Взаимодействие с удаленным сервером
- •Взаимодействие с Web-службами
- •Защита конфиденциальной информации
- •Вмешательство в процесс передачи данных
- •Организация защищенного НТТР-взаимодействия
- •Передача шифрованных данных в ходе обычного HTTP-взаимодействия
- •Управление доступом к потокам данных Ajax
- •Создание защищенных программ на уровне сервера
- •Ограничение доступа к данным из Web
- •Резюме
- •Ресурсы
- •Что такое производительность
- •Скорость выполнения JavaScript-программ
- •Определение времени выполнения приложения
- •Использование профилировщика Venkman
- •Оптимизация скорости выполнения Ajax-приложения
- •Использование памяти JavaScript-кодом
- •Борьба с утечкой памяти
- •Особенности управления памятью в приложениях Ajax
- •Разработка с учетом производительности
- •Простой пример управления памятью
- •Как уменьшить объем используемой памяти в 150 раз
- •Резюме
- •Ресурсы
- •Сценарий двойной комбинации
- •Недостатки клиентского решения
- •Недостатки клиентского решения
- •Архитектура клиента
- •Разработка взаимодействия клиент/сервер
- •Реализация сервера: VB.NET
- •Написание кода сервера
- •Представление результатов
- •Применение каскадных таблиц стилей
- •Дополнительные вопросы
- •Запросы при выборе нескольких элементов
- •Переход от двойного связного выбора к тройному
- •Реструктуризация
- •Новый и улучшенный объект netContentLoader
- •Создание компонента двойного списка
- •Резюме
- •Глава 10. Опережающий ввод
- •Изучаем опережающий ввод
- •Типичные элементы приложений опережающего ввода
- •Google Suggest
- •Ajax как средство опережающего ввода
- •Структура серверной части сценария: С#
- •Сервер и база данных
- •Тестирование серверного кода
- •Структура клиентской части сценария
- •HTML
- •JavaScript
- •Обращение к серверу
- •Дополнительные возможности
- •Реструктуризация
- •День 1: план разработки компонента TextSuggest
- •День 3: включаем Ajax
- •День 4: обработка событий
- •День 5: пользовательский интерфейс всплывающего окна с предлагаемыми вариантами
- •Итоги
- •Резюме
- •Эволюционирующий портал
- •Классический портал
- •Портал с богатым пользовательским интерфейсом
- •Создание портала с использованием Java
- •Таблица пользователя
- •Серверная часть кода регистрации: Java
- •Структура регистрации (клиентская часть)
- •Реализация окон DHTML
- •База данных окон портала
- •Серверный код окна портала
- •Добавление внешней библиотеки JavaScript
- •Возможность автоматического сохранения
- •Адаптация библиотеки
- •Автоматическая запись информации в базе данных
- •Реструктуризация
- •Определение конструктора
- •Адаптация библиотеки AjaxWindows.js
- •Задание команд портала
- •Выводы
- •Резюме
- •Понимание технологий поиска
- •Классический поиск
- •"Живой" поиск с использованием Ajax и XSLT
- •Возврат результатов клиенту
- •Код клиентской части сценария
- •Настройка клиента
- •Инициализация процесса
- •Код серверной части приложения: РНР
- •Создание XML-документа
- •Создание документа XSLT
- •Объединение документов XSL и XML
- •Совместимость с браузером Microsoft Internet Explorer
- •Совместимость с браузерами Mozilla
- •Последние штрихи
- •Применение каскадных таблиц стилей
- •Улучшение поиска
- •Поддержка браузерами Opera и Safari
- •Использовать ли XSLT
- •Решение проблемы закладок
- •Реструктуризация
- •Объект XSLTHelper
- •Компонент "живого" поиска
- •Выводы
- •Резюме
- •Считывание информации из внешнего мира
- •Поиск XML-лент
- •Изучение структуры RSS
- •Богатый пользовательский интерфейс
- •Чтение лент
- •HTML-структура без таблиц
- •Гибкое CSS-форматироеание
- •Глобальный уровень
- •Предварительная загрузка средствами Ajax
- •Богатый эффект перехода
- •Правила прозрачности, учитывающие индивидуальность браузеров
- •Реализация затухающего перехода
- •Интеграция таймеров JavaScript
- •Дополнительные возможности
- •Введение дополнительных лент
- •Интеграция функций пропуска и паузы
- •Как избежать ограничений проекта
- •Обход системы безопасности браузеров Mozilla
- •Изменение масштаба приложения
- •Реструктуризация
- •Модель приложения
- •Представление приложения
- •Контроллер приложения
- •Выводы
- •Резюме
- •Отладчики
- •Для чего нужен отладчик
- •Средство Safari DOM Inspector для Mac OS X
- •Ресурсы
- •JavaScript — это не Java
- •Формирование объектов
488 Часть IV. Ajax в примерах
ботки, и вызывает сервер, который динамически создаст ответные данные, основываясь на отправленном значении строки запроса. Первым параметром функции LoaciXMLXSLTDoc () является URL страницы РНР, которая генерирует XML-документ, объединенный со строкой запроса, сформированной ссылкой на значений поля HTML-формы О. Второй параметр — это имя XSLTфайла ©, используемого в преобразовании XML-данных. Третий параметр, требуемый функцией LoadXMLXSLTDoc (), представляет собой идентификатор элемента div, в который следует помещать результаты поиска. Идентификатор — это строковое имя выходного элемента, а не ссылка на объект; в данном случае в качестве идентификатора используется строка "results" .
На следующем этапе мы с помощью методов DOM добавляем на Webстраницу изображение-индикатор. Создается элемент изображения © и устанавливается атрибут источника изображения О. Этот созданный элемент добавляется к элементу div с результатами ©. Таким образом, когда наша функция вызывается из обработчика событий onsubmit формы, на страницу помещается файл изображения. Вообще, для пользователя важно создать визуальную обратную связь — сообщение или изображение, — указывающую, что обработка находится в процессе. Благодаря этому пользователь не будет повторно щелкать на кнопке отправки форы, думая, что ничего не происходит (помните, процесс Ajax — "незаметный").
Последний этап — это вызов функции LoadXMLXSLTDoc () ®, инициирующей процесс отправки информации на сервер. Функция LoadXMLXSLTDoc (), описанная в разделе 12.4, обрабатывает вызов объекта ContentLoader (), который запрашивает документы с сервера. Задавая в качестве параметра выходное положение (а не кодируя значение жестко в функции LoadXMLXSLTDoc {)), мы можем многократно использовать данную функцию на одной странице, не требуя для разделения функциональных возможностей добавления множества процедур или операторов if. Следовательно, мы перенаправляем результаты различных поисковых запросов на различные части страницы. Однако, прежде чем мы все это сделаем, давайте посмотрим, как создать на сервере документы XML и XSLT.
12.3.Код серверной части приложения: РНР
Вданном разделе мы создадим для проекта динамический XML-документ, используя РНР — популярный язык подготовки сценариев с открытым исходным кодом (как вы знаете, инфраструктура Ajax совместима с любым серверным языком или платформой). XML-документ генерируется динамически по набору результатов, полученному в ответ на запрос клиента к базе данных. Кроме того, мы покажем, как создать статический документ XSLT, который расположен на сервере и извлекается каждый раз, когда запрашивается динамический файл. Оба указанных документа возвращаются клиенту независимо, когда объект ContentLoader запрашивается в двух отдельных запросах (листинг 12.7). XSLT-код преобразовывает наш динамический XML-документ на стороне клиента и создает HTML-таблицу, которая отображается пользователю.
Глава 12 "Живой" поиск с использованием XSLT 489
12.3.1. Создание XML-документа
Поскольку мы используем XSLT, нам нужен структурированный XMLдокумент, представляющий собой простую запись информации, чтобы XSLфайл мог выполнить стандартное преобразование. В данном проекте мы создадим динамический XML-файл, когда клиент затребует РНР-файл.
Разработка XML-структуры
Прежде чем мы начнем создание XML-файла, необходимо создать шаблон для него. Этот шаблон должен отражать структуру данных, возвращаемых при поиске. В выбранной формулировке задачи (телефонная книга) мы будем возвращать название компании, имя контактного лица, страну и телефонный номер. В листинге 12.3 показан базовый XML-шаблон, содержащий четыре поля.
Листинг 12.3. Базовый XML-файл
<?xml version="l . 0" ?> <phonebook>
<entry>
<company>Company Name</company> <contact>Contact Name</contact> <country>Country Name</country> <phone>Phone Number</phone>
</entry>
</phonebook>
Первым элементом является phonebook. Следующий — элемент entry, содержащий подэлементы со всеми деталями, которые связаны со всеми контактными телефонами, найденными в запросе. Если у нас есть пять результатов, в XML-документе будет пять элементов entry. Имя компании отображается в элементе company. Кроме того, мы добавили имя контактного лица, название страны и номер телефона. Мы не ограничены только указанными полями; в зависимости от того, какую информацию необходимо отобразить, поля можно добавлять и удалять.
Если результаты не найдены, то вместо отображения предупреждающего сообщения можно создать элемент, отображающий эту информацию для пользователя. STO облегчит нам задачу возврата результата пользователю и не потребует дополнительного кода в клиентской части приложения. Код, приведенный в листинге 12.4, практически не отличается от кода из листинга 12.3, но на этот раз мы вводим текст в элементы XML, которые желаем показать пользователю, чтобы сообщить, что результаты не найдены.
Листинг 12.4. Файл XML без результатов
<?xml version="l . 0" ?> <phonebook>
<entry>
<company>No Results</company>
// О Вместо имени компании отображается "No R e s u l t s " <contact>N/A</contact>
490Часть IV. Ajaxв примерах
//© Вместо оставшихся полей отображается "N/A"
<country>N/A</country>
<phone>N/A</phone>
</entry>
</phonebook>
С помощью данного кода мы отображаем пользователю единственную строку, сообщающую, что затребованная информация отсутствует. В дескрипторе company О отображается информация, сообщающая, что результатов нет. В других дескрипторах 0 пользователю сообщается, что информации нет. Если мы не желаем отображать текст "N/A" ("не доступно"), можно добавить вместо него неразрывный пробел, , что позволит показать ячейки таблицы. Если бы мы не добавили вообще никакой информации, ячейки в таблице не появились бы.
Как видите, формат XML имеет очень простую структуру. Если бы данный XML-файл был статическим, пользователю было бы относительно просто добавить в файл нового абонента. Поскольку же он создается динамически, нам потребуется цикл, создающий XML-документ по набору результатов.
Создание динамического XML-документа
Как всегда, мы создаем XML-документ на сервере. Придерживаясь политики использования в примерах различных серверных языков, серверный код дайной главы написан на РНР. Еще раз напомним, что инфраструктуру Ajax можно создать с помощью любого серверного языка, и мы будем описывать только сам принцип реализации серверного кода, не вдаваясь в детали. Итак, в листинге 12.5 показан код серверной части приложения. Код получает параметр строки запроса и генерирует множество результатов запроса базы данных. Затем мы проходим по множеству результатов, создавая в XML-файле согласно приведенному в листинге 12.4 шаблону элемент для каждого номера телефона, полученного в ответ на запрос.
Листинг 12.5. Сценарий phoneXML.php: генерация XML-документа на сервере
<?php
//О Объявить тип MIME header("Content-type: text/xml"); echo("<?xml version='1.01 ?>\n");
//© Соединиться с базой данных
$db = mysql__connect ( "localhost", "ajax", "action"); rnysql_select_db("ajax",$db);
$result = mysql_query("SELECT *
FROM Contacts WHERE ContactName like '%". // © Заполнить запрос
$_GET['q'] ."%"',$db); ?> <phonebook>
<?
// О Проверить результаты
if ($myrow = mysgl_fetch_array($result)) { do {
// © Пройти по множеству результатов
Глава 12. "Живой" поиск с использованием XSLT 491
?>
<entry id='<?=$rayrow['id']?>001'>
<company><?=$myrow['companyNarae']?></company> <contactx?=$myrow['contactName']?></contact> <countryX?=$myrow['country1 ]?></country>
<phone><?=$myrow [ ' phone' ] ?x/phone> </entry>
<?
}while ($myrow - mysql_fetch_array{$result)); }else{
?>
<entry id='0011 >
//@ Показать пустой набор данных
<company>No Results</company> <contact>N/A</contact> <country>N/A</country> <phone>N/A</phone>
</entry> <? } ?> </phonebook>
Чтобы данная динамическая генерация XML-документа удалась, тип MIME документа необходимо установить равным text/xml О; если пропустить этот этап, XSLT-преобразование может не произойти (особенно в браузерах Mozilla и Firefox).
Требуемые нам данные хранятся в таблице базы данных, и нам необходимо просто выбрать нужные записи. В данном случае, для того чтобы максимально упростить работу, мы для непосредственного общения с базой данных используем встроенные функции MySQL языка РНР. Мы соединяемся с базой данных ajax, запущенной на локальном сервере базы данных, используя имя пользователя ajax и пароль action ©. После этого создается строка SQL-запроса; для заполнения оператора WHERE применяется параметр request, переданный в клиентском коде ©.
Для более надежной реализации серверной части приложения рекомендуется не связываться напрямую с базой данных, как в приведенном коде, а использовать структуру, подобную DB_DataObject (Pear) (см. главу 3). Впрочем, текущая реализация очень проста, и читатели, желающие самостоятельно протестировать рассматриваемый пример, могут ее легко настроить.
Получив множество результатов, мы проверяем наличие в нем данных О, а затем либо последовательно проходим по нему © для создания записей телефонной книги, либо выдаем сообщение "No Results" 0.
12.3.2. Создание документа XSLT
Используя XSLT, наш XML-файл с помощью пары строк кода можно преобразовать в красивую таблицу HTML. XSLT-документ разрешает сопоставление с шаблоном, если оно необходимо для отображения данных в любом требуемом формате. При сопоставлении с шаблоном для отображения данных применяется структура-шаблон. При этом мы проходим по узлам дере-
492 Часть IV. Ajax в примерах
ва источника, используя XSLT. XSLT-доку мент принимает структурированный XML-файл и преобразует его в формат, который удобен для просмотра, обновления и изменения. В нашем случае XSLT-доку мент определяется статически.
Структура XSLT
XSLT-преобразование содержит правила для перевода исходного дерева в конечное. Весь XSLT-процесс заключается в сопоставлении со структуройшаблоном. Когда элементы исходного дерева соответствуют заданной структуре, согласно шаблону документа создается конечное дерево.
Структура конечного дерева не обязательно должна быть связана со структурой исходного. Следовательно, исходный XML-файл можно преобразовать в любой требуемый формат. Использовать только табличное представление набора данных не обязательно.
XSLT-преобразование называется таблицей стилей, поскольку оно определяет стилевое оформление конечного дерева. Таблица стилей содержит правила шаблона, состоящие из двух частей. Первая часть — это структурашаблон, с которой сравниваются узлы исходного дерева. Обнаружив соответствие, XSLT-процессор задействует вторую часть — шаблон, содержащий дескрипторы для построения исходного дерева.
Создание XSLT-документа
Сформировать XSLT-преобразование для данного проекта сравнительно просто. Поскольку мы собираемся получить таблицу, никакое необычное сопоставление с шаблоном не потребуется; мы просто последовательно пройдем по всем узлам-элементам исходного дерева. Ниже мы разработаем шаблон, формирующий таблицу HTML с четырьмя столбцами. Соответствующий XSLTфайл для данного проекта показан в листинге 12.6.
i Листинг 12.6. XSLT-файл
<?xml version="1.0" encoding=>"ISO-8859-l"?>
//О Установить версию XML и кодировку <xsl:stylesheet version="l.О" xmlns:xsl=
//© Задать пространство имен XSLT "http://www.w3.org/1999/XSL/Transform">
//© Установить правила шаблона <xsl:template match="/">
//О Добавить элемент table
<table id="tablel">
// © Создать строку заголовка <tr>
<th align="left">Company</th> <th align="left">Contact</th> <th align="left">Country</th> <th align="left">Phone</th>
</tr>
Глава 12 "Живой" поиск с использованием XSLT 493
// 0 Последовательно пройти по элементам телефонной книги <xsl:for-each
select="phonebook/entry"> // © Отформатировать выходные данные
<tr>
<tdxxsl:value-of select="company"/></td> <td><xsl:value-of select="contact"/></td> <td><xsl:value-of select="country"/></td> <td><xsl:value-of select="phone"/></td>
</tr>
</xsl:for-each> </table>
</xsl:template>
</xsl:stylesheet>
При создании XSLT-преобразования необходимо указать кодировку и версию XML О, а также задать пространство имен XSLT ©. Пространство имен определяет правила и спецификации, которым должен соответствовать документ. Элементы в пространстве имен XML распознаются в исходном документе, но не распознаются в документе результатов. Для определения всех наших элементов в пространстве имен XSLT применяется префикс xsl. Далее молено установить правило шаблона — искать структуру / ©, которая соответствует всему документу.
Теперь можно начинать создание шаблона таблицы, в которой отображаются наши результаты. Мы добавляем дескриптор table О, сопоставляющий с таблицей идентификатор. После этого вводится строка заголовка таблицы ©, вмещающая имена столбцов, указывающих пользователю, какая информация содержится в таблице.
Последовательно проходя по множеству узлов исходного дерева, мы получаем остальные строки таблицы. В данном случае используется цикл for-each ©, в процессе обработки записей выдающий узлы, расположенные в phonebook/entry.
Поскольку мы последовательно проходим по дереву документа, необходимо выбрать значения столбцов. Чтобы выбрать значения из узлов, используется оператор value-of в, извлекающий значение элемента XML и добавляющий его в выходной поток преобразования. Чтобы задать элемент XML, текст которого мы желаем извлечь, используем с именем элемента атрибут select. Сформировав XSLT-фаЙл и создав код для динамической генерации документа XML, можно завершить создание JavaScript-кода и посмотреть, как объединение XSLT-преобразования со структурированным XML-файлом позволяет получить удобную для просмотра таблицу.
На следующем этапе мы снова возвращаемся на сторону клиента, извлекающего файлы, созданные только что с помощью НТТР-отклика.