
- •Введение
- •Несколько слов о книге
- •Глава 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
- •Формирование объектов
Пожалуй, это все, на что можно надеяться при адаптации библиотеки. Перейдем теперь к API портала. Изучая метод handleMouseUp (), можно догадаться об одной из трех команд портала, которые должен иметь компонент портала. При отпускании кнопки мыши вызывается метод saveWindowProp- e r t i e s t ) , записывающий состояние и положение текущего окна. Ниже мы подробно рассмотрим детали этого процесса, а также разберем другие API команд портала.
11.6.3. Задание команд портала
Как обсуждалось выше, наш компонент портала, в первую очередь, является отправителем команд. Отправляемые команды представляют собой запросы Ajax к серверной системе управления порталом. Понятие команд и формальную структуру Command в Ajax мы уже рассматривали в главах 3 и 5. Теперь мы изучим другую возможность использовать данные знания.
Итак, мы организовали в портале поддержку таких команд: регистрация, загрузка и запись настроек. Еще мы собираемся ввести возможность добавления и удаления окон, о которой мы уже упоминали, хотя и не показывали ее полную реализацию. Перечисленные возможности можно представлять как методы нашего портала. Однако, прежде чем мы начнем рассмотрение кода, выполним подготовительную работу, которая поможет нам в локализации изменений. Прежде всего, мы имеем в виду имена самих команд. Давайте определим символы для всех имен команд, чтобы их можно было использовать в любой части компонента. Рассмотрим следующий набор символов:
Portal.LOGIN_ACTION » "login"; Portal.LOAD__SETTINGS_ACTION - "PageLoad"; Portal.SAVE_SETTINGS_ACTION = "UpdateDragWindow"; Portal.ADD_WINDOW_ACTION - "AddWindow"; Portal.DELETE_WINDOW_ACTION - "DeleteWindow";
Хотя используемый язык и не поддерживает напрямую константы, предположим, что, используя договоренность о прописных буквах, можно считать указанные значения постоянными. Мы можем просто провести данные строковые литералы через наш код, но данный подход слишком неаккуратен. При подобном использовании констант наши "магические" строки будут располагаться в одном месте. Если контракт сервера изменится, мы сможем к этому приспособиться. Представим, например, каким образом может измениться контракт сервера (табл. 11.1).
Теперь, когда мы можем обращаться к командам с помощью указанных символов, рассмотрим общий механизм передачи серверу команд управления порталом. Нам потребуется вспомогательный метод, в общем виде отправляющий серверу Ajax-команды портала. Рассмотрим данный контракт использов ания.
myPortal.issuePortalCommand( Portal.SAVE_SETTINGS_ACTION, "settingl=" + settinglValue, "setting2=" + setting2Value, . . . )-"
В данном сценарии мы рассматриваем метод issuePortalCommand(), принимающий в качестве первого аргумента имя команды (например, одну из
Таблица 11.1. Изменения открытого контракта
Изменение контракта сервера |
Требуемое действие |
Переименована команда (например, |
Заменить правую часть оператора присваивания |
PageLoad заменена глагольной |
константы LOAD_SETTINGS_ACTION новым |
формой LoadPage) |
значением. Остальная часть кода не меняется |
Сервер больше не поддерживает |
Удалить контракт и выполнить глобальный поиск |
команду |
всех упоминаний команды. В каждом случае |
|
произвести необходимую модификацию кода |
Сервер поддерживает новую команду |
Добавить константу для этой команды |
|
и использовать ее имя в коде |
наших констант) и переменное число аргументов, соответствующих параметрам, которые ожидает/требует команда. Как и следовало ожидать, параметры имеют точно такую же форму, которая требуется методом sendRequest() объекта net.ContentLoader. Определенный нами метод issuePortalCommand() можно реализовать следующим образом:
issuePortalCommand: function{ commandName ) {
/ / О Получить параметр действия
v a r a c t i o n P a r a m - t h i s . o p t i o n s [ t q u o t e a c t i o n p a r a m t q u o t e ] ; // © Получить суффикс URL
v a r u r l S u f f i x = t h i s . o p t i o n s [ t q u o t e u r l S u f f i x t q u o t e J ; i f ( ' u r l S u f f i x ) u r l S u f f i x = " " ;
v a r u r l = t h i s . b a s e U r l ; var callParms •" [];
if (actionParam){ callParms.push(
//© Применить параметр действия actionParam + "=" + commandName ); }else{
//О Применить суффикс URL
url += "/" + commandName + urlSuffix; } for ( var i = 1 ; i < arguments.length ; i++ )
callParms.push( argumentsfi] ); var ajaxHelper = new
// 0 Создать объект ContentLoader net.ContentLoader( this, url, "POST", [] );
ajaxHelper.sendRequest // 0 Отправить запрос
,apply( ajaxHelper, callParms );
),
Данный метод создает URL, основываясь на конфигурационных опциях, обсуждавшихся в разделе 11.6.1, Если мы установили значение actionParam О, оно будет добавлено к параметрам с помощью POST, передаваемым на сервер ©. Если нет, мы добавим команду к пути URL О, присоединяя суффикс URL, если он указан в опциях ©. Первый аргумент функции — имя команды. Все остальные аргументы рассматриваются как параметры запроса. Затем сформированный URL передается объекту ContentLoader ©, и, как показано в предыдущем примере, отправляется запрос со всеми предоставленными
параметрами ©. Благодаря данному методу все API команд нашего портала будут очень лаконичными . Еще один "бонус" подобного общего метода заключается в том, что мы можем поддерживать новые команды, появляющиеся на сервере, не меняя код клиентской части приложения. А теперь рассмотрим команды, которые мы уже знаем.
регистрация
Напомним, что обработчик событий onclick нашей кнопки регистрации инициирует вызов метода login () страницы, который в свою очередь вызывает указанный выше метод. Функция login (по крайней мере, с точки зрения сервера) представляет собой команду, которую сервер должен обработать, проверив предоставленную пользователем регистрационную информацию, а затем (если эта информация верна) ответив так же, как команда load-page. Учитывая сказанное, рассмотрим реализацию функции login (), показанную в листинге 11.15.
login: function(userName, password) { this.userName = userName; this.password - password;
if ( this.options.messageSpanld ) document.getElementById(
this.options.messageSpanld).innerHTML = "Verifying Credentials";
|
this.issuePortalCommand( Portal.LOGIN_ACTION, |
|
|
}, |
"user=" + this.userName, "pass=" + this.password |
); |
|
|
|
m |
Данный метод помещает сообщение "Verifying Credentials" в элемент span, определяемый настраиваемой опцией t h i s . options .messageSpanld. Затем он отправляет команду login внутреннему коду портала, передавая регистрационную информацию, полученную методом в виде параметров запроса. Всю сложную работу выполняет метод issuePortalCommand{).
Загрузка настроек
Напомним, что функция createPortai () нашей страницы вызывает указанный выше метод для загрузки исходной конфигурации окон портала. Для загрузки настроек страницы применяется метод, который даже проще рассмотренного выше метода регистрации. Это просто удобная интерфейсная оболочка вокруг команды issuePortalCommand{). В качестве единственного своего параметра, используемого сервером для загрузки нужных настроек окон, она передает имя пользователя.
loadPage: function(action) {
this.issuePortalCommand( Portal.LOAD_SETTINGS_ACTION, "user=" + this.userName, "pass=" + this.password ); },
476 Часть IV. Ajax в примерах
Запись настроек
Метод записи настроек также достаточно прост. Напомним, что данный метод вызывается адаптированной библиотекой AjaxWindows.js при наступлении события mouseup и производит запись всех операций перемещения и изменения размеров.
saveWindowProperties: function(id) {
this.issuePortalCommand( 'portal.SAVE_SETTINGS_ACTION, "ref=" + id, "x=" + parselnt(elemWin.style.left), "y=" + parselnt(elemWin.style.top),
»w=" + parselnt(elemWin.style.width),
"h=" + parselnt(elemWin.style.height) ); elemWin = null; },
Добавление и удаление окон
Хотя мы не полностью разработали концепцию добавления и удаления окон (по крайней мере, с точки зрения пользовательского интерфейса, удобного для инициации этих действий), мы можем определить командные методы API, поддерживающие указанные операции.
addWindow: f u n c t i o n ( t i t l e , |
u r l , х, |
у, |
w, |
h) |
{ |
|
|
|
||
t h i s . issuePortalCommand ( |
P o r t a l .ADD__WINDOW_ACTION, |
|||||||||
" t i t l e - " |
+ |
t i t l e , |
" u r l - " |
+ |
u r l , |
"x=" |
+ x, |
|||
" y = " + y, " w = " + w, " h = " + h ) ; }, |
|
|||||||||
deleteWindow: f u n c t i o n ( i d ) |
{ |
|
|
|
|
|
|
|
|
|
v a r d o D e l e t e • |
|
|
|
|
|
|
|
|
|
|
c o n f i r m ( " A r e you |
s u r e |
you |
want |
to |
d e l e t e |
t h i s |
window?"); |
|||
i f ( d o D e l e t e ) t h i s . i s s u e P o r t a l C o m m a n d ( |
|
|
|
|
||||||
Portal.DELETE_WINDOW_ACTION, |
" r e f = " + |
id |
); |
}, |
Данный метод завершает обсуждение программных интерфейсов, требуемых для поддержки команд портала. Рассмотрим теперь обработку Ajax на портале.
11.6.4. Обработке средствами Ajax
Как уже отмечалось, в данном примере мы используем технологию Ajax для обработки ответов. В частности здесь реализуется взаимодействие, ориентированное на сценарии. Описанная технология основана на том, что ожидаемый ответ сервера представляет собой приемлемый код JavaScript. При таком подходе очень желательно, чтобы клиенту для понимания ответа не требовалось выполнять какую-либо сортировку или синтаксический анализ. Ответ вычисляется с помощью метода JavaScript eval (), и в дальнейшем с клиента снимается вся ответственность. Недостаток данного подхода состоит Б ТОМ, что вся ответственность возлагается на сервер, который отвечает за понимание клиентской объектной модели и генерирует синтаксически верный ответ, согласующийся с требованиями языка (JavaScript). Второй недостаток описанного подхода частично устраняется с помощью использования для определения откликов популярной разновидности рассматриваемой технологии — JSON. Существуют определенные серверные библиотеки, помогающие гене-