Электронная библиотека книг Александра Фролова и Григория Фролова.
Shop2You.ru Создайте свой интернет-магазин
Библиотека
Братьев
Фроловых
[Назад] [Содержание] [Дальше]

Создание приложений с базами данных для Интернета и интрасетей: практическое руководство

(С) Александр Вячеславович Фролов, Григорий Вячеславович Фролов, 2000

2. Сценарии в страницах HTML и DHTML

2. Сценарии в страницах HTML и DHTML. 1

Объектная модель браузера Microsoft Internet Explorer 2

Применение сценариев для создания интерфейса пользователя. 5

Начальная регистрация пользователя. 5

Ввод календарных дат. 8

Загрузка новой страницы в окно браузера. 16

Перекодирование содержимого полей форм.. 17

Отключение кэширования страниц. 17

Модальные и немодальные диалоговые панели. 18

Модальные диалоговые панели. 18

Вывод информационных сообщений. 18

Сообщение с выбором одной из двух возможностей. 20

Диалоговая панель на базе документа HTML. 22

Немодальные диалоговые панели. 26

Работа с фреймами. 28

Файл описания фреймов. 28

Параметры тега <FRAMESET>. 29

Параметры оператора <FRAME>.. 29

Взаимодействие между фреймами. 30

Десятично-шестнадцатеричный преобразователь. 30

Одновременная замена нескольких документов HTML в окнах разных фреймов. 34

Использование растровых изображений. 37

Растровое изображение как объект. 38

Динамическая замена растровых изображений. 39

Изменение внешнего вида графических ссылок. 39

Создание анимационных изображений. 40

Ожидание загрузки всех изображений. 42

Наложение фильтра на графическое изображение. 43

Применение Cookie в клиентских сценариях. 45

Выполнение основных операций с Cookie. 46

Создание Cookie. 46

Создание Cookie расширением сервера Web. 46

Создание Cookie в клиентском сценарии. 47

Получение значения Cookie. 48

Изменение значения параметра Cookie. 50

Удаление Cookie. 50

Ограничения на использование Cookie. 50

Примеры использования Cookie. 50

Фиксация повторных посещений страницы.. 50

Записная книжка Cookie Notepad. 53

Настройка параметров документа HTML. 55

Настройка браузера для работы с Cookie. 58

Отладка клиентских сценариев. 59

Прежде чем Вы начнете использовать страницы ASP и непосредственно работать с базой данных, Вам необходимо освоить основные приемы создания документов HTML и DHTML с клиентскими сценариями на языках JavaScript и VB Script. Мы предполагаем, что Вы уже владеете этими языками программирования, поэтому не стали подробно излагать их в книге. Однако краткую справочную информацию по JavaScript и VB Script мы поместили в приложение к книге. При необходимости Вы можете к ней обратиться.

Объектная модель браузера Microsoft Internet Explorer

Для выполнения каких-либо действий над страницами HTML, загруженными в окно браузера, клиентский сценарий должен обращаться к интерфейсам объектов сценария, доступных в браузере.

Схематически объектная модель браузера Microsoft Internet Explorer представлена на рис. 2-1. Вы можете обращаться к этому рисунку при составлении клиентских сценариев для указанного браузера.

Рис. 2-1. Объектная модель браузера Microsoft Internet Explorer

Объект window соответствует окну браузера Microsoft Internet Explorer. Он содержит такие объекты, как document, navigator, frames, history, location, screen и event. В свою очередь, объект document может содержать объекты links, anchor, forms и другие, а объект forms — объект elements.

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

В таблице 2-1 Вы найдете описание некоторых объектов браузера Microsoft Internet Explorer.

Таблица 2-1. Объекты браузера Microsoft Internet Explorer

Объект

Описание

window

Представляет собой сам браузер и считается корневым в иерархии объектов

document

Представляет собой страницу HTML, загруженную в окно браузера. В зависимости от содержимого страницы этот объект может включать в себя другие объекты, размещенные на странице — ссылки, локальные ссылки, формы и т. д.

navigator

Позволяет извлечь информацию о браузере — название браузера и номер его версии. Полезен в тех случаях, когда сценарий должен учесть особенности браузера

frames

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

history

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

location

Содержит адрес URL страницы, загруженной в окно браузера. Изменяя свойства этого объекта, можно загрузить в окно браузера новую страницу

scripts

Представляет сценарии, расположенные в загруженной странице HTML

event

Содержит информацию о возникающих событиях

links

Представляет собой массив всех ссылок, расположенных в загруженной странице HTML

anchora

Содержит массив всех локальных анкеров внутри страницы HTML

forms

Представляет формы, размещенные внутри страницы HTML. Мы будем использовать этот объект для доступа к полям и другим элементам управления, расположенным в формах

elements

Содержит массив всех элементов управления, расположенных в текущей странице HTML

 

В зависимости от содержимого страницы HTML, загруженной в окно браузера, сценариям становятся доступными и другие объекты, например images и applets.

Заметим, что браузер Netscape Navigator имеет другой набор объектов и другие связи между ними.

Окно браузера Netscape Navigator соответствует объекту window, содержащему такие объекты как Frame, document, Location и History. Объект document, представляющий собой документ HTML, загруженный в окно браузера, содержит в свою очередь объекты Form, Layer, Link, Image, Area, Anchor, Applet и Plugin.

Если документ HTML, загруженный в браузер Netscape Navigator, содержит формы, то соответствующие объекты Form могут включать в себя объекты, созданные для элементов форм, таких, как переключатели, поля ввода текстовой информации, списки и т. д. Это объекты Text, Textarea, Password, Hidden, Submit, Reset, Radio, Checkbox, Button, Select и FileUpload. Объект Select, представляющий собой список, содержит объекты Option, создаваемые для строк списка.

Более подробную информацию об объектах браузера Netscape Navigator Вы найдете в Интернете по адресу http://developer.netscape.com/doc/manuals, а также в литературе, список которой приведен в конце нашей книги.

В качестве простого примера обращения сценариев JavaScript к объекту Navigator мы приведем листинг небольшого документа HTML, расположенного в файле BrowserInfo.html (листинг 2-1).

Листинг 2-1. Файл ch01/BrowserInfo.html

Обращаясь к свойству браузера navigator.appName мы можем определить название браузера:

document.writeln("<TR><TD>Название браузера:</TD><TD>"
  + navigator.appName.bold() + "</TD></TR>");

Аналогичным образом мы можем определить другие параметры браузера и системы, такие как версия, тип процессора, язык и т. д.:

document.writeln("<TR><TD>Кодовое имя браузера:</TD><TD>"
  + navigator.appCodeName.bold() + "</TD></TR>");
document.writeln("<TR><TD>Версия браузера:</TD><TD>"
  + navigator.appVersion.bold() + "</TD></TR>");
document.writeln("<TR><TD>Агент HTTP:</TD><TD>"
  + navigator.userAgent.bold() + "</TD></TR>");
document.writeln("<TR><TD>Тип процессора:</TD><TD>"
  + navigator.cpuClass.bold() + "</TD></TR>");
document.writeln("<TR><TD>Язык системы:</TD><TD>"
  + navigator.systemLanguage.bold() + "</TD></TR>");
document.writeln("<TR><TD>Язык пользователя:</TD><TD>"
  + navigator.userLanguage.bold() + "</TD></TR>");
document.writeln("<TR><TD>Вторая цифра версии браузера:</TD><TD>"
  + navigator.appMinorVersion.bold() + "</TD></TR>");

При загрузке этого документа в окно браузера Вы увидите сведения о версии браузера. На рис. 2-2 и 2-3 мы показали, что получится при загрузке документа BrowserInfo.html в браузер Microsoft Internet Explorer 5.0 и в браузер Netscape 4.51.

Рис. 2-2. Информация о браузере Microsoft Internet Explorer

Обратите внимание, что браузер Netscape не показал нескольких свойств, с которыми легко справился Microsoft Internet Explorer. Это свойства navigator.cpuClass, navigator.systemLanguage, navigator.userLanguage и navigator.appMinorVersion, появившиеся в последних версиях браузера Microsoft Internet Explorer. Даже на таком простейшем примере видно, что сценарии JavaScript могут работать по-разному в разных браузерах.

Рис. 2-3. Информация о браузере Netscape

Далее мы расскажем о применении различных объектов описанной выше модели браузера.

Применение сценариев для создания интерфейса пользователя

При создании Интернет-магазина мы используем диалоговый интерфейс, основанный на применении форм и фреймов. Если Вы знакомы с языком HTML, то должны знать, что формы создаются с помощью тегов <FORM>. Внутри формы могут располагаться текстовые поля ввода, списки, переключатели, кнопки и другие объекты.

Как выполняется обработка данных, введенных пользователем в форме?

Тут возможны два варианта. Первый таков: данные, введенные пользователем при помощи формы, сразу переправляются на сервер для проверки и обработки. Во втором случае эти данные предварительно проверяются клиентским сценарием.

У каждого из этих двух способов есть свои преимущества и недостатки.

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

При применении второго способа введенные пользователем данные проверяются локально. Это улучшает время ответа системы, но иногда приводит к возникновению проблемы совместимости использованного Вами сценария и браузера пользователя.

В том случае, когда Вы ставите перед собой задачу обеспечить максимальную доступность магазина для посетителей с любыми браузерами, постарайтесь полностью исключить применение клиентских сценариев. Однако при разработке административных приложений, предназначенных для управления работой магазина (или любого другого приложения Web) использование клиентских сценариев для проверки форм вполне допустимо.

Начальная регистрация пользователя

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

В этом разделе мы расскажем о том, как выполнить предварительную проверку регистрационных данных, введенных пользователем, перед их отправкой на сервер. Сам процесс отправки мы рассмотрим позже, в разделе, посвященном страницам ASP.

В качестве примера мы подготовили небольшую форму, предназначенную для регистрации посетителей магазина (рис. 2-4).

Рис. 2-4. Форма регистрации посетителей магазина

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

Некоторые поля в этой форме отмечены как обязательные для заполнения. Перед тем как отправлять введенные данные на сервер для записи в базу данных покупателей, было бы неплохо проверить правильность заполнения полей формы. Для этой цели мы используем сценарий JavaScript, который:

·       проверяет, заполнил ли посетитель обязательные поля, отмеченные в форме символом «*»;

·       сравнивает пароль с подтверждением пароля — они должны совпадать;

·       проверяет e-mail, который должен содержать по крайней мере один символ «@» и одну точку.

В качестве тренировки Вы можете добавить строку для проверки номера телефона — в нем допустимы пробелы, символы «-» и цифры. Чтобы отличить цифры от других символов, используйте функцию isDigit.

Исходный текст документа HTML с формой и сценарием JavaScript показан в листинге 2-2. Этот документ был создан при помощи Microsoft FrontPage. Клиентские сценарии редактировались в среде Microsoft InterDev 6.0.

Листинг 2-2. Файл ch01/RegisterForm.html

В документе имеется форма с полями ввода регистрационной информации:

<form name="RegForm" action="http://www.YourServer.YourDomain/YourCGI.cgi" metod="post">
  <table border="0" cellPadding="0" cellSpacing="0" width="385" height="340">
     <tr><td valign="top" align="left" colspan="2">
<b>Введите имя, отчество и фамилию:</b> <font color="#FF0000">*</font></td></tr>
. . .
<select name="country" size="1">
     <option selected value="Россия">Россия</option>
     <option value="Беларусь">Беларусь</option>
     <option value="Чехословакия">Чехословакия</option>
     <option value="Германия">Германия</option>
     <option value="Греция">Греция</option>
     <option value="Польша">Польша</option>
     <option value="США">США</option>
     <option value="Украина">Украина</option>
     <option value="Швейцария">Швейцария</option>
</select></td></tr>
. . .
<input type="button" onClick="checkForm();"
       value="
Регистрация" name="B1"></td>
       <td valign="top" align="left">
<input type="reset" value="
Отмена" name="B2"></td></tr>
  </table>
</form>

Обращаем Ваше внимание на следующий фрагмент этого документа:

<input type="button" onClick="checkForm();"
  value="
Регистрация" name="B1"></td>

Когда посетитель щелкнет мышью кнопку Регистрация, будет вызвана функция checkForm, выполняющая проверку полей формы:

function checkForm()
{
  if(  document.RegForm.name.value == "" ||
       document.RegForm.addr.value == "" ||
       document.RegForm.email.value == "" ||
       document.RegForm.password.value == "")
  {
     alert("Вы заполнили не все обязательные поля формы");
     return;
  }

  if(document.RegForm.password.value != document.RegForm.passwordchk.value)
  {
     alert("Ошибка при подтверждении пароля");
     return;
  }
  if(!mailAddressIsValid(document.RegForm.email.value))
  {
     alert("Ошибка в адресе E-Mail");
     return;
  }
  var sRegInfo="";
  sRegInfo = "Сведения о регистрации:\n" +
  "Имя: " + document.RegForm.name.value +
  "\nСтрана: " + document.RegForm.country.options[document.RegForm.country.selectedIndex].value +
  " (" + document.RegForm.country.selectedIndex + ")" +
  "\nПочтовый адрес: " + document.RegForm.addr.value +
  "\nE-Mail: " + document.RegForm.email.value +
  "\nТелефон: " + document.RegForm.phone.value +
  "\nПароль: " + document.RegForm.password.value;
  alert(sRegInfo);

  document.RegForm.submit();
}

Если при вводе допущены ошибки, функция отобразит на экране пользователя сообщение об ошибке, а если все правильно — отправит данные на сервер Web для обработки программой CGI.

Доступ к полям формы выполняется при помощи объекта document, например:

document.RegForm.name.value

Здесь мы ссылаемся на имя формы (RegForm), на имя поля (name), а также на свойство value, содержащее значение этого поля.

Для проверки правильности ввода почтового адреса мы применили функцию mailAddressIsValid:

function mailAddressIsValid(mailAddress)
{
  var atPresent=false;
  var dotPresent=false;
  for(var i=0; i < mailAddress.length;i++)
  {
     var c=mailAddress.substring(i,i+1);
     if(c == "@")
       atPresent=true;
     if(c == ".")
       dotPresent=true;
  }
  if(atPresent == true && dotPresent == true)
     return true;
  else
     return false;
}

Если все данные введены правильно, мы отображаем их на экране функцией alert и затем отправляем на сервер Web. Для отправки данных формы применяется метод submit, как это показано ниже:

document.RegForm.submit();

Для удобства эта строка выделена в листинге 2-2 жирным шрифтом.

Такое действие эквивалентно щелчку кнопки типа Submit, применяемой в обычных формах для отправки данных.

Ввод календарных дат

Еще одна задача, часто возникающая при разработке приложений Web, это ввод календарных дат и диапазонов календарных дат. Например, Вам может потребоваться список клиентов, зарегистрировавшихся в определенный период времени или список платежных транзакций, выполненных за определенный период времени.

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

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

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

И, наконец, при записи даты в базу данных или при использовании дат в запросах SQL Вам придется преобразовать ее в фиксированный формат, с которым сможет работать программа SQL.

С учетом сказанного выше, на наш взгляд, лучше всего применять для ввода дат такие органы управления, как списки. Предварительно в них следует указать возможные значения дат.

Нам понравилось, как решена проблема ввода диапазона дат Максимом Синевым из компании Spektrum Web Development (http://www.spektrum.org.ru). На рис. 2-5 мы показали форму с календарями, предназначенную для просмотра списка покупателей по дате регистрации.

В этой форме мы применили (в немного измененном виде) разработанное им решение для ввода диапазона дат, основанное на применение средств DHTML и сценариев JavaScript. Заметим, что в силу использования объектной модели браузера Microsoft Internet Explorer, этот метод не пригоден для работы с другими браузерами. Однако данное обстоятельство не имеет решающего значения при создании приложений Web для интрасетей и административных приложений Web в Интернете.

Как пользоваться формой, показанной на рис. 2-5?

Все операции выполняются мышью. Щелкая ссылки вида <<< и >>>, Вы можете изменять год в начальной и конечной дате. В данном случае выполняется поиск пользователей, зарегистрировавшихся в период с 1998 до 2000 года.

Щелкая название месяца и календарной даты в левом и правом календаре, Вы установите период времени с точностью до одного дня. В нашем случае начальная дата — 3 марта 1998 года, а конечная — 29 февраля 2000 года. Для наглядности названия месяцев и календарные даты выделены в окне формы желтым цветом.

Для того чтобы запустить поиск, достаточно щелкнуть мышью ссылку Поиск.

Рис. 2-5. Форма для просмотра списка покупателей по дате регистрации

Если снять флажок у переключателя искать по дате регистрации:, календари в форме исчезнут, причем это произойдет мгновенно, без повторной загрузки формы с сервера Web (рис. 2-6).

После его повторного включения календарь также быстро появится на экране вновь. Операции рисования календаря, его сокрытия и повторного отображения выполняются с применением сценариев JavaScript и объектной модели DHTML.

Форма, предназначенная для определения параметров просмотра, определена следующим образом:

<form method="POST" id="SearchForm">
  <table border="0" cellpadding="5" cellspacing="0">
     <tr>
       <td><table cellspacing="5">
          <tr>
            <td><small><strong>Имя, отчество или фамилия покупателя:</strong></small></td>
            <td><input type="text" name="LOGNAME" id="LogName" size="25"></td></tr><tr>
            <td><small><strong>Адрес E-Mail:</strong></small></td>
            <td><input type="text" name="EMAIL" id="CEMail" size="25"></td></tr><tr>
            <td><small><input type="checkbox" name="USEDATE" id="UseDataCheckBox"
            onClick="hidecalendar();"
            TITLE="Выключите для игнорирования даты регистрации"
            value="ON"></small><strong>искать по дате регистрации<big>:</big></strong></td><td></td></tr>
       </table>
       </td>
     </tr>
  </table>
</form>

Полный иИсходный текст документа HTML, содержащего эту форму, мы привели в листинге 2-3.

Листинг 2-3. Файл ch01/CustomerSearch.html

Рис. 2-6. Теперь дата регистрации не учитывается

Изучая этот листинг, прежде всего обратите внимание на то, что он ссылается на файл calendar.js:

<html>
<head><script LANGUAGE="javascript" SRC="calendar.js"></script>
<title></title>
</head>
. . .

 В нем хранится большинство функций сценария JavaScript, обеспечивающих работу календарей. Полный текст файла calendar.js Вы найдете в листинге 2-4.

Листинг 2-4. Файл ch01/calendar.js

Теперь мы расскажем о том, как устроен документ HTML CustomerSearch.html (листинг 2-3). При внимательном изучении видно, что помимо всего прочего он содержит две пустые таблицы для календарей:

<table border="0" cellpadding="0" cellspacing="0" id="calendarTable">
  <tr align="middle" bgcolor="#ffffcc">
     <td><h2>Начальная дата</h2>
     </td>
     <td><h2>Конечная дата</h2>
     </td>
  </tr>
  <tr valign="top">
     <td><table border="0" cellpadding="0" cellspacing="5">
       <tr>
          <td align="left" ID="FromPrev"></td>
          <td align="middle"><b ID="FromYear"></b></td>
          <td align="right" ID="FromNext"></td>
       </tr><tr><td colspan="3"><hr width="100%"> </td></tr>
       <tr valign="top">
          <td ID="FromMonths1"></td>
          <td ID="FromDays" valign="top"></td>
          <td ID="FromMonths2"></td>
       </tr>
     </table>
     </td>
     <td><table border="0" cellpadding="0" cellspacing="5">
       <tr>
          <td align="left" ID="ToPrev"></td>
          <td align="middle"><b ID="ToYear"></b></td>
          <td align="right" ID="ToNext"></td>
       </tr><tr><td colspan="3"><hr width="100%"> </td></tr>
       <tr valign="top">
          <td ID="ToMonths1"></td>
          <td ID="ToDays" valign="top"></td>
          <td ID="ToMonths2"></td></tr>
     </table>
     </td>
  </tr>
  <tr bgcolor="#ffffcc">
     <td><strong><big><big><big><a href="javascript:go();">Поиск</a></big></big></big></strong></td>
     <td></td>
  </tr>
</table>

Заполнение этих таблиц осуществляется при помощи сценария JavaScript.

Как это происходит?

В теле тега <BODY> мы определили обработчик события onLoad, вызывающий функцию buildmap:

<body onload="buildmap()">

Вот исходный текст функции buildmap:

function buildmap()
{
  var today = new Date();
  byear = today.getFullYear();
  bmonth = today.getMonth()+1;
  bday = 1;
  eyear = today.getFullYear();
  emonth = today.getMonth()+1;
  eday = today.getDate();
  refby();
  fillfmonths();
  fillfdays();
  refey();
  filltmonths();
  filltdays();
  document.all.UseDataCheckBox.checked=true;
}

Данная функция вызывается при завершении загрузки документа HTML в окно браузера. В ее задачу входит определение текущей даты и ее составляющих — номера года, месяца и числа. Для этой цели вызываются функции getFullYear, getMonth и getDate.

Далее для заполнения полей таблицы начальной даты функция buildmap последовательно вызывает функции refby, fillfmonths и fillfdays:

function refby()
{
  FromYear.innerText=byear.toString();

  if(byear>1901) FromPrev.innerHTML='<a   href="javascript:prevbyear();">&lt;&lt;&lt;</a>';
  else FromPrev.innerHTML="&lt;&lt;&lt;";

  if(byear<eyear) FromNext.innerHTML='<a href="javascript:nextbyear();">&gt;&gt;&gt;</a>';
  else FromNext.innerHTML="&gt;&gt;&gt;"
}

function fillfmonths()
{
if(byear==eyear && bmonth>=emonth) {
     emonth=bmonth;
     if(bday>=eday) eday=bday;
  }
var month_selected=false;
var line="<table border=0 cellpadding=0 cellspacing=0>";
for(var j=0; j<6; j++) {
  if(j+1==bmonth) month_selected=true;
  if(byear==eyear && j==emonth) month_selected=false;
  if(month_selected) {
     line=line+'<tr><td bgcolor="#FFFFCC">';
  } else {
     line=line+'<tr><td bgcolor="#FFFFFF">';
  }
  if(j+1==bmonth) {
     line=line+months[j];
  } else {
     line=line+'<a href="javascript:selfmonth('+j.toString()+');">'+ months[j] +'</a>';
  }
  line=line+'</td></tr>';
  }
line=line+'</table>';
FromMonths1.innerHTML=line;

var line="<table border=0 cellpadding=0 cellspacing=0>";
for(var j=6; j<12; j++) {
  if(j+1==bmonth) month_selected=true;
  if(byear==eyear && j==emonth) month_selected=false;
  if(month_selected) {
     line=line+'<tr><td bgcolor="#FFFFCC">';
  } else {
     line=line+'<tr><td bgcolor="#FFFFFF">';
  }
  if(j+1==bmonth) {
     line=line+months[j];
  } else {
     line=line+'<a href="javascript:selfmonth('+j.toString()+');">'+ months[j] +'</a>';
  }
  line=line+'</td></tr>';
  }
line=line+'</table>';
FromMonths2.innerHTML=line;
}

function fillfdays()
{
var from_day=firstDay(byear,bmonth);
var max_day=monthDuration(byear, bmonth);
var cur_day=0;
if(max_day<bday) bday=max_day;

if(byear==eyear && bmonth>=emonth) {
  emonth=bmonth;
  if(bday>eday) eday=bday;
  }

var line="<table border=0 cellpadding=0 cellspacing=0>";

line=line+'<tr><td colspan=9 align="center" bgcolor="#CCCCEE" width="*"><b>'+months[bmonth-1]+'</b></td></tr>';

var markday=false;

for(var i=0; i<6 && from_day+max_day>cur_day; i++) {
  line=line+'<tr>';
  line=line+'<td bgcolor="#CCCCEE" width="8%">&nbsp;</td>';
  for(var j=0; j<7; j++) {
     if((cur_day-from_day)+1==bday) markday=true;
     if(from_day+max_day==cur_day)  markday=false;
     if(cur_day-from_day==eday && (byear==eyear && bmonth==emonth)) markday=false;
     if(markday) {
       line=line+'<td align="center" bgcolor="#FFFFCC" width="13%">';
       }
     else {
       line=line+'<td align="center" width="13%">';
       }
     var printdate=(cur_day>=from_day && from_day+max_day>cur_day);
     var makeref=(printdate && (cur_day-from_day)+1!=bday);
     if(makeref) line=line+'<a href="javascript:selfday('+(cur_day-from_day+1).toString()+');">';
  else line=line+'<b>';
     if(printdate) line=line+(cur_day-from_day+1).toString();
     if(makeref) line=line+'</a>';
  else line=line+'</b>';
    
     line=line+'</td>';
     cur_day++;
     }
  line=line+'<td bgcolor="#CCCCEE" width="*">&nbsp;</td>';
  line=line+'</tr>';
  }

line=line+'</tr><td bgcolor="#CCCCEE" width="8%">&nbsp;</td>';
for(var j=0; j<7; j++) {
  line=line+'<td bgcolor="#CCCCEE" width="12%">';
  line=line+daysOfWeek[j] ;
  line=line+'</font>&nbsp;&nbsp;</td>';
  }
line=line+'<td bgcolor="#CCCCEE" width="*">&nbsp;</td>';
line=line+'</tr>';

line=line+'</table>';
FromDays.innerHTML=line;
}

Для заполнения полей таблицы конечной даты вызываются функции refey, filltmonths и filltdays.

Эти функции интенсивно используют свойство innerText различных объектов таблиц календарей, заданных в тексте HTML их идентификаторами ID:

function refby()
{
  FromYear.innerText=byear.toString();

  if(byear>1901) FromPrev.innerHTML='<a   href="javascript:prevbyear();">&lt;&lt;&lt;</a>';
  else FromPrev.innerHTML="&lt;&lt;&lt;";

  if(byear<eyear) FromNext.innerHTML='<a href="javascript:nextbyear();">&gt;&gt;&gt;</a>';
  else FromNext.innerHTML="&gt;&gt;&gt;"
}

Присваивая новое значение свойству innerText, сценарий JavaScript способен динамически изменять содержимое тегов страницы, отображаемой в окне браузера. На этой возможности DHTML и строится вся работа данного сценария.

Последнее действие, выполняемое функцией buildmap, это активизация переключателя искать по дате регистрации:. Именно этот режим используется в форме по умолчанию:

document.all.UseDataCheckBox.checked=true;

В файле calendar.js содержится определение функции buildmapExона позволяет выполнить предварительную установку календарей для заданного диапазона дат:

function buildmapEx(FY, FM, FD, TY, TM, TD, DateCheck)
{
  byear = FY; bmonth = FM; bday = FD;
  eyear = TY; emonth = TM; eday = TD;
  refby();
  fillfmonths();
  f
illfdays();
  refey();
  filltmonths();
  filltdays();

  if(DateCheck == "true")
     document.all.UseDataCheckBox.checked=true;
  else
  {
     document.all.UseDataCheckBox.checked=false;
 
     oCurrentNode=document.getElementById("calendarTable");
     sCalendarPreserve = oCurrentNode.innerHTML;
    
     oNewNode = document.createElement("<table>");
     oCurrentNode.replaceNode(oNewNode);
     oNewNode.outerHTML =
  "<table id='TableReplaced'><tr align='middle' bgcolor='#ffffcc'><td><h1>&nbsp;<a href='javascript:go();'>Поиск</a>&nbsp;</h1></td></tr></table>";
  }
}

Еще одна функция, представляющая интерес, определена в файле CustomerSearch.html (листинг 2-3). Это функция hidecalendar, предназначенная для того, чтобы отображать и убирать с экрана календари при изменении состояния переключателя искать по дате регистрации:. Вот ее исходный текст:

var sCalendarPreserve;
var oCurrentNode;
var oCalendarTable;
var oPNode;
var oNewNode;

function hidecalendar()
{
  if(document.all.UseDataCheckBox.checked == false)
  {
     oCurrentNode=document.getElementById("calendarTable");
     sCalendarPreserve = oCurrentNode.innerHTML;
    
     oNewNode = document.createElement("<table>");
     oCurrentNode.replaceNode(oNewNode);
     oNewNode.outerHTML =
"<table id='TableReplaced' border='0' cellpadding='5' cellspacing='0'><tr align='middle' bgcolor='#ffffcc'><td><h1>&nbsp;<a href='javascript:go();'>
Поиск</a>&nbsp;</h1></td></tr></table>";

     document.all.UseDataCheckBox.checked=false;
  }
  else
  {
     oCurrentNode=document.getElementById("TableReplaced");
     oPNode = document.createElement("<table>");
     oCurrentNode.replaceNode(oPNode);
     oPNode.outerHTML = '<table border="0" cellpadding="0" cellspacing="0" id="calendarTable">'
      + sCalendarPreserve + '</table>';
      
     document.all.UseDataCheckBox.checked=true;
  }
}

Функция hidecalendar вызывается по событию onClick, когда пользователь щелкает этот переключатель. Если флажок снят, функция hidecalendar сохраняет в переменной sCalendarPreserve содержимое кода HTML таблицы календарей с идентификатором calendarTable:

var sCalendarPreserve;
var oCurrentNode;
var oCalendarTable;
var oPNode;
var oNewNode;

if(document.all.UseDataCheckBox.checked == false)
{
  oCurrentNode=document.getElementById("calendarTable");
  sCalendarPreserve = oCurrentNode.innerHTML;
  . . .

Далее функция hidecalendar создает новую пустую таблицу, сохраняя ссылку на соответствующий объект в переменной oNewNode, и замещает таблицу с календарями этой пустой таблицей:

oNewNode = document.createElement("<table>");
oCurrentNode.replaceNode(oNewNode);

На следующем этапе мы замещаем содержимое таблицы, изменяя свойство outerHTML, и выключаем переключатель:

oNewNode.outerHTML =
"<table id='TableReplaced' border='0' cellpadding='5' cellspacing='0'><tr align='middle' bgcolor='#ffffcc'><td><h1>&nbsp;<a href='javascript:go();'>Поиск</a>&nbsp;</h1></td></tr></table>";

document.all.UseDataCheckBox.checked=false;

Новое содержимое таблицы представляет собой одну строку ссылки в виде слова Поиск. При выборе этой или аналогичной ссылки в исходной таблице с календарями управление передается функции go, выполняющей переход к странице поиска покупателей.

Когда пользователь вновь активизирует переключатель искать по дате регистрации:, функция hidecalendar возвращает таблицу календарей в исходное состояние:

oCurrentNode=document.getElementById("TableReplaced");
oPNode = document.createElement("<table>");
oCurrentNode.replaceNode(oPNode);
oPNode.outerHTML = '<table border="0" cellpadding="0" cellspacing="0" id="calendarTable">' + sCalendarPreserve + '</table>';

Что же касается функции go, то мы рассмотрим ее в следующем разделе.

Загрузка новой страницы в окно браузера

Сценарий JavaScript способен загрузить в окно браузера (или в окно фрейма, если документ содержит фреймы) новый документ HTML, заданный адресом URL. В частности, если текущий документ содержит форму запроса к базе данных, сценарий JavaScript может загрузить в текущее окно браузера документ HTML (или ASP) с результатами обработки этого запроса.

Именно так и работает функция go из примера, приведенного в листинге 2-3:

function go()
{
  . . .
  window.location.href = "GetSearchResults.asp?DATECHECK=" +
     sUseDataCheckBox+"&FY=" + byear.toString()+
     "&FM="+bmonth.toString()+
     "&FD="+bday.toString()+"&TY="+eyear.toString() +
     "&TM="+emonth.toString()+ "&TD="+eday.toString()+
     "&LOGNAME="+sLogName+"&EMAIL="+sEMail+
     "&FRCE="+Math.random().toString();
}

Здесь в свойство href объекта window.location записывается адрес страницы ASP, с названием GetSearchResults.asp. Эта страница расположена в том же каталоге, что и вызывающий ее документ HTML, поэтому вместо полного пути мы указали только имя файла.

После имени файла проставлен разделяющий символ «?» и достаточно длинная строка параметров, передаваемая странице ASP. Эта строка содержит начальную и конечную дату, имя пользователя, адрес его электронной почты и еще один параметр с именем FRCE, о котором мы пока умолчим. Строка параметров будет прочитана и обработана серверным сценарием, встроенным в страницу GetSearchResults.asp. Подробнее об этом мы расскажем в следующей главе.

Если Вы не собираетесь выполнять предварительную обработку формы при помощи клиентского сценария, адрес данной страницы ASP нужно указать в параметре ACTION тега <FORM>, как это делается при вызове расширений CGI и ISAPI.

Перекодирование содержимого полей форм

Чтобы данные из полей формы были корректно переданы программам CGI, ISAPI или странице ASP, они должны иметь так называемую кодировку URL. В этой кодировке символы пробелов заменяются знаком «+», а для представления кодов управляющих и некоторых других символов применяется последовательность вида «%xx», где символы «xx» представляют собой шестнадцатеричный код исходного символа в виде двух символов ASCII.

Если Вы передаете программам CGI, ISAPI или странице ASP параметры из клиентского сценария, преобразование текстовых строк в кодировку URL придется выполнить явным образом. В сценариях JavaScript это легко осуществить при помощи функции escape. Вот, например, как это делается в функции go из только что рассмотренного примера:

var sLogName=escape(document.all.SearchForm.LogName.value);
var sEMail=escape(document.all.SearchForm.CEMail.value);

Если же вызов программ расширения сервера Web или страниц ASP выполняется через параметр ACTION тега <FORM>, преобразование происходит автоматически.

Отключение кэширования страниц

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

К сожалению, механизм кэширования страниц иногда вызывает проблемы в приложениях Web, создающих страницы динамически при помощи программ CGI, ISAPI или средств ASP.

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

Как отменить кэширование страниц?

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

Первый достаточно известный способ заключается в применении тега <META> с параметром HTTP-EQUIV=Expires, расположенного внутри заголовка документа <HEAD>. Этот параметр указывает дату, начиная с которой содержимое документа считается устаревшим и он подлежит перезагрузке. Например, Вы можете использовать тег <META> следующего вида:

<META HTTP-EQUIV=Expires CONTENT=Tue, 02 Jan 1996 01:00:00 GMT>

К сожалению, этот простой способ работает не всегда. Более надежный способ, который можно применить при загрузке динамически создаваемых страниц с помощью клиентских сценариев, заключается в добавлении фиктивного параметра со случайным значением. Мы применили этот способ в функции go, полный текст которой приведен в листинге 2-3:

window.location.href = "GetSearchResults.asp?DATECHECK=" +
  sUseDataCheckBox+"&FY=" + byear.toString()+
  . . .
 
"&FRCE="+Math.random().toString();

Параметр с именем FRCE представляет собой случайное число, полученное от функции Math.random и преобразованное в текстовую строку функцией toString.

Другие способы отключения кэширования страниц будут описаны в главе, посвященной серверным сценариям ASP.

Модальные и немодальные диалоговые панели

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

Заметим, что описанные здесь средства лучше применять для создания административных приложений, доступ к которым осуществляется не всеми пользователями Интернета, а только сотрудниками Вашей фирмы. Это связано с тем, что посетители могут отключить в их браузере возможность работы клиентских сценариев.

Модальные диалоговые панели

Модальными называются такие диалоговые панели, которые должны быть закрыты для продолжения работы приложения. Например, если приложение выводит на экран модальную диалоговую панель с сообщением об ошибке, работа приложения будет приостановлена до тех пор, пока пользователь не прочитает сообщение и не щелкнет кнопку OK.

Для создания окон модальных диалоговых панелей серверный сценарий использует методы, перечисленные в таблице 2-2.

Таблица 2-2. Методы для создания окон модальных диалоговых панелей

Метод

Параметры и описание

alert

alert(sMsg)

Простейшая диалоговая панель с текстовым сообщением sMsg и кнопкой OK

confirm

confirm(sMsg)

Диалоговая панель с текстовым сообщением sMsg и двумя кнопками OK и Cancel. В зависимости от того, какой кнопкой Вы завершили работу панели, метод возвращает значение true (соответствует кнопке OK) или false (соответствует кнопке Cancel)

prompt

prompt(sMsg [,sDefaultMsg])

Панель для запроса у пользователя одной текстовой строки. В окне панели отображается сообщение sMsg. Если указан необязательный параметр sDefaultMsg, то соответствующая строка появляется в поле ввода

showModalDialog

showModalDialog(sURL [, params [, features]])

Этим методом можно создавать сложные диалоговые панели на базе документов HTML. Параметр sURL определяет адрес URL такого документа. Необязательный параметр params позволяет передавать в диалоговую панель произвольный набор параметров, а параметр features (также необязательный) определяет внешний вид окна панели. Метод showModalDialog, в отличие от метода prompt, позволяет запрашивать у пользователя произвольную информацию, а не только одну строку

Теперь мы рассмотрим несколько практических примеров применения перечисленных выше методов.

Вывод информационных сообщений

В первом примере мы покажем, как выводить на экран обычные текстовые сообщения.

На рис. 2-7 изображено окно с двумя кнопками — Вход и Выход. Если щелкнуть кнопку Вход, на экране появится приветственное сообщение, показанное на рис. 2-8, а если щелкнуть кнопку Выход — сообщение, показанное на рис. 2-9.

Рис. 2-7. Панель для демонстрации способа выдачи сообщений

Исходный текст соответствующего документа HTML представлен в листинге 2-5.

Листинг 2-5. Файл ch02/MessageBox.html

Как видно из этого исходного текста, в документе имеется таблица с двумя кнопками:

<table border="0" width="27%" cellpadding="2">
  <tr><td width="22%">
  <input type="button" onClick="msgBox('Добро пожаловать!');" value="Вход" name="B1">
  </td><td width="78%">
  <input type="reset" onClick="msgBox('До свидания!\nЗаходите еще!');"   value=" Выход" name="B2"></td>  </tr>
</table>

Для каждой из этих кнопок мы определили обработчик события onClick, задача которого заключается в вызове функции msgBox.

Эта функция просто обращается к методу alert, передавая ему в качестве параметра строку сообщения:

function msgBox(sMessage)
{
  alert(sMessage);
}

Рис. 2-8. Сообщение, появляющееся в результате щелчка кнопки Вход

Рис. 2-9. Сообщение, появляющееся в результате щелчка кнопки Выход

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

Сообщение с выбором одной из двух возможностей

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

Все эти задачи решают с помощью методов confirm и prompt. Покажем, как это сделать на конкретном примере.

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

Рис. 2-10. Документ HTML, предназначенный для удаления пользователей

Если Вы щелкнете кнопку Удалить пользователя, клиентский сценарий запросит имя «жертвы» (рис. 2-11). При этом он вызовет метод prompt.

Рис. 2-11. Ввод имени удаляемого пользователя

Чтобы удалить пользователя, Вам надо ввести его имя и нажать кнопку OK. В реальных приложениях имена пользователей хранятся в базе данных. О том, как удалять пользователей из базы данных, Вы узнаете позже.

Перед удалением пользователя наш сценарий выводит на экран сообщение, показанное на рис. 2-12. Оно отображается с применением метода confirm.

Рис. 2-12. Запрос подтверждения на удаление пользователя

Здесь отображается имя удаляемого пользователя и предлагается подтвердить выполнение этой операции.

Если щелкнуть кнопку OK, на экране появится сообщение об успешном удалении пользователя с заданным именем (рис. 2-13). Оно отображается методом alert.

Рис. 2-13. Сообщение об успешном удалении пользователя

Исходный текст документа HTML со сценарием, выполняющим описанные выше действия, Вы найдете в листинге 2-6.

Листинг 2-6. Файл ch02/OtherModalMessageBox.html

Когда пользователь щелкает кнопку Удалить пользователя, управление получает функция deleteUser:

function deleteUser()
{
  var sUserName="";
  sUserName=prompt("Введите имя пользователя,\nудаляемого из базы данных покупателей", "<temp user>");
  if(sUserName != null && sUserName != "")
  {
     if(confirm("Вы действительно будете удалять пользователя\n" + sUserName + "\nиз базы данных покупателей?") == true)
     {
       // Удаление пользователя
       // . . .

       msgBox("Пользователь с именем\n" + sUserName + "\nуспешно удален из базы данных покупателей");
     }
  }
}

Она вызывает метод prompt и указывает ему в качестве имени удаляемого пользователя значение по умолчанию — «<temp user>».

Если пользователь завершает работу диалоговой панели кнопкой OK, метод prompt возвращает строку имени пользователя. После щелчка кнопки Cancel метод prompt возвращает значение null. Есть и еще один способ — пользователь вводит кнопкой OK пустую строку. При этом метод prompt также возвращает пустую строку.

После вызова метода prompt функция deleteUser проверяет возвращенное этим методом значение. Если это не пустая строка и не значение null, сценарий выполняет действия по удалению пользователя. В нашем случае эти действия фактически не реализуются, но Вы можете добавить свой код в то место сценария, которое выделено строкой комментария.

Когда удаление пользователя завершается удачей, функция deleteUser выводит на экран сообщение об этом, вызывая функцию msgBox:

function msgBox(sMessage)
{
  alert(sMessage);
}

Диалоговая панель на базе документа HTML

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

Средствами метода showModalDialog Ваш клиентский сценарий может организовать вывод документов HTML с формой ввода на экран, получение и предварительную обработку введенной информации.

Например, в документе HTML на рис. 2-14 имеется кнопка, предназначенная для регистрации новых книг (наряду с кнопками регистрации других новых товаров).

Рис. 2-14. Документ HTML для регистрации новых товаров

Если Вы щелкнете эту кнопку, на экране появится модальная диалоговая панель регистрации новых книг, содержащая форму ввода с полями различных типов (рис. 2-15).

Рис. 2-15. Документ HTML с формой регистрации новых книг

Заполнив поля в этой форме, Вы можете зарегистрировать книгу в базе данных, щелкнув кнопку Добавить в базу данных, либо отказаться от регистрации при помощи кнопки Отменить регистрацию. После этого окно с формой исчезнет с экрана.

В случае успешной регистрации на экране появится сообщение, содержащее текст из всех полей формы (рис. 2-16).

Рис. 2-16. Просмотр информации о зарегистрированной книге

Если же регистрация отменена, Вы вновь вернетесь к документу HTML, показанному на рис. 2-14.

Теперь обратимся к исходному тексту клиентского сценария, выполняющего все перечисленные выше действия (листинги 2-7 и 2-8).

Листинг 2-7. Файл ch02/ModalRegisterDialog.html

В листинге 2-7 приведен исходный текст документа HTML с кнопкой запуска регистрации. Данная кнопка расположена в ячейке таблицы:

<table border="0" width="27%" cellpadding="2">
  <tr><td width="22%">
  <input type="button" onClick="registerNewBook();"
     value="Зарегистрировать новую книгу" name="B1"></td></tr>
</table>

Щелчок этой кнопки вызывает функцию registerNewBook, выполняющую отображение модельной диалоговой панели регистрации, прием из полей этой панели введенной информации и отображение ее на экране:

function registerNewBook()
{
  var regFields = new Array();
  regFields = window.showModalDialog("ModalRegisterForm.html",
    "Регистрация книги",
     "dialogWidth:35em; dialogHeight:22em; resizable=yes");

  if(regFields["Return"] == "OK")
  {
     var sBookInfo = "Название: " + regFields["Title"] +
       "\nАвтор: " + regFields["Author"]  +
       "\nАннотация: " + regFields["Annotation"] +
       "\nИздатель: " + regFields["Publisher"];
     alert(sBookInfo);
  }
}

Как работает эта функция?

Прежде всего, она создает массив regFields для сохранения значений из полей формы регистрации:

var regFields = new Array();

В этот массив будет записано значение, возвращенное методом showModalDialog, после того как пользователь завершит работу с модальной диалоговой панелью:

regFields = window.showModalDialog("ModalRegisterForm.html",
  "Регистрация книги",
  "dialogWidth:35em; dialogHeight:22em; resizable=yes");

В качестве первого параметра мы передаем методу showModalDialog адрес URL документа с формой ModalRegisterForm.html. В нашем случае этот документ лежит в том же каталоге, что и вызывающий его документ ModalRegisterDialog.html, поэтому вместо полного или относительного адреса URL мы ограничимся именем файла.

Через второй параметр мы передаем текстовую строку, которая будет использована в диалоговой панели как заголовок формы. Заметим, что Вы можете передать панели не только одно значение, а целый массив. Это полезно, например, для начальной инициализации полей формы значениями по умолчанию.

И, наконец, третий параметр формы определяет ширину и высоту окна, в котором будет отображена панель, а также диапазоны изменения размеров этого окна пользователем (эта возможность доступна только при использовании браузера Microsoft Internet Explorer 5.0 или более новой версии).

Один из элементов возвращаемого массива — Return определяет, добавил ли пользователь новую книгу в базу данных кнопкой Добавить в базу данных или отказался от выполнения это операции, щелкнув кнопку Отменить регистрацию. Следующий фрагмент кода позволяет определить, какой кнопкой была завершена работа с диалоговой панелью:

if(regFields["Return"] == "OK")
{
  . . .
}

Если панель закрыта кнопкой Добавить в базу данных, соответствующий сценарий (размещенный в файле ModalRegisterForm.html) записывает в элемент массива Return строку «OK», а если Отменить регистрацию — строку «Cancel».

После успешной регистрации функция registerNewBook получает содержимое всех полей формы регистрации, обращаясь к соответствующим элементам массива по именам, и формирует итоговую строку для отображения на экране методом alert:

var sBookInfo = "Название: " + regFields["Title"] +
  "\nАвтор: " + regFields["Author"]  +
  "\nАннотация: " + regFields["Annotation"] +
  "\nИздатель: " + regFields["Publisher"];
alert(sBookInfo);

Теперь мы рассмотрим исходный текст документа HTML с формой регистрации, который находится в листинге 2-8.

Листинг 2-8. Файл ch02/ModalRegisterForm.html

Помимо полей для ввода сведений о книге, в форме регистрации имеется таблица с кнопками:

<table width="497">
  <tr><td width="273" valign="top" align="left">
     <input type="button" onClick="addBook();"
       value="Добавить в базу данных" name="B1"></td>
     <td width="216">
     <input type="reset" onClick="addCancel();"
       value="Отменить регистрацию" name="B2"></td></tr>
</table>

Когда пользователь щелкает кнопку Добавить в базу данных, управление передается функции addBook, а когда кнопку Отменить регистрацию — функции addCancel.

Сначала мы рассмотрим функцию addBook:

function addBook()
{
  formFields["Title"]=document.RegForm("Title").value;
  formFields["Author"]=document.RegForm("Author").value;
  formFields["Annotation"]=document.RegForm("Annotation").value;
  formFields["Publisher"]=document.RegForm("Publisher").value;
  formFields["Return"]="OK";

  window.returnValue = formFields;
  event.returnValue=false;
  window.close();
}

Ее задача заключается в заполнении массива formFields, определенном в документе ModalRegisterForm.html следующим образом:

var formFields = new Array;

Обращаясь последовательно ко всем полям формы, функция addBook формирует содержимое массива formFields:

formFields["Title"]=document.RegForm("Title").value;
formFields["Author"]=document.RegForm("Author").value;
formFields["Annotation"]=document.RegForm("Annotation").value;
formFields["Publisher"]=document.RegForm("Publisher").value;

Дополнительно в элемент массива Return функция addBook записывает строку «OK», которая срабатывает при завершении работы диалоговой панели кнопкой Добавить в базу данных:

formFields["Return"]="OK";

Дальнейшие действия функции addBook показаны ниже:

window.returnValue = formFields;
event.returnValue=false;
window.close();

Здесь мы сохраняем заполненный массив в свойстве window.returnValue, записываем значение false в свойство event.returnValue и закрываем окно диалоговой панели, вызывая метод window.close. Изменение значения event.returnValue позволяет не возвращать объект event (это происходит по умолчанию).

Что же касается функции addCancel, вызываемой щелчком кнопки Отменить регистрацию, то она записывает в массив formFields только одно значение с именем Return и возвращает это значение аналогично функции addBook:

function addCancel()
{
  formFields["Return"]="Cancel";
  window.returnValue = formFields;
  event.returnValue=false;
  window.close();
}

Таким образом, с помощью элемента массива formFields с именем Return мы передаем код кнопки, использованной для завершения работы диалоговой панели. Остальные элементы — Title, Author, Annotation и Publisher — передают значения из полей формы, введенные пользователем при регистрации книги.

Немодальные диалоговые панели

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

Клиентский сценарий может открыть новое немодальное окно методом open и загрузить в него для просмотра любой документ HTML.

Пример вызова метода open показан ниже:

open(sURLAddress [, sWindowName [, sFeatures [, replace]]]]);

Метод возвращает имя нового окна, которое можно использовать для ссылки на свойства и методы окна, а также на свойства и методы объектов, расположенных в этом окне.

Рассмотрим параметры метода open.

Первый обязательный параметр sURLAddress задает адрес URL документа HTML, предназначенного для загрузки в новое окно.

Второй необязательный параметр sWindowName определяет имя окна для использования в параметре target тега <A> или в теге <FORM>. Он может быть пустой строкой.

Третий, тоже необязательный параметр features, задает различные параметры, определяющие внешний вид создаваемого окна браузера. Он представляет собой текстовую строку, где через запятую перечислены значения отдельных параметров, например:

var wndNewWindow;
wndNewWindow=open("helloWindow.html", "HelloWindow",
"toolbar=no,menubar=no,scrollbars=no,width=300,height=100");

Параметр определяет действия с указанным адресом URL в списке истории просмотренных страниц. Если он равен true, данный адрес замещает текущий в указанном списке, а если false — этот адрес будет добавлен в конец списка.

В таблице 2-3 мы перечислили все возможные параметры окна.

Таблица 2-3. Параметры окна

Параметр

Описание

toolbar

Если параметр toolbar имеет значение yes или 1, окно снабжается стандартной инструментальной линейкой. Если же значение этого параметр равно no или 0, то инструментальная линейка отсутствует

location

Определяет, будет ли отображаться поле ввода адреса документа

directories

Аналогично предыдущему, но управляет отображением кнопок каталогов браузера Netscape Navigator — What's New и What's Cool

status

Отображение строки состояния

menubar

Отображение линейки меню

scrollbars

Отображение полос просмотра

resizable

Если этот параметр указан как yes или 1, пользователь сможет изменять размер вновь созданного окна

width

Ширина окна в пикселах

height

Высота окна в пикселах

В качестве примера, иллюстрирующего применение немодальных окон, рассмотрим страницу HTML, предназначенную для просмотра других страниц с заданным адресом URL. Такая страница показана на рис. 2-17.

Рис. 2-17. Выбор адреса URL страницы для просмотра в немодальном окне

Здесь в поле Адрес URL Вы можете задать адрес любой страницы, расположенной как на локальном диске, так и в сети Интернет. Мы указали имя документа BrowserInfo.html, исходный текст которого уже рассматривал ранее в нашей книге.

После того как пользователь щелкнет кнопку GO!, на экране появится новое окно, и в него будет загружена указанная Вами страница (рис. 2-18). Конечно, копирование выполняется только в том случае, если при вводе адреса URL Вы не допустили ошибку.

Рис. 2-18. Страница загружена в немодальное окно

Обращаем Ваше внимание на то, что окно браузера, показанное на этом рисунке, не совсем стандартное. В нем нет ни меню, ни инструментальных линеек, ни строки состояния. Мы это сделали намеренно, указав соответствующие параметры при вызове метода window.open. При необходимости Вы можете изменить вид этого окна по своему усмотрению.

Исходный текст документа HTML с клиентским сценарием, создающим новое окно браузера, представлен в листинге 2-9.

Листинг 2-9. Файл ch02/ShowURL.html

В форме, предназначенной для ввода адреса URL имеется поле ввода адреса и кнопка, предназначенная для выполнения перехода по заданному адресу:

<form name="GoForm">
  <table border="0" width="66%" cellpadding="2">
     <tr><td width="21%">
Адрес URL:</td>
       <td width="79%">
       <input type="text" name="URLAddress" size="40"></td></tr>
     <tr><td width="21%"></td>
       <td width="79%">
       <input type="button" onClick="go();" value="GO!" name="B1"></td></tr>
  </table>
</form>

Когда пользователь щелкнет кнопку GO!, управление будет передано функции go:

function go()
{
  window.open(document.GoForm.URLAddress.value,
     "NewWindow","toolbar=no,menubar=no,resizable=yes");
}

Эта функция вызывает метод window.open, передавая ему в качестве первого параметра значение, извлеченное из поля формы с именем URLAddress. Именно там находится указанный пользователем адрес URL.

Второй параметр определяет имя окна, а третий задает параметры его отображения. В нашем случае мы указываем, что в окне не должно быть инструментальной линейки (параметр toolbar=no) и меню (параметр menubar=no). Кроме того, пользователь получит возможность изменять размеры окна после его отображения по своему усмотрению (параметр resizable=yes).

Работа с фреймами

Использование фреймов для создания приложений Web для Интернета имеет свои положительные и отрицательные стороны. С одной стороны, фреймы значительно облегчают процесс разработки и сопровождения крупных серверов Web, так как ссылки на разделы сервера располагаются не на всех страницах, а только не некоторых, специально предназначенных для этой цели. С другой стороны, не все браузеры в состоянии корректно просматривать страницы с фреймами.

Принимая решение о применении фреймов или об отказе от них, учитывайте, что такие приложения как Интернет-магазин содержат помимо страниц, предназначенных для широкого круга посетителей, страницы администрирования. На них записаны процедуры администрирования работой магазина, поэтому доступ к ним, как правило, имеет небольшое число сотрудников Вашей фирмы. Вы можете установить на компьютерах этих сотрудников браузер Microsoft Internet Explorer самой новой версии и забыть о проблемах несовместимости с фреймами. В этом случае применение фреймов значительно упростит административную часть Вашего проекта.

Не вдаваясь в детали использования фреймов (которые Вы легко найдете в других книгах), мы приведем только необходимые сведения о них.

Файл описания фреймов

Для того чтобы объединить несколько страниц HTML при помощи фреймов, Вам нужно подготовить специальный документ HTML, в котором описаны такие параметры фреймов, как их размер и расположение.

Особенность такого документа — отсутствие на своем обычном месте области тела документа, выделенного тегами <BODY> и </BODY>. Вместо этого в файле описания фреймов присутствуют теги <FRAMESET>, </FRAMESET>, <NOFRAME> и </NOFRAME>:

<html>
<head>
. . .
</head>
<frameset rows="Высота_строки" cols="Ширина_колонки"
  onLoad="Обработчик_события" onUnload="Обработчик_события">
  <frame src="Адрес_URL" name="Имя_фрейма">
      . . .
  <frame src="Адрес_URL" name="Имя_фрейма">
  <noframe>
     <body>
      . . .
     </body>
  </noframe>
</frameset>
</html>

Параметры rows и cols тега <FRAMESET> определяют размеры фреймов и задаются в виде списка значений, разделенных запятой.

Вы можете определить обработчики событий onLoad и onUnload, получающие управление, соответственно, при загрузке содержимого в главное окно фрейма и при замене текущего документа HTML в этом окне на другой документ. Фактически эти обработчики относятся не к фреймам, а к окну, где эти фреймы отображаются.

Для тех браузеров, которые не могут работать с фреймами, необходимо подготовить документ HTML, расположив его тело между операторами <NOFRAME> и </NOFRAME>. В этот документ стоит поместить сообщение о том, что для просмотра данной страницы Web необходимо применять более современный браузер.

Параметры тега <FRAMESET>

Рассмотрим подробнее параметры оператора <FRAMESET>, предназначенного для определения набора фреймов. Эти параметры описаны в таблице 2-4.

Таблица 2-4. Параметры тега <FRAMESET>

Параметр

Описание

COLS

Ширина колонки в процентах, пикселах или ее относительный размер

ROWS

Высота строки в процентах, пикселах или ее относительный размер

FRAMEBORDER

Если значение этого параметра равно 1, фреймы будут ограничены трехмерной рамкой, ширина которой задается в пикселах. В том случае когда указано значение 0, рамка не создается

BORDER

Используется только браузером Netscape Navigator. Задает толщину рамки фрейма в пикселах

FRAMESPACING

С помощью этого параметра задается дополнительное расстояние между фреймами в пикселах

Параметры COLS и ROWS нужны в том случае, когда фреймы, определенные в наборе, располагаются в виде таблицы. Первый из этих параметров указывает ширину колонки, а второй — высоту строки. Если фреймы располагаются в одном столбце, параметр COLS указывать не надо. Аналогично, если фреймы занимают только одну строку, не нужно указывать параметр ROWS.

Вы можете задать значения для параметров COLS и ROWS либо в процентном отношении соответственно к ширине и высоте окна браузера, либо в пикселах. Если вместо значения указан символ «*», колонка или строка занимают всю оставшуюся часть окна.

Например, в следующей строке задана высота первого фрейма, равная 90 пикселам, а второй фрейм занимает всю нижнюю часть окна браузера:

<FRAMESET ROWS="90,*">

В следующем примере два фрейма, расположенные рядом, занимают соответственно 20% и 80% ширины окна браузера.

<FRAMESET COLS="20%,80%">

Параметры оператора <FRAME>

Между тегами <FRAMESET> и </FRAMESET> располагаются теги <FRAME>, определяющие параметры отдельных фреймов. Это параметры SRC и NAME. Первый задает адрес URL документа HTML, который будет загружен в данный фрейм, а второй — имя фрейма, которое можно использовать в клиентском сценарии для адресации объектов, расположенных во фрейме. Заметим, что адрес URL не должен содержать анкеры (anchor).

Параметры тега <FRAME> приведены в таблице 2-5.

Таблица 2-5. Параметры тега <FRAME>

Параметр

Описание

ALIGN

Используется только для «плавающих» фреймов в браузере Microsoft Internet Explorer. Задает выравнивание фрейма или текста, расположенного рядом с фреймом. Этот параметр может принимать следующие значения: LEFT, CENTER, RIGHT, TOP, BOTTOM

MARGINHEIGHT

Размер отступа (в пикселах) по вертикали от границ фрейма

MARGINWIDTH

Размер отступа (в пикселах) по горизонтали от границ фрейма

FRAMEBORDER

Если значение этого параметра равно 1, фреймы ограничены трехмерной рамкой, ширина которой задается в пикселах. В том случае, когда указано значение 0, рамка не создается

NAME

Этот параметр задает имя фрейма, которое используется в теге ссылки <A> для указания, в какой фрейм нужно загрузить новый документ

NORESIZE

Если указан этот параметр, пользователь не сможет изменять размеры фрейма, передвигая его границы мышью

SCROLLING

Параметр SCROLLING определяет, нужно ли создавать полосы просмотра для пролистывания содержимого фрейма. Для этого параметра можно указывать следующие значения:

YES        полосы просмотра создаются всегда;

NO           полосы просмотра не создаются;

AUTO     полосы просмотра создаются только при необходимости, когда документ HTML не помещается полностью в окне фрейма

SRC

Адрес URL файла с документом HTML, который загружается в окно фрейма

Взаимодействие между фреймами

Средства клиентских сценариев, составленных на языках JavaScript или VBScript, позволят Вам наделить фреймы возможностями, недостижимыми при использовании одного лишь языка разметки гипертекста HTML. Например, один из фреймов может содержать ссылки на документы, которые при активизации этих ссылок загружаются в окно другого фрейма. Клиентский сценарий позволит таким образом загружать не один документ, а одновременно несколько документов в разные фреймы. В следующем разделе мы на конкретном примере расскажем о том, как передавать данные между объектами форм, расположенных в разных фреймах.

Десятично-шестнадцатеричный преобразователь

В качестве примера применения клиентских сценариев для передачи данных между окнами различных фреймов мы рассмотрим десятично-шестнадцатеричный преобразователь. Внешний вид этого преобразователя показан на рис. 2-19.

Рис. 2-19. Десятично-шестнадцатеричный преобразователь, выполненный с использованием фреймов

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

Вы можете вводить исходное число не только с клавиатуры, но и непосредственно в поле Dec, расположенное в правом фрейме. Поле Hex заблокировано для ввода при помощи обработчика события onFocus.

Исходный текст файла описания фреймов показан в листинге 2-10.

Листинг 2-10. Файл ch02/Converter/index.html

В нем определены фреймы нашего калькулятора:

<frameset ROWS="85,*" frameborder=1>
  <frame scrolling="no" name="title" src="title.html" marginheight="1">
  <frameset COLS="180,*" FRAMEBORDER=1>
     <frame scrolling="auto" name="toc" src="toc.html">
     <frame scrolling="auto" name="mainpage" src="main.html">
  </frameset>
  <noframe>
     <body bgcolor="#FFFFFF">
     </body>
  </noframe>
</frameset>

Наш сценарий будет работать с фреймами toc и mainpage, хранящимися соответственно в файлах с именами toc.html и main.html. В файле title.html содержится заголовок (листинг 2-11).

Листинг 2-11. Файл ch02/Converter/title.html

Исходный текст документа, содержащего форму с полями Dec и Hex, представлен в листинге 2-12.

Листинг 2-12. Файл ch02/Converter/main.html

Форма определена следующим образом:

<form name="Sel">
  <table>
   <tr><td><b>Hex:</b></td><td>
  <input TYPE="text" NAME="hexValue" SIZE="20" onFocus="this.blur();">
  </td></tr>
  <tr><td><b>Dec:</b></td><td>
  <input TYPE="text" NAME="decValue" SIZE="20">
  </td></tr>
</form>

Для поля исходного десятичного числа при помощи параметра NAME мы задали имя decValue. Поле результата называется hexValue. Эти имена используются сценарием JavaScript для адресации наших полей.

Документ toc.html (листинг 2-13) содержит форму с кнопками и функции сценария.

Листинг 2-13. Файл ch02/Converter/toc.html

Рассмотрим работу сценария в нашем десятично-шестнадцатеричном преобразователе.

Главная особенность этого приложения — то, что поля для ввода и отображения преобразуемых чисел располагаются в разных документах HTML, загруженных в отдельные фреймы.

Для того чтобы проинициализировать поля hexValue и decValue, мы ссылаемся на форму, расположенную внутри фрейма mainpage:

parent.mainpage.document.forms[0].hexValue.value = "";
parent.mainpage.document.forms[0].decValue.value = "";

Здесь parent ссылается на объект, который является родительским по отношению к документу HTML, содержащему сценарий. В данном случае это окно, в котором отображаются все наши фреймы.

Для чтения содержимого поля decValue применяется аналогичная техника:

szOld = parent.mainpage.document.forms[0].decValue.value;

Обратите внимание, что для текстового поля hexValue мы предусмотрели обработчик событий onFocus. Он получает управление, когда пользователь передает полю фокус ввода. Задача обработчика заключается в том, чтобы снова отобрать фокус ввода, предотвратив непосредственное редактирование числа пользователем.

Теперь о том, как выполняется ввод преобразуемых десятичных чисел.

С каждой из кнопок, связанной с вводом десятичного числа, связан обработчик события onClick, вызывающий функцию putNumber, например:

INPUT TYPE="button" NAME="3" VALUE=" 3 " onClick="putNumber(this,this.form);">

Этой функции передаются два параметра — нажатая кнопка (как объект класса button) и форма, в которой эта кнопка находится:

function putNumber(btn,form)
{
  var szOld = "";
  var szNew = "";
  if(bNewNumber)
  {
     parent.mainpage.document.forms[0].hexValue.value = "";
     parent.mainpage.document.forms[0].decValue.value = "";

     bNewNumber = false; 
  }
  szOld = parent.mainpage.document.forms[0].decValue.value;
  szNew = szOld.concat(btn.name);
  nCurrent = eval(szNew);
  parent.mainpage.document.forms[0].decValue.value = nCurrent;
}

Задача функции putNumber — ввод числа и его отображение в двух текстовых полях, расположенных в верхней части калькулятора:

function putNumber(btn,form)
{
  var szOld = "";
  var szNew = "";
  if(bNewNumber)
  {
     parent.mainpage.document.forms[0].hexValue.value = "";
     parent.mainpage.document.forms[0].decValue.value = "";

     bNewNumber = false; 
  }
  szOld = parent.mainpage.document.forms[0].decValue.value;
  szNew = szOld.concat(btn.name);
  nCurrent = eval(szNew);
  parent.mainpage.document.forms[0].decValue.value = nCurrent;
}

В самом начале своей работы функция putNumber проверяет двоичную переменную newnumber. Если ее значение равно true, пользователь может ввести первую цифру нового числа. В этом случае функция putNumber обнуляет содержимое текстовых полей hexValue и decValue, а также устанавливает значение newnumber, равное false.

Далее функция проставляет введенную пользователем цифру перед переменной szOld, равной текущему значению из поля decValue. При этом она вызывает метод concat из класса String, предназначенный для слияния (конкатенации) строк.

На следующем этапе текущее значение вычисляется функцией eval. Эта функция пытается интерпретировать текстовую строку, переданную ей в качестве параметра, как арифметическое выражение, возвращая результат интерпретации в виде численного значения. Результат сохраняется в переменной nCurrent и отображается в текстовом поле decValue.

Функция getResult, выполняющая десятично-шестнадцатеричное преобразование, получает исходное число из поля decValue и передает его функции dec2hex . Результат преобразования записывается затем в поле hexValue:

function getResult(form)
{
  parent.mainpage.document.forms[0].hexValue.value = dec2hex(parent.mainpage.document.forms[0].decValue.value);
  bNewNumber = true;
}

Рассмотрим функцию dec2hex, преобразующую десятичное число в шестнадцатеричное. Результат преобразования эта функция возвращает в виде текстовой строки:

function dec2hex(nDec)
{
  var szHexTable="0123456789ABCDEF";
  var szResult = "";
  var szBuf="";
  var nRem = 0;
  var bNegative=false;
  if(nDec < 0)
  {
     bNegative=true;
     nDec = -nDec;
  }
  nTmp=nDec;
    
  while(true)
  {
     nRem = nTmp % 16;
     nTmp = nTmp / 16;

     if(Math.floor(nTmp) < 16)
       break;

     szBuf=szHexTable.charAt(nRem);
     szResult = szBuf.concat(szResult);
     nTmp = Math.floor(nTmp);
  }
    
  szBuf=szHexTable.charAt(nRem);
  szResult = szBuf.concat(szResult);

  if(Math.floor(nTmp) != 0)
  {
     szBuf=szHexTable.charAt(Math.floor(nTmp));
     szResult = szBuf.concat(szResult);
  }

  if(bNegative == true)
     return ("-" + szResult);
  else
     return szResult;
}

В начале своей работы функция dec2hex проверяет знак исходного числа. Отрицательные числа преобразуются в положительные. При этом в переменную bNegative записывается значение true.

Алгоритм преобразования десятичного числа в шестнадцатеричное основан на делении исходного числа на 16 в цикле. Если целая часть результата деления, вычисляемая методом Math.floor, оказывается меньше 16, цикл завершается. В противном случае остаток от деления рассматривается как значение текущего шестнадцатеричного разряда.

Для того чтобы получить символическое представление шестнадцатеричного числа по его значению, мы извлекаем нужный символ из строки szHexTable, вызывая для этого метод charAt:

szBuf=szHexTable.charAt(nRem);
szResult = szBuf.concat(szResult);

По завершении цикла функция вычисляет старшие разряды результата, а также корректирует знак этого результата в соответствии с состоянием переменной bNegative.

Одновременная замена нескольких документов HTML в окнах разных фреймов

Еще одна задача, для решения которой можно с успехом применять клиентские сценарии, связана с одновременным отображением нескольких документов HTML в окнах разных фреймов.

Рассмотрим следующую ситуацию.

Предположим, мы готовим страницу с тремя фреймами. Верхний фрейм содержит заголовок, левый — некоторое подобие оглавления и, наконец, правый — показывает содержимое. Щелкая кнопки, расположенные в левом фрейме, Вы можете просматривать в правой части окна различные документы HTML (рис. 2-20).

Рис. 2-20. Главная страница с тремя фреймами

С помощью клиентского сценария мы отобразим аннотацию на материал, представленный в правом фрейме, во фрейме заголовка, расположенного в верхней части окна. Если Вы щелкнете кнопку Добро пожаловать, в заголовке появится наш логотип. Если же щелкнете кнопку Книги или Статьи, заголовок будет выглядеть так, как это показано на рис. 2-21 и 2-22 соответственно.

Рис. 2-21. В результате щелчка кнопки Книги изменилось содержимое правого и верхнего фрейма

Рис. 2-22. Теперь мы просматриваем информацию о статьях

В листинге 2-14 мы показали исходный текст файла описания фреймов index.html.

Листинг 2-14. Файл ch02/ourCD/index.html

Так же как и в предыдущем примере, здесь определены три фрейма:

<FRAMESET ROWS="85,*" FRAMEBORDER=1>
  <FRAME SCROLLING="no" NAME="title" SRC="title.html" MARGINHEIGHT="1">
  <FRAMESET COLS="180,*" FRAMEBORDER=1>
     <FRAME SCROLLING="auto" NAME="toc" SRC="toc.html">
     <FRAME SCROLLING="auto" NAME="mainpage" SRC="main.html">
  </FRAMESET>
  <NOFRAME>
     <BODY BGCOLOR="#FFFFFF"></BODY>
  </NOFRAME>
</FRAMESET>

Документ HTML, загружаемый в окно фрейма заголовка и отображающийся сразу после загрузки фрейма (а также после того, как пользователь щелкнет кнопку Добро пожаловать), показан в листинге 2-15.

Листинг 2-15. Файл ch02/ourCD/title.html

Файл main.html представлен в листинге 2-16. Он не имеет никаких интересных особенностей.

Листинг 2-16. Файл ch02/ourCD/main.html

Гораздо важней для нас файл toc.html. В этом файле находятся функции сценария JavaScript и ссылки на другие документы HTML. Этот файл показан в листинге 2-17.

Листинг 2-17. Файл ch02/ourCD/toc.html

Функция loadPage загружает в фреймы mainpage и title документы HTML, адреса URL которых передаются ей через параметры:

function loadPage(szNewURL,szTitle)
{
  parent.mainpage.window.location.href=szNewURL;
  parent.title.window.location.href=szTitle;
}

Чтобы загрузить документ мы устанавливаем свойство location.href окна соответствующего фрейма:

parent.mainpage.window.location.href=szNewURL;
parent.title.window.location.href=szTitle;

Для вызова функции loadPage мы используем следующую конструкцию:

<A HREF="javascript:loadPage('main.html', 'title.html');">
<IMG SRC="pic/fcd_62.gif" BORDER=0 ALT="Добро пожаловать"></A>

Здесь в параметре HREF тега ссылки <A> после ключевого слова javascript мы расположили строку вызова функции. Обратите внимание на применение одинарных и двойных кавычек. Так как в сценариях JavaScript вложение одинаковых кавычек недопустимо, для строк, передаваемых функции в качестве параметров, мы применяем одинарные кавычки. Значение же параметра HREF выделено при этом двойными кавычками.

Использование растровых изображений

Растровые изображения в виде файлов формата GIF и JPEG широко применяются в документах HTML, так как они позволяют значительно улучшить внешний вид страниц серверов Web.

К сожалению, возможности HTML не позволяют добиться достаточно сложных видеоэффектов без применения дополнительных средств — аплетов Java, элементов управления ActiveX и клиентских сценариев. Фактически, кроме статической графики Вы можете использовать только анимационные изображения, построенные с применением многосекционных файлов GIF, и сегментированные графические изображения, нужные для создания ссылок.

В этом разделе мы рассмотрим некоторые возможности графического оформления страниц серверов Web, которые станут Вам доступны при использовании клиентских сценариев. Снова заметим, что применять описанные здесь приемы нужно осмотрительно, так как пользователь может запретить работу сценариев при настройке своего браузера.

Растровое изображение как объект

Для того чтобы встроить растровое изображение в документ HTML, необходимо использовать тег <IMG>. Общий вид этого тега показан ниже:

<IMG SRC="Адрес_файла_изображения"
  NAME="Имя_изображения"
     . . .
  WIDTH="Ширина" HEIGHT="Высота">

Здесь мы указали только три параметра. Полный список параметров тега <IMG> с кратким их описанием Вы найдете в таблице 2-6.

Таблица 2-6. Параметры тега <IMG>

Параметр

Описание

SRC

Адрес URL файла с растровым графическим изображением

NAME

Имя объекта, соответствующего растровому графическому изображению. Это имя может быть использовано для ссылки на объект в клиентском сценарии

ALT

Текстовая строка, которая отображается в тех случаях, когда браузер не может показывать графические изображения или когда такая возможность отключена

ALIGN

Выравнивание текста относительно графического изображения:

LEFT — по левой границе;

RIGHT — по правой границе;

TOP — по верхней границе;

MIDDLE — по центру изображения;

BOTTOM — по нижней границе;

TEXTTOP — выравнивание по верхней границе относительно самых высоких символов в текстовой строке;

ABSMIDDLE — выравнивание середины текстовой строки относительно середины изображения;

BASELINE — выравнивание нижней рамки изображения относительно базовой линии текстовой строки;

ABSBOTTOM — выравнивание нижней границы изображения относительно нижней границы текущей строки

HEIGHT

Высота изображения в пикселах

WIDTH

Ширина изображения в пикселах

BORDER

Ширина рамки (в пикселах) вокруг изображения (используется только браузером Netscape Navigator)

HSPACE

Ширина (в пикселах) свободного пространства, отделяющего изображение от текста по горизонтали

VSPACE

Ширина (в пикселах) свободного пространства, отделяющего изображение от текста по вертикали

USEMAP

Адрес URL файла, содержащего так называемую карту изображения, которая используется для сегментированной графики

ISMAP

Этот параметр указывает, что данное изображение является сегментированным

Параметры тега <IMG> определяют адрес файла с изображением, выравнивание текста, расположенного возле изображения и т. д. С помощью параметров HEIGHT и WIDTH выполняется масштабирование графических изображений. Значение этих параметров указано в процентах от ширины окна просмотра.

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

Если в документе HTML размещено несколько растровых изображений, то Вы можете адресовать соответствующие объекты как элементы массива document.images. Например, первое изображение адресуется следующим образом: document.images[0]. Однако в некоторых случаях удобнее пользоваться именами изображений, определенными параметром NAME оператора <IMG>.

Объект-изображение имеет свойство src, соответствующее параметру SRC оператора <IMG>. Адресуясь к этому свойству, Вы можете не только определять текущий адрес URL изображения, но и задавать новый. Этим мы и воспользуемся далее.

Динамическая замена растровых изображений

Одна из наиболее интересных возможностей, доступных при использовании клиентских сценариев, заключается в динамической замене графических изображений, указанных в параметре SRC оператора <IMG>.

Например, в следующей строке сценария мы указываем, что изображение с именем btn1 должно иметь адрес «pic/aurap.gif»:

document.btn1.src="pic/aurap.gif"

Здесь мы указали неполный адрес URL, однако, можно указывать и полный адрес.

Что произойдет при выполнении этой строки сценария?

Область, выделенная в окне браузера для растрового изображения btn1, будет заполнена изображением pic/aurap.gif. Если до этого там было другое изображение, оно будет заменено новым.

Какие возможности предоставляет динамическая замена растровых изображений?

Во-первых, Вы можете создавать графические ссылки, которые изменяют свой вид, когда над ними установлен курсор мыши.

Во-вторых, заменой растровых изображений в клиентском сценарии Вы сможете создавать анимационные изображения.

Рассмотрим примеры сценариев, иллюстрирующих эти возможности.

Изменение внешнего вида графических ссылок

В документе HTML, изображенном на рис. 2-23, находятся две кнопки, созданные как растровые графические изображения. Они используются для активизации ссылок, соответствующих двум другим документам HTML.

Рис. 2-23. Кнопка с надписью АУРАМЕДИА изменила свой цвет

Если установить курсор над одной из кнопок, надпись на соответствующей кнопке изменит свой цвет. Это достигается динамической заменой графического изображения кнопки при помощи клиентского сценария.

Обратите внимание на исходный текст документа HTML, показанный представленный в листинге 2-17.

Листинг 2-17. Файл ch02/grbutton/grbutton.html

Для создания ссылок мы воспользовались тегом <A>. Он применяется здесь совместно с тегом <IMG>, поэтому ссылка отображается как графическое изображение.

Для тега ссылки <A> мы определили обработчики событий onMouseOver и onMouseOut:

onMouseOver="document.btn1.src='pic/aurap.gif'"
onMouseOut="document.btn1.src='pic/aura.gif'"

Когда курсор мыши оказывается над ссылкой (то есть над графическим изображением ссылки), управление получает обработчик события onMouseOver. Этот обработчик загружает изображение pic/aurap.gif, где слово АУРАМЕДИА написано черным цветом (для второй кнопки в аналогичной ситуации загружается изображение pic/softcatp.gif).

После того как пользователь убирает курсор мыши от кнопки, в дело включается обработчик события onMouseOut. Он восстанавливает исходное изображение, указанное в параметре SRC тега <IMG>.

Создание анимационных изображений

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

На рис. 2-24 мы показали документ HTML именно с такой анимацией.

Рис. 2-24. Анимация с помощью клиентского сценария

В окне браузера последовательно отображаются кадры анимационного изображения (рис. 2-25), причем сначала в прямой, а затем — в обратной последовательности. Это выглядит так, как будто слово «Noise» периодически тонет в цветном «шуме» и затем проявляется вновь.

Рис. 2-25. Изображения отдельных кадров анимационной последовательности

Также обратите внимание вот на что: чтобы получить подобный эффект при помощи многосекционного файла GIF, размер этого файла надо удвоить. Причина заключается в том, что Вам придется включить в файл кадры вначале в прямой, а затем в обратной последовательности. Клиентский сценарий позволяет более тонко управлять процессом отображения кадров, причем относительно простыми средствами, в результате этого Вам станут доступны достаточно сложные визуальные эффекты.

Исходный текст документа HTML, в котором имеется сценарий, выполняющий анимацию, показан в листинге 2-18.

Листинг 2-18. Файл ch02/noise/noise.html

В теле документа с помощью тега <IMG> мы разместили первый кадр анимационной последовательности:

<IMG SRC="img01.gif" NAME="Img">

С помощью параметра NAME мы задали имя Img. Его использует сценарий для ссылки на объект.

Кроме того, в теле нашего документа находится вызов функции showNextImage:

<body BGCOLOR=white>
  <img SRC="img01.gif" NAME="Img">
  <SCRIPT LANGUAGE="JavaScript">
  <!--
     showNextImage();
  // -->
  </SCRIPT>
</body>

Она предназначена для отображения очередного кадра анимационной последовательности в окне бразуера. Вот исходный текст функции showNextImage:

function showNextImage()
{
  if(bForward)
  {
     i++;
     if(i>17)
     {
       bForward=false;
     }
  }
  else
  {
     i--;
     if(i<2)
     {
       bForward=true;
     }
  }
  document.Img.src= "img0" + i + ".gif";
  setTimeout("showNextImage()", 100);
}

В области заголовка документа HTML находится определение функции showNextImage и двух глобальных переменных:

var i=1;
var bForward=true;

Переменная i хранит номер текущего кадра, отображаемого в окне браузера. Этот номер вначале увеличивается функцией showNextImage от 1 до 16, а затем снова уменьшается до 1. Изменение номера происходит на 1 (в ту или иную сторону) при каждом вызове функции showNextImage.

В переменной bForward хранится направление изменения номера кадра. Значение true соответствует прямому направлению, а значение false — обратному.

Когда функция showNextImage получает управление, она анализирует содержимое переменной bForward. Если в этой переменной находится значение true, функция showNextImage увеличивает значение переменной i, а затем сравнивает результат с числом 17. Когда отображение всех кадров в прямой последовательности завершено, в переменную bForward записывается false, после чего при следующем вызове функции showNextImage номер текущего кадра не увеличится, а уменьшится.

Для отображения очередного кадра функция showNextImage изменяет значение свойства src изображения document.Img, как это показано ниже:

document.Img.src= "img0" + i + ".gif";

Имя файла, в котором хранится изображение кадра, конструируется из строки «img0», номера кадра, и строки «.gif».

Последнее, что делает функция showNextImage, перед тем как возвратить управление, — вызывает функцию setTimeout:

setTimeout("showNextImage()", 100);

Напомним, что функция setTimeout устанавливает таймер. Задержка срабатывания таймера определяется вторым параметром и в нашем случае равна 100 миллисекундам.

Когда таймер включится, начнется выполнение строки сценария, которая была передана функции setTimeout в качестве первого параметра. Мы вызываем после окончания задержки функцию showNextImage и, таким образом, обеспечиваем вызов этой функции в бесконечном цикле.

Ожидание загрузки всех изображений

Если Вы собираетесь размещать в своем документе HTML анимационное изображение, состоящее из отдельных кадров, которые, в свою очередь, расположены в отдельных файлах, возникает одна проблема. Она связана с трудностью определения времени загрузки всех изображений анимационной последовательности через медленные и нестабильные каналы Интернета.

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

В листинге 2-19 мы привели исходный текст документа HTML со сценарием, который работает подобным образом.

Листинг 2-19. Файл ch02/noise/noise2.html

В теле документа HTML расположен сценарий, вызывающий последовательно функции loadAllImages и showNextImage:

loadAllImages(nNumberOfImages);
showNextImage();

Функции loadAllImages в качестве параметра передается общее количество изображений в анимационной последовательности. В нашем случае оно равно 18.

Задача функции loadAllImages — заполнить массив объектов класса Image:

function loadAllImages(nNumberOfImages)
{
  var i;
  for(i=0; i<nNumberOfImages; i++)
  {
     imgArray[i] = new Image();
     imgArray[i].src = "img0" + (i+1) + ".gif";
  }
}

Этот массив определен в области заголовка нашего документа HTML:

var imgArray = new Array(18);

Заполнение массива выполняется в цикле:

var i;
for(i=0; i<nNumberOfImages; i++)
{
  imgArray[i] = new Image();
  imgArray[i].src = "img0" + (i+1) + ".gif";
}

Для каждого элемента массива вначале с помощью ключевого слова new создается объект класса Image, а затем устанавливается значение свойства src этого объекта. Последняя операция и приводит к инициированию загрузки файла изображения, выполняемой асинхронно.

После того как массив заполнен, можно вызывать функцию showNextImage:

var nNumberOfImages = 18;
var i=1;
var bForward=true;
var imgArray = new Array(18);

function showNextImage()
{
  if(bForward)
  {
     i++;
     if(i>17)
     {
       bForward=false;
     }
  }
  else
  {
     i--;
     if(i<2)
     {
       bForward=true;
     }
  }
  document.Img.src = imgArray[i-1].src;
  setTimeout("showNextImage()", 100);
}

Она идентична описанной в предыдущем примере, за исключением того, что для установки свойства src изображения Img используются элементы заранее подготовленного массива imgArray:

document.Img.src = imgArray[i-1].src;

Наложение фильтра на графическое изображение

Способ подмены графического изображения, описанный ранее в разделе «Изменение внешнего вида графических ссылок», имеет один существенный, на наш взгляд, недостаток. Для каждого изображения Вам придется подготовить два файла, первый из которых будет соответствовать невыделенному состоянию графической ссылки, а второй — выделенному. Если таких ссылок много, это увеличит время загрузки страницы, а также объем файлов, хранящихся в каталоге Вашего сервера Web.

Между тем средствами DHTML Вы можете подсветить выделенные мышью графические ссылки без удвоения объема файлов с графикой. Этого достигают, изменяя одно из свойств стиля ячейки таблицы, содержащей графическую ссылку.

На рис. 2-26 показана основная страница нашего сервера Web, расположенного в Интернете по адресу http://www.glasnet.ru/~frolov.

Рис. 2-26. Подсвечивание элементов графического меню средствами DHTML

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

Как достигается такой эффект?

В листинге 2-20 мы привели исходный текст файла toc.html, образующего левый фрейм главной страницы нашего сервера Web.

Листинг 2-20. Файл ch02/ColorFilter/toc.html

Вот фрагмент этого файла:

<table border="0" width="130" cellspacing="0" cellpadding="0">
<tr><td width="100%">
  <img src="../images/menu1t.gif" alt="[На нашем сервере]"
     border="0" WIDTH="130" HEIGHT="16"></td>   </tr>
<tr><td width="100%" onMouseOver="GON()" onMouseOut="GOFF()">
  <a href="main.html" target="mainpage">
  <img src="../images/menu1_welcome.gif" alt="[Добро пожаловать]"   border="0" name="btn11" WIDTH="130" HEIGHT="16"></a></td></tr>
. . .
</table>

Обратите внимание, что в теге <td> ячейки таблицы, содержащей графическую ссылку на файл main.html мы определили обработчики событий onMouseOver и onMouseOut (выделено в листинге 2-20 жирным шрифтом). Первое из них возникает, когда курсор мыши располагается над областью окна браузера, занимаемой этой ячейкой, а второе — когда курсор покидает данную область.

В ответ на эти события вызываются функции GON и GOFF, исходные тексты которых приведены в листинге 2-20.

Обращаясь к объекту события event.srcElement, эти функции вначале проверяют свойство tagName, которое содержит имя тега объекта, возбудившего событие. В случае изображения имя тега будет представлять собой текстовую строку «IMG».

Далее функция определяет фильтр event.srcElement.style.filter, который используется при рисовании графического объекта.

Функция GON устанавливает фильтр «Gray», действие которого заключается в преобразовании цветного изображения в черно-белое с градациями серого:

function GON()
{
  if(event.srcElement.tagName == "IMG")
     event.srcElement.style.filter = "Gray";
}

Функция GOFF отменяет действие фильтра, записывая в соответствующее свойство пустую строку.

function GOFF()
{
  if(event.srcElement.tagName == "IMG")
     event.srcElement.style.filter = "";
}

Помимо «Gray», Вы можете использовать и другие фильтры, описанные в документации по DHTML, например фильтр «Invert», инвертирующий цветное изображение.

Заметим, что описанный в этом разделе способ подсветки работает только в браузере Microsoft Internet Explorer. Что же касается Netscape Navigator, то он имеет другую объектную модель. Если загрузить страницу toc.html в этот браузер, подсветка перестанет работать (тем не менее ссылки будут функционировать нормально).

Применение Cookie в клиентских сценариях

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

Что такое Cookie?

Скажем сразу, что с кулинарным искусством это связано мало, хотя переводится с английского языка как «печенье» или «булочка». Говоря кратко, Cookie представляет собой свойство документа HTML. Данные Cookie физически хранятся локально на компьютере пользователя, загрузившего этот документ, в виде специальных файлов. Средствами Cookie пользователь может настроить, или «приготовить», по собственному вкусу документ HTML, если для него предусмотрена такая настройка.

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

Как мы уже говорили, основное, для чего нужен Cookie, — так это для того, чтобы предоставить пользователю возможность настроить «под себя» интерфейс активных документов HTML. Эти параметры могут анализироваться или не анализироваться сервером Web, но в любом случае они хранятся у пользователя. И, разумеется, пропадут, если пользователь, скажем, отформатирует свой жесткий диск. После этого для документа HTML их придется задавать заново.

Конечно, задачу индивидуальной настройки параметров страниц можно решить и другими способами, например при помощи активных серверных страниц ASP или расширений сервера Web — типа программ CGI и приложений ISAPI. Для этого на сервере Web надо установить базу данных, хранящую параметры для всех зарегистрированных в ней пользователей. В этом случае расширение сервера Web способно динамически создавать настраиваемые документы HTML, используя для определения внешнего вида страниц параметры, хранящиеся в базе данных.

Возлагая задачу хранения параметров отдельных документов HTML на пользовательский браузер, Вы сильно упрощаете задачу организации настройки диалогового интерфейса. А для этого как раз нужны Cookie и клиентские сценарии.

Еще одно практическое применение Cookie — хранение товара, выбранного посетителем Вашего виртуального электронного магазина. Покупатель отмечает разный товар на разных страницах сервера. При этом полный заказ вначале сформирован и сохранен в Cookie, а затем по явному запросу пользователя переправляется на сервер.

Среди других применений Cookie можно отметить сетевые игры. В Cookie хранится , например, текущее состояние игры или другие параметры.

При разработке приложений Web помните, что приложения ни при каких условиях не должны хранить в Cookie такую информацию, как идентификаторы пользователей и пароли, а также номера кредитных карточек. Дело в том, что эта информация может оказаться доступной администраторам серверов Web и попасть в третьи руки. Обнаружив, что Ваше приложение пытается записывать в Cookie конфиденциальную информацию, предусмотрительные пользователи, скорее всего, откажутся от работы с ним.

Выполнение основных операций с Cookie

Рассмотрим основные операции с Cookie, например создание Cookie, получение и изменение значений параметров Cookie, а также удаление Cookie.

Создание Cookie

Существуют два способа создания Cookie, первый из которых используется расширениями сервера Web, а второй — клиентскими сценариями. Мы рассмотрим их оба.

Создание Cookie расширением сервера Web

Для того чтобы создать Cookie первым способом, расширение сервера Web обычно добавляет в заголовок HTTP динамически создаваемого документа HTML поле с именем Set-Cookie. В нем определяются имена и значения параметров Cookie.

Когда расширение сервера Web вызывается из документа HTML, имеющего Cookie, параметры Cookie предаются этому расширению через поле Cookie заголовка HTTP и могут быть проанализированы.

Заголовок HTTP, предназначенный для создания Cookie, выглядит следующим образом:

Set-Cookie: Имя=Значение; expires=Дата_GMT;
path=Адрес_URL; domain=Домен; secure

Описание отдельных полей заголовка Set-Cookie приведено в таблице 2-7.

Таблица 2-7. Поля заголовка Set-Cookie

Поле

Описание

Имя

Произвольное имя параметра, определенного в Cookie. Здесь Вы можете использовать любую строку, лишь бы в ней не было пробелов, запятых и двоеточий. В том случае, когда имя содержит перечисленные выше символы, используйте кодировку URL

Значение

Текстовая строка значений параметров. В этой строке не должно быть пробелов, запятых и двоеточий, поэтому надо использовать для нее кодировку URL

expires=Дата_GMT

Дата автоматического удаления Cookie по Гринвичу. Если эта дата не указана, а параметр expires отсутствует, Cookie будет удален сразу после того, как браузер закончит сеанс связи с сервером Web

domain=Домен

Доменная часть адреса URL, для которой действует данный Cookie. Если этот параметр не указан, то по умолчанию используется доменный адрес URL документа HTML, где был установлен Cookie

path=Адрес_URL

Часть адреса URL, задающая путь к документу HTML, для которого действует данный Cookie. Если этот параметр не указан, то по умолчанию используется адрес URL документа HTML, где был установлен Cookie

secure

Если указано это поле, данные Cookie необходимо предавать только с использованием защищенного протокола SSL. Такой протокол применяется серверами HTTPS

 

Все поля, кроме первых двух (Имя и Значение), не обязательны.

Дата должна быть записана в формате День_недели, ДД-Мес-ГГ ЧЧ:ММ:СС GMT, где:

·    День_недели — английское трехбуквенное сокращение названия дня недели (например, Mon);

·    ДД — номер дня недели;

·    Мес — английское трехбуквенное сокращение названия месяца (например, Jun);

·    ГГ — две последние цифры года;

·    ЧЧ — часы;

·    ММ — минуты;

·    СС — секунды

Например, дату можно указать так:

Mon, 07-Jun-93 14:45:00 GMT

Сделаем небольшое замечание относительно полей domain и path, определяющих условие, при котором выполняется установка Cookie.

Когда браузер загружает документ HTML с сервера Web и среди заголовков HTTP этого документа присутствует заголовок Set-Cookie, он проверяет возможность установки Cookie. В процессе проверки анализируется адрес URL, откуда был загружен этот документ, а также содержимое полей domain и path.

Если эти поля не указаны, то по умолчанию считаются, что они соответствуют адресу URL, по которому находится загруженный документ HTML. В этом случае выполняется установка Cookie.

Когда же указано поле domain, установка Cookie выполняется, только если документ загружен с сервера Web, принадлежащего данному домену.

Средствами параметра path можно установить ограничение на адреса URL в рамках домена, для которых выполняется установка Cookie. При этом значение «/» соответствует всем адресам данного домена.

Одновременно сервер Web способен создать несколько параметров Cookie, включив в заголовок документа HTML несколько заголовков Set-Cookie.

Создание Cookie в клиентском сценарии

Второй способ предполагает использование свойства document.cookie. Это свойство мы упомянули, рассказывая о свойствах и методах объекта document, создаваемого для документа HTML, загруженного в окно браузера.

В общем виде сценарий создает Cookie следующим образом:

document.cookie = "Имя=Значение";

Здесь мы просто записываем в свойство cookie объекта document текстовую строку, определяющую Cookie.

Для пересчета текущей даты в формат GMT в клиентских сценариях можно использовать встроенные функции, о чем мы расскажем чуть попозже.

В качестве примера ниже показан исходный текст функции addCookie, которую мы используем в своих сценариях для создания Cookie.

function addCookie(szName,szValue,dtDaysExpires)
{
   var dtExpires = new Date();
   var dtExpiryDate = "";

   dtExpires.setTime(dtExpires.getTime() +
      dtDaysExpires * 24 * 60 * 60 * 1000);

   dtExpiryDate = dtExpires.toGMTString();

   document.cookie =
     szName + "=" + szValue + "; expires=" + dtExpiryDate;
}

Функция addCookie получает три параметра.

Через параметр szName передается имя параметра, хранящегося в Cookie. Параметр szValue определяет значение этого параметра Cookie. Что же касается последнего параметра — dtDaysExpires, то он задает интервал времени по отношению к моменту создания Cookie, когда этот Cookie необходимо удалить.

Самое сложное в функции addCookie — это определение даты удаления Cookie и преобразование этой даты в формат GMT. Данная задача решается следующим образом.

Прежде всего, функция addCookie создает объект класса Date с помощью ключевого слова new:

var dtExpires = new Date();

Записанная таким образом в переменную dtExpires дата соответствует моменту вызова функции addCookie.

Далее с помощью метода getTime функция addCookie определяет текущую дату в миллисекундах и прибавляет к результату значение параметра dtDaysExpires, полученное функцией, умноженное на константу (24*60*60*1000):

dtExpires.getTime() + dtDaysExpires * 24 * 60 * 60 * 1000

Константа — это количество часов в сутках, умноженное на количество минут в часе, затем на количество секунд в минуте и, наконец, на количество миллисекунд в секунде.

Результат вычислений записывается при помощи метода setTime в переменную даты dtExpires. Теперь здесь хранится дата автоматического уничтожения Cookie браузером. Осталось лишь преобразовать эту дату в формат GMT.

Такое преобразование нетрудно сделать с помощью специально предназначенного для этого метода toGMTString, возвращающего текстовую строку в нужном нам формате:

dtExpiryDate = dtExpires.toGMTString();

Теперь нам остается только сформировать текстовую строку определения Cookie и записать ее в свойство document.cookie:

document.cookie =
  szName + "=" + szValue + "; expires=" + dtExpiryDate;

На этом создание Cookie завершено.

Теперь, когда в Вашем распоряжении есть функция addCookie, создание Cookie представляет собой очень простую задачу. Например, в следующей строке мы создаем Cookie с именем Count и значением 0, причем через 10 дней браузер автоматически удалит этот Cookie:

addCookie("Count","0",10);

При необходимости использования других параметров Cookie, например path или domain, Вы можете немного дополнить текст функции addCookie. С этой задачей Вы легко справитесь самостоятельно.

Получение значения Cookie

Итак, Вы научились создавать Cookie в клиентских сценариях. Теперь попробуем решить другую задачу — определение значения параметров Cookie.

Она сводится к простому сканированию текстовой строки, полученной следующим образом:

var szCookieString = document.cookie;

В этой строке Вам нужно найти подстроку «Имя=Значение;», а затем извлечь полученное значение.

Для облегчения этой работы Вы можете воспользоваться функцией findCookie. Исходный текст этой функции приведен ниже:

function findCookie(szName)
{
  var i = 0;
  var nStartPosition = 0;
  var nEndPosition = 0;
  var szCookieString = document.cookie;

  while(i <= szCookieString.length)
  {
     nStartPosition = i;
     nEndPosition = nStartPosition + szName.length;

     if(szCookieString.substring(
          nStartPosition,nEndPosition) == szName)
     {
       nStartPosition = nEndPosition + 1;
       nEndPosition =
          document.cookie.indexOf(";",nStartPosition);

       if(nEndPosition < nStartPosition)
          nEndPosition = document.cookie.length;

       return document.cookie.substring(
            nStartPosition,nEndPosition); 
       break;  
     }
     i++;
  }
  return "";
}

После извлечения строки из свойства document.cookie и записи этой строки в переменную szCookieString функция findCookie организует циклический просмотр всех символов этой строки. Условием завершения цикла является просмотр всех символов szCookieString.length.

Сравнивая имя параметра с подстрокой, извлеченной из строки szCookieString при помощи метода substring, функция findCookie пытается найти нужный параметр. Если попытка оказывается успешной, функция findCookie пропускает символ присваивания, извлекая значение параметра, ограниченное точкой с запятой. Это значение возвращается функцией findCookie.

Если же поиск неудачен, функция findCookie возвращает пустую строку.

Какие возможности предоставляет функция findCookie?

Во-первых, она позволит Вам проверить, установлен ли для данного документа Cookie с заданным именем:

if(findCookie("Visit") == "")
{
  // cookie с именем Visit установлен
  . . .
}
else
{
  // cookie с именем Visit не установлен
  . . .
}

Для того чтобы записать в текстовую переменную значение параметра Cookie с заданным именем, Вы должны сделать следующее:

var szVisitValue = findCookie("Visit");

Как видите, пользоваться функцией findCookie достаточно просто.

Изменение значения параметра Cookie

Для изменения значения параметра Cookie с заданным именем Вы можете просто вызвать функцию addCookie еще раз:

addCookie("Count","0",10);
// Значение параметра Count равно 0
  . . .
addCookie("Count","5",10);
// Значение параметра Count равно 5

Здесь мы вначале установили для параметра Count значение 0, а затем изменили это значение на 5.

Удаление Cookie

Самый простой способ удалить Cookie — установить для него такое время автоматического удаления, которое уже прошло. Для этого нужно получить текущую дату, уменьшить ее, например, на одну микросекунду, а затем изменить значение document.cookie.

Все это делает функция removeCookie:

function removeCookie(szName)
{
  var dtExpires = new Date();
  dtExpires.setTime(dtExpires.getTime() - 1);

  var szValue = findCookie(szName);

  document.cookie = szName + "=" + szValue +
     "; expires=" + dtExpires.toGMTString();
}

В последней строке этой функции мы указали такое значение параметра expires, при котором Cookie будет немедленно удален браузером.

Ограничения на использование Cookie

На использование Cookie накладываются определенные ограничения, перечисленные ниже:

·    всего можно создать не более 300 Cookie;

·    необходимо, чтобы размер каждого Cookie не превышал 4 кб;

·    для каждого домена может быть создано не более 20 Cookie

Если указанные ограничения будут нарушены, браузер может удалить самые старые Cookie или обрезать значения параметров Cookie.

Примеры использования Cookie

В этом разделе на примере конкретных клиентских сценариев мы покажем, как можно использовать Cookie для решения различных практических задач.

Фиксация повторных посещений страницы

В нашем первом примере документ HTML содержит форму с двумя кнопками (рис. 2-27).

Рис. 2-27. Кнопки для перехода к динамически создаваемому документу HTML и для удаления Cookie

Если нажать на кнопку GO!, сценарий создаст новый документ HTML. Внешний вид его зависит от того, сколько раз пользователь нажимал на эту кнопку.

Кнопка Удалить cookie предназначена для удаления Cookie, созданного в нашем документе HTML.

Когда Вы нажимаете на кнопку GO! в первый раз, Cookie еще не создан. При этом генерируется документ HTML, изображенный на рис. 2-28.

Рис. 2-28. Такой документ HTML создается динамически при первом посещении

Во второе и последующие посещения внешний вид документа изменяется (рис. 2-29).

Рис. 2-29. Такой документ HTML создается динамически при втором посещении

Теперь здесь виден новый заголовок, а также содержимое параметров Cookie с именами Visit, Count, info, MidiUsed и JavaUsed.

При каждом новом посещении значение параметра Count будет увеличиваться на единицу. Если же в документе, показанном на рис. 2-27, Вы нажмете кнопку Удалить cookie, подсчет посещений начнется заново.

Исходный текст документа HTML показан в листинге 2-21.

Листинг 2-21. Файл ch02/Again.html

Функции addCookie, findCookie и removeCookie, определенные в этом документе, Вам уже знакомы. Они предназначены для создания Cookie, извлечения значения заданного параметра Cookie и удаления Cookie соответственно.

Функция btnClick вызывается, когда пользователь нажимает в форме кнопку GO!:

function btnClick()
{
  if(findCookie("Visit") == "")
  {
    addCookie("Visit","Alexandr_Frolov",10);
     addCookie("Count","0",10);
     document.write("<H2>Добро пожаловать!</H2>");    
  }
  else
  {
     var szCnt = findCookie("Count");
     var i=0;

     if(szCnt != "")
     {
       i = szCnt;
       i++;
       szCnt = i.toString();
 
       addCookie("Count",szCnt,10);
     }
     document.write("<H2>Рады видеть Вас СНОВА!</H2>");   
     document.write(document.cookie);  
  }
}

Прежде всего, эта функция ищет параметр Cookie с именем Visit. Если такой параметр не найден, считается, что страница посещается в первый раз. В этом случае функция btnClick создает параметры Cookie с именами Visit и Count, а затем формирует текст документа HTML с приглашением:

addCookie("Visit","Alexandr_Frolov",10);
addCookie("Count","0",10);
document.write("<H2>You are welcome!</H2>");

Когда пользователь посещает страницу повторно, параметр Cookie с именем Visit уже существует. В этом случае функция btnClick пытается найти параметр с именем Count и получить его значение:

var szCnt = findCookie("Count");

Это значение затем увеличивается на единицу и записывается обратно в параметр Cookie с именем Count:

i = szCnt;
i++;
szCnt = i.toString();
addCookie("Count",szCnt,10);

Завершая свою работу, функция btnClick записывает приглашение для повторно посетивших страницу пользователей и отображает содержимое свойства document.cookie:

document.write("<H2>You are welcome AGAIN!</H2>");   
document.write(document.cookie);

Обработчик события onClick кнопки Удалить cookie вызывает функцию removeCookie для параметров Cookie с именами Count и Visit, удаляя их:

<INPUT TYPE="button" VALUE="Remove All Cookies"
  onClick="removeCookie('Count');removeCookie('Visit')">

Записная книжка Cookie Notepad

В следующем примере мы применили Cookie для хранения произвольного текста, набранного пользователем в многострочном окне редактирования (рис. 2-30).

Рис. 2-30. Документ с записной книжкой Cookie Notepad

При первой загрузке документа HTML с записной книжкой окно редактирования остается пустым. Вы можете набрать здесь любой текст и записать его в Cookie, щелкнув кнопку Сохранить текст. Если теперь Вы закроете документ HTML и откроете его вновь, набранный Вами ранее текст появится в окне редактирования.

Для того чтобы удалить текст и Cookie, достаточно щелкнуть кнопку Удалить текст.

Исходный текст документа HTML с записной книжкой Cookie Notepad показан в листинге 2-22.

Листинг 2-22. Файл ch02/Notebook.html

Функция addCookie, использованная нами здесь, имеет одну особенность: перед записью текстовой строки в параметр Cookie она выполняет ее кодировку в формате URL, вызывая для этого функцию escape:

document.cookie = szName + "=" + escape(szValue) + "; expires=" + dtExpiryDate;

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

Аналогичные изменения мы внесли и в функцию findCookie. Она возвращает значение, перекодированное в обычный текст функцией unescape, выполняющей действия противоположные действиям функции escape:

szTemp = document.cookie.substring(
  nStartPosition,nEndPosition); 
return unescape(szTemp);

Когда пользователь нажимает кнопку Сохранить текст, вызывается функция btnClick:

function btnClick()
{
  addCookie("MyText",TestForm.Comment.value,10);
}

Эта функция просто записывает в параметр Cookie с именем MyText текстовую строку, извлеченную из многострочного поля редактирования TestForm.Comment.value.

При удалении текста кнопкой Удалить текст вызывается функция removeCookie, удаляющая параметр Cookie с именем MyText, а также записывается пустая строка в окно многострочного редактирования:

<INPUT TYPE="button" VALUE="Clear text"
  onClick = "removeCookie('MyText'); TestForm.Comment.value=''">

В самом конце тела документа HTML находится небольшой фрагмент сценария, запускающийся сразу после загрузки этого документа:

var szMyText="";
szMyText = findCookie("MyText");

if(szMyText != "")
{
  TestForm.Comment.value = szMyText;
}

Этот фрагмент пытается получить значение параметра Cookie с именем MyText. Если это ему удается и функция findCookie возвращает непустую строку, полученная строка записывается в окно многострочного поля редактирования TestForm.Comment.value. В результате сразу после загрузки документа это окно оказывается заполненным текстом, сохраненным в Cookie.

Вы можете посмотреть системный файл, хранящий данные Cookie. Для этого откройте каталог Temporary Internet Files, расположенный в системном каталоге Microsoft Windows 95 или в каталоге %systemroot%\Profiles\<имя_пользователя>\Cookies операционной системы Microsoft Windows NT (здесь %systemroot% — системный каталог Microsoft Windows NT).

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

Visit
Alexandr_Frolov
~~local~~/E:\!Russian Edition\InternetDB\Src\ch02\
0
3219211008
29310152
404023264
29308141
*
Count
1
~~local~~/E:\!Russian Edition\InternetDB\Src\ch02\
0
24243712
29310153
1499803264
29308141
*
MyText
%u0421%20%u043F%u043E%u043C%u043E%u0449%u044C%u044E%20cookie%20%u0432%u044B%20%u043C%u043E%u0436%u0435%u0442%u0435%20%u0445%u0440%u0430%u043D%u0438%u0442%u044C%20%u0443%20%u043F%u043E%u043B%u044C%u0437%u043E%u0432%u0430%u0442%u0435%u043B%u044F%20%u0435%u0433%u043E%20%u043B%u043E%u043A%u0430%u043B%u044C%u043D%u044B%u0435%20%u043D%u0430%u0441%u0442%u0440%u043E%u0439%u043A%u0438
~~local~~/E:\!Russian Edition\InternetDB\Src\ch02\
0
204374528
29310157
1686804080
29308145
*

В самом начале файла видно имя Visit параметра Cookie. На следующих строках находятся значения других параметров, отделенные друг от друга строкой ~~local~~/E:\!Russian Edition\InternetDB\Src\ch02\. Для записи символов кириллицы здесь использована кодировка URL.

Если удалить этот файл и затем открыть документ HTML, многострочное окно редактирования будет пустым. Удалив этот файл, мы удалим и расположенный в нем Cookie.

Настройка параметров документа HTML

Следующий пример демонстрирует, как можно использовать Cookie для настройки пользователем параметров документа HTML.

На рис. 2-31 показан документ HTML с двумя кнопками и переключателем, имеющим зависимую фиксацию.

Рис. 2-31. Главный документ HTML, позволяющий выполнить настройку

Если Вы нажмете верхнюю кнопку, то в окне браузера появится документ HTML, созданный динамически клиентским сценарием. В первый раз этот документ будет таким, как показано на рис. 2-32.

Рис. 2-32. Внешний вид документа при первом посещении

Переключатели позволят Вам выбрать один из четырех цветов фона документа. Это значение будет храниться в Cookie. Для того чтобы вернуться к цвету, принятому по умолчанию, в документе HTML, показанному на рис. 2-31, нужно нажать кнопку Параметры по умолчанию.

При последующих посещениях внешний вид документа изменится (рис. 2-33).

Рис. 2.33. Внешний вид документа при третьем посещении

Его фон будет иметь такой цвет, какой был задан при помощи переключателей.

Исходный текст документа HTML показан в листинге 2-23.

Листинг 2-23. Файл ch02/CustomPage.html

Помимо функций addCookie, findCookie и removeCookie, предназначенных для работы с Cookie, в сценарии определена переменная szColor, предназначенная для хранения выбранного пользователем цвета фона, а также функции btnGo, chkRadio и setDefault.

Функция btnGo прежде всего проверяет наличие параметра Cookie с именем Count:

function btnGo()
{
  if(findCookie("Count") == "")
  {
     addCookie("Count","0",10);
     addCookie("bgColor",szColor,10);

     document.write("<H2>Добро пожаловать!</H2>");    
     document.write("<P>Вы можете настроить цвет фона этой");
     document.write(" страницы при помощи переключателей,");
     document.write(" расположенных на главной странице.");  
     document.write("<P>Настройки будут использованы, когда Вы");
     document.write(" посетите эту страницу в следующий раз.");
  }
  else
  {
     var szCnt = findCookie("Count");
     var i=0;

     if(szCnt != "")
     {
       i = szCnt;
       i++;
       szCnt = i.toString();
 
       addCookie("Count",szCnt,10);
     }

     document.write("<H2>Рады видеть Вас снова!</H2>");   
     document.write("Вы посетили эту страницу в " + szCnt.bold() + " раз.");    
     document.bgColor=findCookie("bgColor");
  }
}

Если такого параметра нет, сценарий считает, что пользователь просматривает этот документ в первый раз. В этом случае функция btnGo добавляет два параметра Cookie с именами Count и bgColor:

addCookie("Count","0",10);
addCookie("bgColor",szColor,10);

Первый из них предназначен для хранения счетчика посещений, а второй — для хранения цвета фона. Далее функция btnGo формирует документ HTML с приглашением для пользователя, просматривающего документ в первый раз, и завершает свою работу.

В том случае, когда сразу после вызова функция btnGo нашла параметр Cookie с именем Count и получила его значение, это значение увеличивается на единицу и записывается обратно. Кроме того, оно отображается в тексте документа:

document.write("<H2>Рады видеть Вас снова!</H2>");   
document.write("Вы посетили эту страницу в " +
  szCnt.bold()+" раз.");   

Затем функция btnGo устанавливает цвет фона сформированного документа HTML в соответствии со значением, извлеченным из параметра Cookie с именем bgColor:

document.bgColor=findCookie("bgColor");

Функция chkRadio вызывается, когда пользователь отмечает один из переключателей выбора цвета:

function chkRadio(form,value)
{
  szColor = value;
  addCookie("bgColor",szColor,10);
}

Эта функция записывает значение выбранного цвета в переменную szColor, а также в параметр Cookie с именем bgColor.

И, наконец, функция setDefault удаляет параметр Cookie с именем Count и устанавливает в переменной szColor белый цвет фона, принятый по умолчанию:

function setDefault(form)
{
  removeCookie('Count');
  szColor="White";
}

Эта функция вызывается, когда пользователь нажимает кнопку с надписью Параметры по умолчанию:

<INPUT TYPE="reset" VALUE="Параметры по умолчанию"
  onClick="setDefault(this.form);">

Обратите внимание, что данная кнопка имеет тип reset. Когда пользователь ее щелкает, в форме отмечается переключатель, задающий белый цвет фона. Это происходит потому, что указанный переключатель определен с параметром CHECKED, а кнопка типа reset устанавливает все органы управления формы в исходное состояние.

Настройка браузера для работы с Cookie

Хотя Cookie не представляют особой опасности для пользователей, не каждый захочет, чтобы хранящаяся в них информация передавалась на сервер Web. В сочетании с другими полями заголовка HTTP данные Cookie позволяют собирать определенную статистику о пользователях, а это нравится далеко не всем.

Настраивая браузер соответствующим образом, пользователи могут ограничить или вовсе отключить взаимодействие с Cookie. Вы должны это учитывать, если при создании активных документов HTML надеетесь на использование Cookie.

Браузер Microsoft Internet Explorer версии 5.0 допускает установку различных режимов работы с Cookie. Эти режимы указываются в панели Security Settings на вкладке Security блокнота Internet Options (рис. 2-34), доступного из меню Tools.

Рис. 2-34. Установка режимов работы с Cookie

По умолчанию активизирован переключатель Enable, разрешающий применение Cookie. Переключатель Disable полностью запрещает использование Cookie. Если Вы пометите переключатель Prompt, при попытке установить Cookie на экране появится предупреждающее сообщение.

Отладка клиентских сценариев

Если Вы установили Microsoft InterDev 6.0, отладка клиентских сценариев не вызовет у Вас особых сложностей.

Запустите браузер Microsoft Internet Explorer и выберите из меню View строку Script Debugger. Далее в меню второго уровня укажите строку Break at Next Statement. Теперь браузер подготовлен к запуску сценария под отладкой.

Загрузите в окно браузера документ HTML с отлаживаемым сценарием. Это можно сделать, перетаскивая мышью пиктограмму документа в окно браузера или средствами меню File браузера.

Как только будет выполнена любая строка клиентского сценария, запустится отладчик сценариев, встроенный в Microsoft InterDev 6.0. Вы увидите диалоговую панель Microsoft Development Environment, в которой Вам придется подтвердить необходимость запуска сценария под отладкой, щелкнув кнопку Yes. Когда Вы увидите вторую панель с запросом на открытие файла проекта, откажитесь от этой операции, щелкнув кнопку No.

В результате отобразится окно отладчика Microsoft InterDev 6.0, в которое будет загружен исходный текст документа со сценарием. Строка, на которой произошел останов, выделена цветом. Используя кнопки инструментальной панели, Вы сможете поэтапно выполнять сценарий, устанавливать дополнительные точки останова, просматривать содержимое локальных переменных и т. д. Подробное описание приемов работы с отладчиком выходит за рамки нашей книги. При необходимости воспользуйтесь электронной справочной системой, встроенной в Microsoft InterDev 6.0.

[Назад] [Содержание] [Дальше]