Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Ajax_v_deystvii.pdf
Скачиваний:
38
Добавлен:
05.03.2016
Размер:
5.83 Mб
Скачать

RSSItemView Result

Рис. 13.18. Окончательный вид класса RSSItemView

Причина, по которой мы дали представлению метод tostring, заключается в том, что это позволяет нам взаимозаменяемо использовать экземпляр представления и генерируемую им строку HTML. Например, мы можем присвоить значение атрибуту innerHTML элемента, равное классу представления, и далее будет использоваться строковое представление (сгенерированный HTML-файл). Например, ниже приводится код, присваивающий сгенерированный HTML-документ представления атрибуту innerHTML элемента div с идентификатором contentDiv.

var rssItemView -

new RSSItemView( anRSSFeed, 0, 0, 5 );

$('contentDiv1 ).

innerHTML = rssItemView;

(Помните, $() — это функция из библиотеки Prototype, позволяющая извлекать элементы DOM по их идентификаторам.) Теперь, когда у нас есть хороший набор абстракций для классов модели и представления, рассмотрим контроллер приложения, который свяжет воедино все эти компоненты.

13.7.3. Контроллер приложения

Класс RSSReader будет объединять функции, связанные с манипуляцией классами модели и представления, координируя все действия, соотнесенные с приложением чтения RSS-лент. Напомним, что интерфейс приложения реализован в виде слайд-шоу лент, когда каждая статья будет отображаться на определенный период времени, а затем постепенно переходить в следующую

556 Часть IV. Ajax в примерах

статью. Приложение имеет кнопки, позволяющие переходить на следующую и предыдущую статьи, а также кнопки паузы/возобновления слайд-шоу. Наконец, имеются раскрывающийся список и кнопка добавления новых лент к исходному набору. Ниже перечислены пять необходимых категорий поведения, которые должны быть реализованы в приложении.

1.Построение объектов и первоначальная настройка.

2.Реализация слайд-шоу.

3.Создание эффектов перехода.

4.Загрузка RSS-лент средствами Ajax.

5.Обновление пользовательского интерфейса.

Чтобы уменьшить сложность и объем кода, требуемого для выполнения всех этих задач, используем библиотеку Prototype (позволяющую получить синтаксическую лаконичность), библиотеку Rico (обеспечивающую функциональные возможности, требуемые для эффектов перехода) и объект net.ContentLoader (предлагающий поддержку Ajax). Итак, начнем с первоначального построения и настройки.

Построение и настройка

Фактически разработка всех наших предыдущих компонентов начиналась с конструкторов. Будем верны традиции и сейчас — начнем с определения конструктора, которым в данном случае является простой метод, задающий первоначальные значения по умолчанию для какого-то состояния компонента и, как в других примерах, устанавливающего конфигурационные опции и выполняющего инициализацию. Учитывая это, конструктор RSSReader определяется так, как показано в листинге 13.27.

Листинг 13.27.* Конструктор RSSReader ;

^ Х ^ В

RSSReader = Class.create*);

 

RSSReader.prototype = {

 

initialize: function( readerld, options )

{

// О Установить значения по умолчанию

 

t h i s . i d = r e a d e r l d ;

 

t h i s . t r a n s i t i o n T i m e r = n u l l ;

 

t h i s . p a u s e d = f a l s e ;

 

t h i s . v i s i b l e L a y e r = 0;

 

// © Настроить опции конфигурации

 

t h i s . s e t O p t i o n s ( o p t i o n s ) ;

 

// © Инициализировать поведение

 

t h i s . s t a r t { ) ;

 

) ,

 

Приведенный выше конструктор принимает два аргумента: идентификатор и объект опций. Идентификатор используется как уникальная метка приложения и добавляется как префикс к идентификаторам кнопок, кото-

Глава 13. Создание приложений Ajax, не использующих сервер 557

рые он должен будет определить в структуре DOM. Реализация сказанного будет показана ниже, в методе applyButtonBehaviors. Первое, что делает конструктор О, — это устанавливает значения по умолчанию для состояния. Далее (как и в большинстве других проектов) используется объект опций ©, с помощью которого задаются конфигурационные опции компонента. Для этого применяется метод setoptions. Наконец, в методе star t © происходит все, что требуется для активизации компонента. Далее мы сначала рассмотрим конфигурацию, а затем перейдем к поведению.

За конфигурацию отвечает идиома setoptions, показанная в листинге 13.28. Давайте разберемся с реализацией setoptions и обсудим опции конфигурации.

Листинг 13.28. Метод setoptions

j j j l

setOptions: function(options)

{

 

t h i s . o p t i o n s = {

 

 

slideTransitionDelay: 7000,

 

fadeDuration

: 300,

 

 

errorHTML :

'<hr/>Error retrievin g content.<br/>'

 

}.extend(options);

 

ь

 

 

ш

 

 

 

В приведенном методе setOptions указаны свойства приложения, которые мы решили сделать настраиваемыми. Свойство slideTransitionDelay задает число миллисекунд, в течение которых один "слайд" статьи виден до перехода во второй. Свойство fadeDuration задает время в миллисекундах, требуемое для полного затухания "слайда" (а следовательно, для "проявления" следующего "слайда"). Наконец, при возникновении ошибки в процессе загрузки RSS-ленты используется свойство errorHTML, задающее HTMLдокумент, отображаемый в качестве сообщения об ошибке. В приведенном коде также показаны значения данных свойств по умолчанию, которые сохраняются, если пользователь явно не укажет другие. Здесь стоит отметить, что компонент ожидает, что ему в качестве исходного набора лент для обработки будет передано свойство rssFeeds объекта опций. Поскольку мы в действительности не можем предложить разумное значение по умолчанию для этой величины, в методе setoptions она не определяется. Подразумевается, что приложение будет создано с объектом опций, подобным показанному ниже.

var options =

{

rssFeeds: [

"http://radio.javaranch.com/news/rss.xml",

 

"http://radio.j avaranch.com/pascarello/rss.xml",

 

"http://radio.javaranch.com/bear/rss.xml",

 

"http://radio.javaranch.com/lasse/rss.xml" ] };

var rssReader

= new RSSReader{'rssReader', options );

Итак, мы довольно быстро закодировали создание и настройку конфигурации. Теперь можно переходить к магическому методу start, который и запустит весь процесс. В следующих разделах мы кратко рассмотрим этот метод и посмотрим, к чему приводит его использование. Начнем, как обычно, с реализации, показанной в листинге 13.29.

558 Часть IV. Ajax в примерах

Листинг 13.29. Метод start :ЯНННИНИННННННННН|

start: function() { this.applyButtonBehaviors();

new Effect.FadeTo( this.getLayer(1), 0.0, 1, 1, {} ); this.loadRSSFeed(0,true);

this.startSlideShow{false);

},

 

щ

Метод applyButtonBehaviors настраивает обработчики событий onclick для кнопок перехода к предыдущей/последующей статье, паузы/возобновления, а также кнопки добавления новой ленты. Этот метод мы рассмотрим следующим. Эффект затенения, представленный во второй строке, вызывает постепенное исчезновение с экрана видимого элемента div, чтобы его можно было скрыть при загрузке первого слайда. Обратите внимание на то, что

вданной реализации мы не кодируем эффект самостоятельно, а используем готовое решение из библиотеки Rico, что уменьшает объем кода, который требуется писать, отлаживать и сопровождать. Метод loadRSSFeed инициализирует запрос Ajax на загрузку в первую ленту, а метод startSlideShow запускает таймер со значением slideTransitionDelay, инициируя таким образом слайд-шоу. Подробнее метод loadRSSFeed будет рассмотрен в разделе "'Загрузка RSS-лент с помощью Ajax", а метод startSlideShow — в разделе 'Реализация слайд-шоу". На этом мы, как и обещали, завершаем обсуждение построения и настройки, рассмотрев упомянутый в листинге 13.29 метод applyButtonBehaviors.

Как отмечалось ранее, метод applyButtonBehaviors подключает кнопки

кметодам, реализующим их поведение. Реализация этого метода показана

влистинге 13.30.

Листинг 13.30. Метод applyButtonBehaviors .

applyButtonBehaviors: function!)

{

 

 

 

S(this.id + '__prevBtn') .onclick

=

this.previous.bind(this) ;

 

$ ( t h i s . i d + ' _ n e x t B t n ' ) . o n c l i c k • t h i s . n e x t . b i n d ( t h i s ) ;

 

$ ( t h i s . i d + ' _ p a u s e B t n ' ) . o n c l i c k - t h i s . p a u s e . b i n d ( t h i s ) ;

 

$ ( t h i s . i d + ' _ a d d B t n ' ) - o n c l i c k = t h i s . a d d F e e d . b i n d ( t h i s ) ;

_ ±

 

 

 

.

Здесь, пожалуй, стоит напомнить, какой синтаксис и какие идиомы мы используем. В частности, мы задействовали пару синтаксических элементов библиотеки Prototype. Во-первых, это метод $, который можно рассматривать как вызов document .getElementByld. Во-вторых, метод bind неявно создает для нас замыкание, так что обработчик событий onclick для каждой кнопки может вызывать методы первого класса нашего компонента. Рассмотрим теперь детали реализации.

Реализация открывает неявный контракт между компонентом и HTMLразметкой приложения. Компонент создается с идентификатором, который хранится в атрибуте this . id . Позже этот идентификатор используется как префикс для нахождения различных элементов в разметке. В данном случае предполагается, что идентификаторы кнопок -— это метки, переданные в

Глава 13 Создание приложений Ajax, не использующих сервер 559

Таблица 13.4. Атрибуты контроллера

Атрибут

Описание

t h i s . currentFeed

Экземпляр RSSFeed, в текущий момент загруженный в память

t h i s . feedlndex

Номер ленты, показываемой в текущий момент. Является

 

индексом массива t h i s . o p t i o n s .rssFeeds

t h i s . itemlndex

Номер статьи, показываемой в текущий момент Является

 

индексом массива статей объекта RSSFeed, показываемого

 

в текущий момент

конструктор, к которым добавлено _prevBtn, _nextBtn, _pauseBtn и addBtn. Чтобы проиллюстрировать сказанное, рассмотрим приведенный выше код. В качестве идентификатора здесь используется rssReader, а компонент ожидает, что кнопки будут заданы следующим образом:

<input type="button" id="rssReader_prevBtn" value=" « " /> <input type="button" id="rssReader_pauseBtn" value=" I I " /> <input type="button" id="rssReader_nextBtn" value=" » " /> <input type="button" id="rssReader_addBtn" value="Add Feed" />

Видно, что контроллер RSSReader начинает приобретать форму, и теперь мы можем рассмотреть детали реализации слайд-шоу.

Реализация слайд-шоу

Теперь самое время поговорить об изменении семантики по сравнению

спредыдущей версией сценария. Изначально мы загружали все RSS-ленты

впамять в момент запуска, а затем просто формировали переходы между внутренними представлениями лент. Это было просто, но масштабируемость такого решения вызывала определенные сомнения. Если мы регулярно прочитываем десятки или сотни RSS-лент, содержащих десятки статей, предварительная загрузка их всех была бы чересчур сильной нагрузкой на браузер. Поэтому в разделе реструктуризации мы попытаемся добиться нормальной масштабируемости и производительности приложения, так изменив семантику, чтобы за раз в память загружалась единственная RSS-лента. Все статьи RSSItems одной ленты побывают в памяти, однако в каждый отдельный момент времени в памяти будет присутствовать только один элемент RSSFeed. За то, на каком этапе находится слайд-шоу в процессе отображения содержимого, отвечают три атрибута контроллера, описанных в табл. 13.4.

Разобравшись с семантикой, переходим к навигации. Если мы планируем реализовать навигацию по всем статьям (элементам item) всех RSS-лент, то должны изучить несколько методов. Рассмотрим для начала пару методов перехода к предыдущей/следующей статье. Механизм перехода требуется не только для реализации явных событий, связанных с кнопками, но и для пассивного чтения при просмотре автоматизированного слайд-шоу.

Итак, рассмотрим пару булевых методов, сообщающих читателю, может ли он переходить вперед или назад. Реализация этих двух методов hasPrevious и hasNext показана в листинге 13.31.

560 Часть IV Ajax в примерах

 

... ЛИСТИЙГ 13.31. Пара методов has Preyious/has Next

: ,

hasPrevious: function() {

 

return ! (this.feedlndex == 0 && this .iteinlndex == 0);

 

},

 

hasNext: function() {

return !(this.feedlndex == this.options.rssFeeds.length - 1 && this.itemlndex == this.currentFeed.items.length - 1);

}, щ

С помощью представленных методов определяется, доступен ли предыдущий или последующий слайд. При указанной реализации предыдущий "слайд" будет доступен в том случае, если в текущий момент приложение демонстрирует не первую статью первой ленты, а следующие "слайд" доступен, если мы читаем не последнюю статью последней ленты.

Рассмотрим теперь, что такое переход на предыдущую и последующую статью ленты. Начнем с метода previous (), показанного в листинге 13.32.

I Листинг 13.32. Метод previous ()Г ^ 1 Д | Д

previous: function() {

if ( !this.hasPrevious() ) return;

var requiresLoad = this.itemlndex == 0;

this.fadeOut( this.visibleLayer, Prototype.emptyFunction ); this.visibleLayer = {this.visibleLayer + 1 ) % 2;

if { requiresLoad )

this.loadRSSFeedf this.feedlndex - 1, false ); else

setTimeout( this.previousPartTwo.bind(this), parselnt (this. options. fadeDuration/4) ). ;

Ь

previousPartTwo: function()

{

 

this.itemlndex'—; this.updateView();

Ь

 

m

Первое, что мы сделали при написании метода previous (), — поместили в самом его начале защитное условие. Если предыдущей статьи не существует, метод previous () ничего не делает. Если значение requiresLoad равно true, тогда содержимое RSS-статьи, на которую планируется переход, еще не загружено. Если мы находимся на первой статье ленты и переходим назад, требуется загрузка предыдущей ленты. Метод затухания, подробно рассмотренный в разделе "Эффекты перехода", постепенно ослабляет видимый слой. Дальнейшие действия этого метода зависят от того, требуется ли перед отображением загрузка какого-либо содержимого. Если да, то мы инициируем загрузку необходимых данных посредством метода loadRSSFeed(). Первым параметром данного метода является номер загружаемой ленты, вторым — булево значение, указывающее направление: true — вперед, false (как в данном случае) — назад. Если же содержимое статьи уже загружено, то мы вызываем previousPartTwo() после паузы, равной одной четвертой общей длительности fadeDuration. Во "второй части" данного метода про-

Глава 13 Создание приложений Ajax, не использующих сервер 561

сто обновляется свойство itemlndex и вызывается функция updateView (), приводящая к затуханию соответствующего слайда.

Ну что, запутались? Ладно, объясняем нормальным языком: если текст, который нужно отобразить, не загружен, его загрузка начинается немедленно, что приводит к обновлению пользовательского интерфейса сразу же после поступления данных. Время, которое требуется на прием данных, используется для естественной реализации затухания! С другой стороны, если содержимое уже загружено {т.е. мы переходим на другую статью загруженной ленты), то мы вводим искусственную задержку (четверть времени затухания) перед проявлением следующей статьи. Довольно хитро, правда?

Метод next (), показанный в листинге 13.33, представляет собой реализацию алгоритма, обратного к приведенному выше.

next:

function{}

{

 

if

(

ithis.hasNext()

) return;

var

requiresLoad =

 

 

this.itemlndex == (this.currentFeed.items.length - 1);

 

this.fadeOut( this.visibleLayer, Prototype.emptyFunction ) ;

 

this.visibleLayer = (this.visibleLayer + 1 ) % 2;

if

(

requiresLoad >

 

 

this.loadRSSFeed{

this.feedlndex + 1, true );

else

 

 

 

setTimeout(

this.nextPartTwo.bind(this),

 

 

 

parselnt(this.options.fadeDuration/4) );

Ь

nextPartTwo: function() {

 

this.itemlndex++; this.updateView();

 

Ь

m

Выглядит знакомо? Метод next () использует противоположную логику индексирования, а во всем остальном идентичен приведенному выше алгоритму. Обратите внимание на то, что при каждом переходе пара методов previous () /next {) переключает видимый слой с одного слайда на другой с помощью такого выражения:

this.visibleLayer = (this.visibleLayer + 1) % 2;

Таким образом, мы сообщаем коду, который в конечном счете обновит пользовательский интерфейс (после загрузки содержимого или явного вызова функции updateView ()), на какой слой помещать результат. Напомним, что контекстная область приложения содержит HTML-разметку, которые выглядит примерно следующим образом:

<!— Контекстная область —>

<div class="content" id="rssReader_content"> <div class="layerl">Layer 0</div>

<div class="layer2">Layer K/div> </div>

Здесь visibleLayer — целочисленное свойство, отслеживающее, в какой элемент div требуется помещать содержимое. Индекс 0 указывает, что при об-

562 Часть IV. Ajax в примерах

новлении пользовательского интерфейса содержимое должно помещаться на слой 0. Значение 1 приводит к вставке данных на слой 1.

Подведем итог. У нас есть методы, с помощью которых реализуется переход вперед/назад по набору статей, и мы можем их использовать для создания методов слайд-шоу. Рассмотрим их В листинге 13.34 показаны метод startSlideShow, который, как вы помните, вызывался из метода s t a r t ( ) , и дополняющий его метод nextSlide ().

ЛистинМ3.34. Методы навигации по слайд-шоу

startSlideShow: function(resume) {

var delay = resume ? 1 : this.options.slideTransitionDelay; this.transitionTimer = setTimeout{this.nextSlide.bind(this),

delay);

К

 

nextSlide: function{) {

 

if ( this.hasNextO

)

 

this.next();

 

 

else

 

 

this.loadRSSFeed(0, true);

 

this.transitionTimer = setTimeout{

 

 

this.nextSlide.bind(this),

),

 

this.options.slideTransitionDelay ) ;

 

ш

Приведенный метод startSlideShow вызывает nextSlide после заданной задержки. В зависимости от того, возобновляем ли мы слайд-шоу после паузы или нет, задержка равна либо slideTransitionDelay, либо одной миллисекунде (практически мгновенно). Таким же простым является и метод nextSlide, вызывающий метод next() при наличии следующего слайда. Если текущий слайд является последним в данной ленте, вызывается loadRSSFeed(0,true) и мы переходим на начало ленты. После этого просто устанавливается таймер и процесс повторяется. Все очень легко!

Мы уже говорили, что слайд-шоу можно приостановить с помощью кнопки паузы, однако соответствующий метод еще не был реализован. Восполним этот пробел и создадим метод, показанный в листинге 13.35.

riv*i к i n i i O . O J . i v ( С 1чЛЦ u a U o c

"•явчвИнЯиИИН^ВДИв^вРИ^1 *i "•• -•;••••••'. • •Щ^шШЯШЩшШШШШЯШЯШЩШЯ^Ш^ШВЯШШЯШЩШШШШШШшШШШШШШШШШШШШШШШШШШ

pause: function() { if ( this.paused )

this.startSlideShow(true); else

clearTimeout( this.transitionTimer ); this.paused = !this.paused;

- ±

-

Метод pause переключает состояние паузы нашего слайд-шоу. Текущее состояние отслеживается с помощью булева атрибута this.paused. Если слайд-шоу уже приостановлено, метод pause вызывает функцию s t a r t - SlideShow, в качестве значения свойства resume передавая значение true;

Глава 13 Создание приложений Ajax, не использующих сервер 563

в противном случае метод обнуляет атрибут transitionTimer, подавляющий все переходы между слайдами до тех пор, пока кнопка паузы не будет нажата повторно.

Чтобы завершить реализацию слайд-шоу, нужно реализовать функцию, которая бы позволила добавлять в этот процесс новые RSS-ленты. Изучая код функции applyButtonBehaviors(), мы видели, что кнопка добавления новой ленты вызывает метод addFeed. Давайте реализуем этот метод (см. листинг 13.36) и будем считать, что мы сделали все для получения управляемого слайд-шоу.

Листинг 13.36. Метод addFeed

addFeed: function() {

var selectBox = $(this.id + '_newFeeds'); var feedToAdd = selectBox.options[

selectBox.selectedlndex ].value; this.options.rssFeeds.push(feedToAdd);

},

m

Приведенный выше метод также зависит от неявного контракта с HTMLразметкой с позиции договоренности об именовании списка дополнительных RSS-лент. Идентификатор данного списка должен быть идентификатором приложения с суффиксом _newsFeeds. Метод addFeed просто принимает выбранную RSS-ленту в списке и добавляет ее в конец массива t h i s . options. rssFeeds. Больше ничего не требуется! Ну как вам это нравится — добавление новых функциональных возможностей требует всего пары строк кода!

На этом мы завершаем разработку методов, связанных со слайд-шоу. Теперь рассмотрим кратко методы, поддерживающие эффекты перехода.

Эффекты перехода

В нашем коде упоминалось несколько методов, поддерживающих затухающие переходы между слайдами. Давайте рассмотрим эти переходы подробнее. Итак, прежде всего мы определим пару методов fadeln() и fadeOutO, как показано в листинге 13 37.

Листинг 13.37. Пара методов fadeln< )/fadeOut() |:[•:'

; = | | | 1 | И

fadeln: function( layer, onComplete )

{

 

 

 

this.fadeTo( 0.9999, layer, onComplete );

 

 

fadeOut: function( layer, onComplete )

{

 

 

 

this.fadeTo( 0.0001, layer, onComplete );

 

 

ь

 

 

M

 

 

 

 

Оба указанных метода делегируют свои полномочия методу fadeToO (он разобран ниже). Они передают методу fadeToO параметр прозрачности — значение между 0 и 1, где 0 соответствует полностью невидимому слою, а 1 — полностью видимому. В некоторых браузерах значение, очень

564 Часть IV. Ajax в примерах

Таблица 13.5. Параметры Effect . FadeTo

Параметр

Описание

t h i s . getLayer ( l a y e r )

Затухающий элемент DOM

п

Степень прозрачности (значение между 0 и 1)

t h i s . o p t i o n s . f adeDuration

Время затухания

12

Число промежуточных этапов

{complete: onComplete}

Обратный вызов, запускаемый после завершения

близкое к 1 (но не точно 1), похоже, немного уменьшает мерцание изображения, поэтому вместо 1 мы будем использовать величину 0,9999. Чтобы указать, какой слой должен затухать, мы передаем функции номер слоя (0 или 1). Наконец, последний аргумент — это функция, обеспечивающая перехват обратного вызова сразу после завершения перехода. Реализация метода fadeTo() показана в листинге 13.38.

fadeTo: function( n, layer, onComplete ) { new Effect.FadeTo( this.getLayer(layer),

n,

this.options.fadeDuration,

12,

{complete: onComplete J

);

 

Ь

 

л

Из-за внезапного приступа лени или в качестве продуманного методологического приема мы решили не изобретать заново эффект перехода. Вместо этого мы используем метод Effect. FadeTo из библиотеки Rico, который и выполнит всю работу. Параметры Effect.FadeTo приведены в табл. 3.5.

Чтобы получить элемент div, соответствующий затухающему слою содержимого, мы использовали вспомогательный метод getLayerO, показанный в листинге 13.39.

Листинг 13.39. Метод aetLaverO _ | Ц ^ Н ^ ^ ^ ^ Д | Н ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ И в getLayer: function(n) {

var contentArea - $(this.id+'_content');

var children = contentArea.childNodes; var j = 0; for ( var i = 0 ; i < children.length ; i++ } {

if ( children[i].tagName && children[i].tagName.toLowerCase() == 'div' ) { if ( j -~ n ) return children[i];

}

}

return null;

Глава 13. Создание приложений Ajax, не использующих сервер 565

Данный метод находит область содержимого, предполагая, что ее идентификатор построен как идентификатор приложения с дописанным в конец значением _content. Найдя элемент содержимого, метод прослеживает его потомков и находит n-й дочерний элемент div.

Все, закончили и с переходами. Теперь рассмотрим тему загрузки RSSлент посредством магии Ajax.

Загрузка RSS-лент с помощью Ajax

Мы уделили довольно много внимания темам создания компонента и обеспечения богатой семантики слайд-шоу, а также необычных технологий DHTML для переходов между слайдами. Однако если все это не создано на основе инфраструктуры Ajax, гордиться совершенно нечем. Все дело в том, что идеальный пользовательский интерфейс может обеспечить только Ajax со своей масштабируемостью и индивидуальным извлечением данных плюс сложный DHTML со своими богатыми возможностями и эффектами. Говорить об этом можно долго, так что лучше все лее рассмотрим требуемую инфраструктуру Ajax, начав с метода, приведенного в листинге 13.40 и выполняющего загрузку RSS-ленты в память.

loadRSSFeed: function{feedlndex,

forward) {

 

 

thxs.feedlndex = feedlndex;

 

 

 

 

this.iteralndex = forward ? 0

:

"last";

 

new net.ContentLoader(this,

 

 

 

 

this.options.rssFeeds[feedlndex],

 

 

"GET",

[]

).sendRequest();

) ,

 

 

я

Данный метод с помощью давно знакомого объекта net.ContentLoader формирует запрос Ajax, передавая в качестве параметра URL RSS-ленты, заданный в массиве this.options.rssFeeds. Параметр forward представляет собой булеву величину, указывающую, что мы загружаем (или не загружаем) новое содержимое вследствие перехода на следующую статью. Далее, согласно этой информации, обновляется свойство itemlndex. Обратите внимание на то, что, если мы переходим назад, itemlndex получает значение, равное last, а не целочисленной величине. Такое решение объясняется тем, что свойство itemlndex должно указывать индекс последней статьи предыдущей RSS-ленты. Единственная проблема заключается в том, что мы не знаем, сколько статей в ленте, поскольку она еще не загружена.

Напомним, что согласно неявному контракту с net.ContentLoader нам требуются методы ajaxUpdate и handleError. Разберем вначале метод aj axUpdate, показанный в листинге 13.41, и посмотрим, как с помощью данной реализации разрешить нашу дилемму индексирования.

566 Часть IV. Ajax в примерах

Листинг 13.41. Метод *1а^Аз^ШШШШЯИШШШШШШШШ

aj axUpdate: function(request) { if ( window.netscape Sfi

window.netscape.security.PrivilegeManager.enablePrivilege)

netscape.security.PrivilegeManager.enablePrivilege( 'UniversalBrowserRead') ;

this.currentFeed = RSSFeed.parseXML(request.responseXML.documentElement);

if ( this-itemlndex == "last" )

this.itemlndex = this.currentFeed.items.length - 1; this.updateView();

__L

 

ш

Метод ajaxUpdate начинает с проверки того, что он работает в среде, предлагающей PrivilegeManager. Если да, тогда он затребует привилегию UniversalBrowserRead. Как отмечалось выше, это сделано для того, чтобы наше приложение могло запускаться локально в браузерах Mozilla.

В приведенном коде this.currentFeed — это экземпляр объекта модели RSSFeed, определенный в разделе "Модель". Он соответствует одной ленте RSSFeed, загруженной в память после отклика Ajax. Если значение this.itemlndex равно l a s t (такое значение устанавливается методом loadRSSFeed при возврате к предыдущей статье), свойство itemlndex обновляется в соответствии с реальным числом статей в новой загруженной ленте RSSFeed. Наконец, в ответ на вызов updateView() обновляется пользовательский интерфейс.

Не забывайте, что нам еще нужно определить метод handleError (не только потому, что это подразумевает контракт с net.ContentLoader, но и потому, что нам действительно нужно какое-то средство обработки ошибок). Если ленту RSS загрузить не удается, мы предоставляем сообщение, показанное в реализации handleError. Разумеется, возможны (и желательны) более сложные реализации.

handleError: function(request) {

this.getLayer(this.visibleLayer).innerHTML = this.options.errorHTML;

Ь

Итак, мы реализовали все необходимые возможности Ajax в приложении RSSReader, остался последний штрих — написать пару методов, обновляющих пользовательских интерфейс.

Обработка пользовательского интерфейса

Напомним, что классы модели и представления мы создавали так, чтобы облегчить себе реструктуризацию кода приложения. Теперь, переходя к контроллеру, отвечающему за обновление пользовательского интерфейса, мы можем считать, что сделана почти все работа. Это действительно так. Рассмотрим, например, метод updateView () (листинг 13.42), на который мы неоднократно ссылались в ходе предыдущей работы.

Соседние файлы в предмете [НЕСОРТИРОВАННОЕ]