Сценарии JavaScript в активных страницах Web

         

Операторы цикла


В языке JavaScript есть несколько операторов, предназначенных для организации циклов.



Операторы для работы с отдельными битами


В своих сценариях вы можете применять операторы, выполняющие над битами переменных такие логические операции, как И, ИЛИ, ИСКЛЮЧАЮЩЕЕ ИЛИ, НЕ:

Оператор

Логическая операция

&

И

|



ИЛИ

^

ИСКЛЮЧАЮЩЕЕ ИЛИ

~

НЕ

Перечисленные выше операторы перед выполнением своих функций преобразуют значения переменных в 32-разрядные целые числа.



Операторы языка JavaScript


Операторы языка сценариев JavaScript напоминают общеизвестные операторы языка C, поэтому мы ограничимся только кратким их описанием.



Операторы отношения


Операторы отношения используются для сравнения значений переменных. Эти операторы возвращают логические значения true или false в зависимости от результата сравнения и применяются главным образом в условных операторах. Эти операторы мы опишем позже в этой главе.

Итак, ниже мы представили список операторов отношения языка сценариев JavaScript:

Оператор отношения

Условие, при котором оператор возвращает значение true

>

Левый операнд больше правого

>=

Левый операнд больше или равен правому

<

Левый операнд меньше правого

<=

Левый операнд меньше или равен правому

==

Левый операнд равен правому

!=

Левый операнд не равен правому

Примеры использования этих операторов вы найдете в разделе, посвященном условным операторам.

В условных операторах также часто применяются логические операторы:

Логический оператор

Описание

Оператор ИЛИ. Возвращает значение true, когда один из операндов равен true

&&

Оператор И. Возвращает значение true, когда оба операнда равны true



Операторы сдвига


Для выполнения операций сдвига в языке JavaScript предусмотрено три оператора:

Оператор сдвига

Назначение

>>

Сдвиг в правую сторону

<<

Сдвиг в левую сторону

>>>

Сдвиг в правую сторону с заполнением освобождаемых разрядов нулями

Перед использованием операторов сдвига значение переменной преобразуется в 32-разрядное целое число.

Ниже мы привели пример, в котором в переменную nValue записывается значение, полученное в результате сдвига бит числа 4. Сдвиг выполняется на два бита влево:

var nValue;

nValue = 4 << 2;



Открываем новое окно


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

Рис. 2.7. Сообщение об открытии документа HTML

Если нажать на кнопку OK в этой диалоговой панели, то в окне браузера появится содержимое документа (рис. 2.8).

Рис. 2.8. Содержимое документа NewWnd.html

В этом окне расположена кнопка “Open Hello window”. Если нажать на эту кнопку, будет создано еще одно окно браузера, в которое загрузится содержимое файла Hello.html. Однако внешний вид этого окна будет несколько необычен (рис. 2.9).

Рис. 2.9. Новое окно для просмотра содержимого документа Hello.html

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

Если теперь закрыть окно документа NewWnd.html, на экране появится диалоговая панель с приглашением, показанная на рис. 2.10.

Рис. 2.10. Диалоговая панель с приглашением

Исходный текст документа HTML NewWnd.html представлен в листинге2.4.

Листинг 2.4. Файл chapter2/NewWnd/NewWnd.html

<HTML>

  <HEAD>

    <TITLE>Window object</TITLE>

    <SCRIPT LANGUAGE="JavaScript">

    <!--

    function Hello()

    {

      window.alert("Welcome to my home page!")

    }

    function Bye()

    {

      window.alert("Bye! Come back again!")

    }

    function OpenHelloWnd()

    {

      var wndNewWindow;

      wndNewWindow =

        window.open("hello.html",

        "",

"toolbar=no,menubar=no,scrollbars=no,width=300,height=100");

    }

    // -->

    </SCRIPT>

  </HEAD>

  <BODY BGCOLOR=white  onLoad="Hello()" onUnload="Bye()">

    <H1>Open second window</H1>

   

    <FORM NAME="selectForm">

      <P><INPUT TYPE="button" VALUE="Open Hello window"


      onClick="OpenHelloWnd();">

    </FORM>   

  </BODY>

</HTML>

В операторе <BODY> мы задали обработку событий onLoad и onUnload:

<BODY BGCOLOR=white onLoad="Hello()" onUnload="Bye()">

Когда пользователь загружает наш документ, после окончания загрузки браузер вызывает функцию Hello, назначенную нами для обработки события onLoad. Перед удалением окна с документом вызывается обработчик события onUnload, реализованный в функции Bye.

Функции Hello и Bye определены в заголовке документа HTML и не имеют никаких особенностей. Для вывода диалоговой панели с сообщением эти функции вызывают метод alert.

Когда пользователь нажимает кнопку "Open Hello window", определенную в форме, вызывается функция OpenHelloWnd. Эта функция открывает новое окно браузера, загружая в него новый документ HTML.

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

wndNewWindow = window.open("hello.html", "",

"toolbar=no,menubar=no,scrollbars=no,width=300,height=100");

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


Отображение нескольких документов HTML


На рис. 4.2 мы показали внешний вид содержимого нашего авторского компакт-диска, первый выпуск которого появился недавно в продаже.

Рис. 4.2. Авторский компакт-диск

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

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

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

При этом если нажать кнопку с надписью “Добро пожаловать”, в заголовке появится наш логотип, показанный на рис. 4.2. Если же нажать кнопку “Книги” или “Статьи”, заголовок будет выглядеть так, как это показано на рис. 4.3 и 4.4, соответственно.

Рис. 4.3. Просмотр информации о книгах

Рис. 4.4. Просмотр информации о статьях

В листинге 4.5 мы показали исходный текст файла описания фреймов.

Листинг 4.5. Файл chapter4/ourCD/index.html

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2//EN">

<HTML>

  <HEAD>

    <TITLE>Авторский диск Александра Фролова и Григория Фролова</TITLE>

  </HEAD>

  <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>


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

Документ заголовка, который отображается сразу после загрузки фрейма, а также после того как пользователь нажмет кнопку “Добро пожаловать”, показан в листинге 4.6.

Листинг 4.6. Файл chapter4/ourCD/title.html

<HTML>

  <HEAD>

    <META HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=windows-1251">

  </HEAD>

  <BODY BACKGROUND="pic/FFON.GIF" BGCOLOR="#ffffff">

    <P>

    <TABLE >

      <TR>

        <TD VALIGN=TOP><A HREF="emailus.htm" TARGET="main page"><IMG SRC="pic/frlogo3.gif" ALT="Александр Фролов и Григорий Фролов, технические писатели из Москвы" BORDER=0></A> 

        <TD VALIGN=TOP><A HREF="emailus.htm" TARGET="main page"><IMG SRC="pic/frlogo.gif" ALT="Александр Фролов и Григорий Фролов, технические писатели из Москвы" BORDER=0></A>

      </TD></TR>

    </TABLE>

    <P>

  </BODY>

</HTML>

Файл main.html представлен в листинге 4.7 (в сокращенном виде). Он не имеет никаких интересных особенностей.

Листинг 4.7. Файл chapter4/ourCD/main.html

<HTML>

  <HEAD>

    <META HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=windows-1251">

    <TITLE>Untitled</TITLE>

  </HEAD>

  <BODY BGCOLOR="#FFFFFF">

    <H2>Добро пожаловать!</H2>

    <P>

    <IMG SRC="pic/cd.gif" ALIGN=LEFT HSPACE=5>

    <P>

    Вы приобрели первый выпуск авторского компакт-диска технических писателей Александра Фролова и Григория Фролова.

      . . .

    <P>

    <CENTER><A HREF="copyrihgt.htm" ><I><FONT SIZE=2>© Александр Фролов, Григорий Фролов, 1997   </FONT></I></A></CENTER>

  </BODY>



</HTML>

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

Листинг 4.8. Файл chapter4/ourCD/toc.html

<HTML>

  <BODY BGCOLOR="#B0FFD8">

  <SCRIPT LANGUAGE="JavaScript">

    <!--

    function loadPage(szNewURL,szTitle)

    {

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

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

    }

    // -->

  </SCRIPT>

  <FONT FACE="Arial, Helvetica" SIZE=1>

  <P>

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

  <BR>

  <A HREF="javascript:loadPage('books/home.html', 'books/title.html');"><IMG SRC="pic/fcd_82.gif" BORDER=0 ALT="Книги"></A>

  <BR>

  <A HREF="javascript:loadPage('articles/articles.html', 'articles/title.html');"><IMG SRC="pic/fcd_102.gif" BORDER=0 ALT="Статьи"></A>

  <BR>

    . . .

  <P>

  </BODY>

</HTML>

Функция loadPage загружает в фреймы mainpage и title документы HTML, адреса URL которых передаются ей через параметры. Для загрузки мы устанавливаем свойство 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 выделено при этом двойными кавычками.


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


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

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

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

Листинг 5.3. Файл chapter5/noise/noise2.html

<HTML>

  <HEAD>

    <TITLE>Animation with JavaScript</TITLE>

    <SCRIPT LANGUAGE="JavaScript">

    <!--

    var nNumberOfImages = 18;

    var i=1;

    var bForward=true;

    var imgArray = new Array(18);

    function loadAllImages(nNumberOfImages)

    {

      var i;

      for(i=0; i<nNumberOfImages; i++)

      {

        imgArray[i] = new Image();

        imgArray[i].src = "img0" + (i+1) + ".gif";

      }

    }

    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);

    }

    // -->

    </SCRIPT>

  </HEAD>

  <BODY BGCOLOR=white>

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

    <SCRIPT LANGUAGE="JavaScript">

    <!--

      loadAllImages(nNumberOfImages);

      showNextImage();

    // -->

    </SCRIPT>

  </BODY>

</HTML>

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


loadAllImages(nNumberOfImages);

showNextImage();

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

Задача функции loadAllImages заключается в заполнении массива объектов класса Image. Этот массив определен в области заголовка нашего документа 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. Она идентична описанной в предыдущем примере, за исключением того что для установки свойства src изображения Img используются элементы заранее подготовленного массива imgArray:

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


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


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

Оператор <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, который загружается в окно фрейма



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


Рассмотрим подробнее параметры оператора <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%">



Parse


Метод parse возвращает количество миллисекунд, прошедших с 00 часов 00 минут 1 января 1970 года по время, указанное в параметре функции. Для вызова этого метода вам не нужно создавать объект класса Date, а можно просто сослаться на имя этого класса:

nMS = Date.parse(szDataString);

Через параметр szDataString вы можете указать время, например, так:

“12 Oct 1998 12:00:00”

“12 Oct 1998 12:00:00 GMT”

“12 Oct 1998 12:00:00 GMT+0330”

Первая из этих строк задает локальную дату и время, вторая - дату и время по Гринвичу, и, наконец, последняя, - время и дату по Гринвичу со смещением на 3 часа и 30 минут.

Метод parse обычно применяют вместе с конструктором объекта Date или с методом setTime, который мы рассмотрим ниже.



Переключатель checkbox


Переключатели checkbox обычно применяются для выбора каких-либо независимых друг от друга параметров или возможностей.

В форме переключатель checkbox создается с помощью оператора <INPUT> с параметром TYPE, равным строке "checkbox":

<INPUT TYPE="checkbox"

  NAME="Имя_переключателя_checkbox"

  VALUE="Значение"

  CHECKED

  onClick="Обработчик_события">

  Текст, отображаемый рядом с переключателем

Параметр NAME задает имя переключателя. Это имя можно использовать для определения состояния этого переключателя в сценарии JavaScript.

С помощью параметра VALUE вы можете определить строку, которая передается расширению сервера при посылке заполненной формы, если переключатель находится во включенном состоянии. Если этот параметр не указан, то по умолчанию посылается строка “on”. Сценарий JavaScript также может получить значение параметра VALUE.

Необязательный параметр

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

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



Переключатель radio


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

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

<INPUT TYPE="radio"

  NAME=" Имя_переключателя_radio"

  VALUE="Значение"

  CHECKED

  onClick="Обработчик_события">

  Текст, отображаемый рядом с переключателем

Назначение параметров NAME, VALUE и CHECKED переключателя radio такое же как и назначение аналогичных параметров переключателя checkbox. Отличие заключается в том, что все переключатели radio, принадлежащие к одной группе, должны иметь одинаковые имена, определенные параметром NAME. Что же касается переключателей checkbox, то если их несколько, то все они должны называться  по-разному.

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

Кроме того, только один из переключателей radio может быть определен с параметром CHECKED.



Переменные в JavaScript


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

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

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



Первый способ: создание 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 приведено ниже:

Поле

Описание

Имя

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

Значение

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

expires

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

domain

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

path

Часть адреса 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.


PI


Свойство PI - это число p. Оно также является константой с приблизительным значением, равным 3,14.

Пример использования свойства PI:

var nL;

var nR;

nL = 2 * Math.PI * nR;

Здесь свойство PI используется для вычисления длины окружности по ее радиусу. Вычисление выполняется по следующей формуле:

l = 2pR,

где R - радиус окружности.



Плавное изменение цвета фона документа HTML


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

Сложный на первый взгляд эффект достигается чрезвычайно просто: изменением свойства bgColor объекта document. В листинге 2.10 мы привели пример сценария, который после загрузки документа HTML в окно браузера изменяет цвет его фона с белого на черный.

Листинг 2.10. Файл chapter2/ChangeBkg/ChangeBkg.html

<HTML>

  <HEAD>

    <TITLE>Color Links</TITLE>

    <SCRIPT LANGUAGE="JavaScript">

    <!--

    var nRed = 255;

    var nGreen = 255;

    var nBlue = 255;

    function colorShift()

    {

      var cmd = "colorShift()";

      document.bgColor = "#" +

        dec2hex(nRed) +

        dec2hex(nGreen) +

        dec2hex(nBlue);

      if(nRed > 0)

      {

        nRed   -= 10;

        nGreen -= 10;

        nBlue  -= 10;

      }

      timer = window.setTimeout(cmd, 50);

    }

    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);

      }

   

      szBuf=szHexTable.charAt(nRem);

      szResult = szBuf.concat(szResult);



Получение cookie расширением сервера Web


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

Наш документ аналогичен описанному ранее в разделе “Записная книжка Cookies Notepad” (рис. 7.8).

Рис. 7.8. Документ HTML, работающий с cookie и расширением сервера ISAPI

Дополнительно мы разместили в документе кнопку Send. С помощью этой кнопки содержимое окна редактирования и заголовок HTTP_COOKIES передается расширению ISAPI сервера Web.

Расширение ISAPI отображает содержимое cookie, как это показано на рис. 7.9.

Рис. 7.9. Результат работы расширения ISAPI

Исходный текст документа HTML вы найдете в листинге 7.4.

Листинг 7.4. Файл chapter7/NotebookISAPI/NotebookISAPI.html

<HTML>

  <HEAD>

    <TITLE>Cookies demo</TITLE>

    <SCRIPT LANGUAGE="JavaScript">

    <!--

    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 + "=" + escape(szValue) + ";

expires=" + dtExpiryDate;

    }

    function findCookie(szName)

    {

      var i = 0;

      var nStartPosition = 0;

      var nEndPosition = 0; 

      var szCookieString = document.cookie; 

      var szTemp = "";

      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;

          szTemp =

            document.cookie.substring(

            nStartPosition,nEndPosition); 

          return unescape(szTemp);

          break;   

        }

        i++; 

      }

      return "";

    }

    function removeCookie(szName)

    {

      var dtExpires = new Date();

      dtExpires.setTime(dtExpires.getTime() - 1);

      var szValue = findCookie(szName);

      document.cookie = szName + "=" + szValue +

        "; expires=" + dtExpires.toGMTString();

    }

    function btnClick()

    {

      addCookie("MyText",TestForm.Comment.value,10);

    }

    // -->

    </SCRIPT>

  </HEAD>

  <BODY BGCOLOR=white>

    <H1>Cookies Notepad</H1>

    <FORM NAME="TestForm" METHOD=POST ACTION="http://frolov/scripts/ishello.dll?">

      <P><TEXTAREA NAME="Comment"

        ROWS="5" COLS="25" WRAP="physical">

      </TEXTAREA>

      <P><INPUT TYPE="button" VALUE="Store text"

      onClick="btnClick();">

      <INPUT TYPE="button" VALUE="Clear text"

      onClick =

        "removeCookie('MyText');TestForm.Comment.value=''">

      <P><INPUT TYPE=submit VALUE="Send">

    </FORM>   

    <SCRIPT LANGUAGE="JavaScript">

    <!--

      var szMyText="";

      szMyText = findCookie("MyText");

      if(szMyText != "")

      {

        TestForm.Comment.value = szMyText;

      }

    // -->

    </SCRIPT>

  </BODY>

</HTML>

В нем, по сравнению с документом из раздела “Записная книжка Cookies Notepad”, мы добавили параметр ACTION в оператор <FORM>, а также кнопку типа submit с надписью Send. С помощью этой кнопки данные из формы отправляются расширению ISAPI:



  . . .

<FORM NAME="TestForm" METHOD=POST ACTION="http://frolov/scripts/ishello.dll?">

  . . .

<INPUT TYPE=submit VALUE="Send">

. . .

Исходный текст расширения ISAPI представлен в листинге 7.5. Он сделан на базе примера, взятого из 29 тома нашей “Библиотеки системного программиста” (раздел “Приложение ISHELLO” восьмой главы).

Листинг 7.5. Файл chapter7/NotebookISAPI/ishello.c

// ===============================================

// Расширение ISAPI ishello.c

// Пример расширения ISAPI, отображающего

// содержимое cookie

//

// (C) Фролов А.В., 1997, 1998

// E-mail: frolov@glas.apc.org

// WWW:    http://www.glasnet.ru/~frolov

//         или

//         http://www.dials.ccas.ru/frolov

// ===============================================

#include <windows.h>

#include <httpext.h>

// =========================================================

// Функция GetExtensionVersion

// Запись версии интерфейса ISAPI и

// строки описания расширения

// =========================================================

BOOL WINAPI GetExtensionVersion(HSE_VERSION_INFO *pVer)

{

  // Записываем версию интерфейса ISAPI

  pVer->dwExtensionVersion =

    MAKELONG(HSE_VERSION_MINOR,HSE_VERSION_MAJOR );

  // Записываем строку описания расширения

  lstrcpyn(pVer->lpszExtensionDesc,

    "Cookie show ISAPI DLL", HSE_MAX_EXT_DLL_NAME_LEN);

  return TRUE;

}

// =========================================================

// Функция HttpExtensionProc

// =========================================================

DWORD WINAPI HttpExtensionProc(EXTENSION_CONTROL_BLOCK *lpECB)

{

  CHAR  szBuff[4096];

  CHAR  szTempBuf[4096];

 

  DWORD  dwSize;

  // Нулевой код состояния - признак успешного выполнения

  lpECB->dwHttpStatusCode = 0;

  // Записываем в буфер заголовок HTTP и начальный

  // фрагмент формируемого динамически документа HTML

  wsprintf(szBuff,



    "Content-Type: text/html\r\n\r\n"

    "<HTML><HEAD><TITLE>Simple ISAPI Extension</TITLE></HEAD>\n"

    "<BODY BGCOLOR=#FFFFFF><H2>Hello from ISAPI Extension!</H2>\n");

  // Добавляем разделительную линию

  strcat(szBuff, "<HR>");

 

  // Добавляем версию интерфейса ISAPI

  wsprintf(szTempBuf, "<P>Extension Version: %d.%d",

    HIWORD(lpECB->dwVersion), LOWORD(lpECB->dwVersion));

  strcat(szBuff, szTempBuf);

 

  // Название метода передачи данных

  wsprintf(szTempBuf, "<BR>Method: %s", lpECB->lpszMethod);

  strcat(szBuff, szTempBuf);

 

  // Строка параметров запуска расширения ISAPI

  wsprintf(szTempBuf, "<BR>QueryString: %s",

    lpECB->lpszQueryString);

  strcat(szBuff, szTempBuf);

 

  // Физический путь к программному файлу расширения ISAPI

  wsprintf(szTempBuf, "<BR>PathTranslated: %s",

    lpECB->lpszPathTranslated);

  strcat(szBuff, szTempBuf);

  // Полный размер данных, которые нужно получить

  wsprintf(szTempBuf, "<BR>TotalBytes: %d",

    lpECB->cbTotalBytes);

  strcat(szBuff, szTempBuf);

  // Тип данных

  wsprintf(szTempBuf, "<BR>ContentType: %s",

    lpECB->lpszContentType);

  strcat(szBuff, szTempBuf);

  // Отображаем содержимое COOKIE

  strcat(szBuff, "<HR><P><B>Cookie:</B><BR>");

  dwSize = 4096;

  lpECB->GetServerVariable(lpECB->ConnID,

    (LPSTR)"HTTP_COOKIE", (LPVOID)szTempBuf, &dwSize);

  strcat(szBuff, szTempBuf);

  // Конечный фрагмент документа HTML

  strcat(szBuff, "</BODY></HTML>"); 

  // Посылаем содержимое буфера удаленному пользователю

  if(!lpECB->ServerSupportFunction(lpECB->ConnID,

    HSE_REQ_SEND_RESPONSE_HEADER, NULL, NULL,

    (LPDWORD)szBuff))



  {

    // Если послать данные не удалось,

    // завершаем работу нашего расширения ISAPI

    // с кодом ошибки

    return HSE_STATUS_ERROR;

  }

  // Записываем код успешного завершения

  lpECB->dwHttpStatusCode = 200;

 

  // Возвращаем принак успешного завершения 

  return HSE_STATUS_SUCCESS;

}

Файл определения модуля для библиотеки DLL расширения приведен в листинге 7.6.

Листинг 7.6. Файл chapter7/NotebookISAPI/ishello.def

LIBRARY            ishello

DESCRIPTION  'Simple ISAPI DLL'

EXPORTS

    GetExtensionVersion

    HttpExtensionProc

Для извлечения значения cookie, предаваемого расширению через заголовки HTTP, мы использовали функцию GetServerVariable, указав ей в качестве второго параметра имя интересующей нас переменной HTTP_COOKIE:

lpECB->GetServerVariable(lpECB->ConnID,

    (LPSTR)"HTTP_COOKIE", (LPVOID)szTempBuf, &dwSize);

Полученное таким образом значение дописывается в буфер динамически создаваемого документа HTML. Этот буфер впоследствии будет отправлен клиенту при помощи функции ServerSupportFunction.


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


Итак, вы научились создавать cookie в сценариях JavaScript. Теперь решим другую задачу - определение значения параметров 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 достаточно просто.



Pow


Возведение числа в заданную степень.

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

var nValue;

nValue = Math.pow(2, 3);

Здесь число 2 возводится в степень 3, а результат, равный 8, записывается в переменную nValue.



В этой книге мы расскажем


В этой книге мы расскажем о новой технологии, предназначенной для разработчиков серверов Web. Это язык сценариев JavaScript, получивший широкое распространение в глобальной сети Internet.
Для тех, кто еще не знаком с Internet, предназначен наш 23 том “Библиотеки системного программиста”, который называется “Глобальные сети компьютеров. Практическое введение в Internet, E-Mail, FTP, WWW и HTML, программирование для Windows sockets”. Здесь вы найдете всю информацию, необходимую для того чтобы подключиться к этой сети и приступить к работе.
Тем из вас, кто интересуется созданием собственных серверов в сети Internet, мы рекомендуем прочитать 29 том “Библиотеки системного программиста” с названием “Сервер Web своими руками”. В этом томе мы рассказали о языке разметки гипертекста HTML, о программах CGI и приложениях ISAPI, а также, конечно, о том, как установить и настроить свой сервер Web.
Многие современные серверы Web являются активными или содержат активные страницы, которые взаимодействуют с пользователем. Описанные в только что упомянутом 29 томе программы CGI и приложения ISAPI позволяют создавать активные серверы Web, способные получать данные от удаленного пользователя, обрабатывать их и посылать результат обработки обратно в виде документа HTML. В качестве примера активных приложений, работающих на сервере Web, можно назвать чрезвычайно популярные счетчики посещений, гостевые книги, базы данных, доступные через Internet и так далее.
Что же касается активных страниц Web, то с их помощью также можно создавать диалоговые приложения, однако обработка введенных данных выполняется не на сервере, а на рабочей станции пользователя, то есть локально. Активными мы будем называть документы HTML, которые содержат в себе аплеты Java, а также программы, составленные на таких языках, как JavaScript и VBScript.
Преимущества, которые можно получить при использовании активных страниц, заключаются не только в улучшении внешнего вида страниц (что само по себе немаловажно), но и в снижении потока данных между рабочей станцией пользователя и сервером Web, а также в снижении загрузки этого сервера. Это, в свою очередь, благоприятно сказывается на скорости реакции сервера.


Что касается аплетов и полноценных приложений Java, то им посвящены тома 30 и 32 “Библиотеки системного программиста”, которые называются “Создание приложений Java. Часть 1” и “Создание приложений Java. Часть 2”, соответственно. Размещая на страницах сервера Web аплеты Java, вы можете выполнять на рабочей станции достаточно сложную локальную обработку данных. Реализация такой обработки с помощью программ CGI или приложений ISAPI была бы затруднительной или вовсе невозможной.
Предметом изучения книги, которую вы сейчас держите в руках, является еще одно средство, предназначенное для создания активных страниц - язык JavaScript.
Заметим сразу, что язык JavaScript не имеет никакого отношения к языку Java, несмотря на схожее название.
Язык программирования Java был создан фирмой Sun и произошел от языка Oak. По своему синтаксису он сильно похож на С++, однако есть немаловажные отличия, описанные нами в 30 томе “Библиотеки системного программиста”.
Первоначальное название языка JavaScript, разработанного фирмой Netscape Communication Corporation, было LiveScript. Затем, после того как язык Java получил всемирную известность, LiveScript переименовали в JavaScript. Возможно, это было сделано фирмой Netscape из коммерческих соображений: все, что имело в своем названии ключевое слово “Java”, вызывало живой интерес.
При разработке языка программирования JavaScript предполагалось, что он будет предназначен для непрофессионалов. По простоте использования JavaScript больше всего напоминает Basic, хотя с помощью него квалифицированные программисты могут решать достаточно серьезные и, что немаловажно, полезные задачи.
В первой главе нашей книги мы приведем семь сценариев JavaScript, демонстрирующих основные возможности этого языка, расскажем о переменных и операторах JavaScript.
Во второй главе мы расскажем о классах и объектах JavaScript. Заметим, что несмотря на свою простоту, JavaScript является объектно-ориентированным языком. Мы приведем достаточно полное описание классов, доступных разработчикам сценариев JavaScript, и многочисленные примеры применения этих классов.


Третья глава посвящена описанию приемов обработки сценариями JavaScript данных, которые пользователи вводят в полях формы, а также другим аспектом интеграции сценариев JavaScript и форм. Мы подробно расскажем об объектах JavaScript, создаваемых для органов управления форм, и научим их использовать в практике разработки интерактивных документов HTML. Отдельно будут рассмотрены вопросы проверки содержимого полей формы перед их отправкой расширению сервера Web для обработки.
В четвертой главе мы расскажем о том, как с помощью сценариев JavaScript можно передавать данные между различными фреймами и получать эффекты, недостижимые в случае применения одного только языка разметки гипертекста HTML.
Сценарий JavaScript может работать с растровыми графическими изображениями, расположенными в документе HTML, обращаясь к ним как к объектам JavaScript. В пятой главе мы описали методику динамической замены растрового графического изображения, которую можно использовать для “оживления” документа HTML.
Шестая глава затрагивает вопросы взаимодействия сценария JavaScript с аплетами Java, встроенными в документ HTML. Такое взаимодействие предусматривает вызов из сценария JavaScript методов, определенных в аплете, а также обращение к полям классов аплета.
В седьмой главе мы подробно рассмотрим механизм cookie, предназначенный для организации локального хранения информации пользователя. Эту информацию можно устанавливать и считывать как при помощи сценариев JavaScript, так и расширениями сервера Web (программами CGI или приложениями ISAPI). Мы приведем исходные тексты сценариев JavaScript и расширений сервера Web, работающих с cookie.
Что вам потребуется для работы с книгой?
Прежде всего, нужен компьютер, оснащенный 8-16 Мбайт оперативной памяти с операционной системой Microsoft Windows 95 или Microsoft Windows NT. Вам также потребуются браузер Microsoft Internet Explorer версии 4.0 и отладчик Microsoft Script Debugger. Последние две программы вы можете бесплатно переписать к себе с сервера Web корпорации Microsoft по адресу http://www.microsoft.com/ie. Для проверки совместимости созданных вами программ неплохо также иметь браузер Netscape Navigator 3.0 или 4.0, демонстрационную версию которого можно бесплатно получить с сервера http://www.netscape.com.


Для редактирования программ JavaScript вы можете применять любые средства создания документов HTML, хотя вполне достаточно редактора, входящего в комплект отладчика Microsoft Script Debugger или даже приложения Notepad.
Кроме всего прочего, чтобы составлять программы на JavaScript, вы должны быть знакомы с языком HTML. Для изучения этого языка мы рекомендуем вам прочитать 29 том нашей “Библиотеки системного программиста”, содержащей описание HTML в необходимом объеме.
Для отладки сценариев JavaScript, описанных в седьмой главе и взаимодействующих с расширениями сервера Web, вам потребуется сервер Microsoft Internet Information Server. Вы можете использовать также сервер Web, входящий в комплект операционной системы Microsoft Windows NT Workstation версии 4.0 или даже Microsoft Personal Web Server, разработанный для Microsoft Windows 95. Сервер Microsoft Personal Web Server доступен для бесплатной загрузки из Internet.
Исходные тексты всех программ вы можете найти на компакт-диске, который продается вместе с книгой. Эти тексты, так же как и исходные тексты программ из всех предыдущих томов “Библиотеки системного программиста”, есть также и на нашем авторском компакт-диске. Подробная информация об авторском компакт-диске есть в сети Internet на сервере авторов этой книги по адресу http://www.glasnet.ru/~frolov или http://www.dials.ccas.ru/frolov.
Мы выражаем благодарность генеральному директору АО “ДиалогНаука” Антимонову Сергею Григорьевичу и его заместителю Лященко Юрию Павловичу за возможность размещения информации о наших книгах на сервере Web по адресу http://www.dials.ccas.ru/frolov, а также за возможность доступа к сети Internet через сервер АО “ДиалогНаука”.
Мы также благодарим корректора Кустова В. С. и сотрудников издательского отдела АО “Диалог-МИФИ” Голубева О. А., Дмитриеву Н. В., Виноградову Е. К., Кузьминову О. А.

Предметный указатель


--, 18

-, 18

!, 18

!=, 19

%, 18

%=, 20

&, 19

&&, 19

&=, 20

&nbsp;, 17

(), 22

*, 18

*=, 20

,, 22

., 22

/, 18

/=, 20

?:, 21

[], 22

^, 19

^=, 20

_blank, 48

_parent, 48

_self, 48

_top, 48

|, 19

, 19

|=, 20

~, 19

+, 18

++, 18

+=, 20

<, 19

<<, 19

<<=, 20

<=, 19

<A>, 46; 48; 95

<APPLET>, 108

<BODY>, 45

<CAPTION>, 31

<FORM>, 32; 60

<FRAME>, 95

<FRAMESET>, 35; 94

<IMG>, 102

<INPUT>, 62

<META>, 43

<NOFRAME>, 94

<OPTION>, 69

<PARAM>, 108; 115

<SCRIPT>, 8

<SELECT>, 69

<TEXTAREA>, 75

-=, 20

=, 20

==, 19

>, 19

>=, 19

>>, 19

>>=, 20

>>>, 19

>>>=, 20

abs, 53

acos, 53

ACTION, 61; 134

alert, 14; 33

ALIGN, 95; 102; 108

ALINK, 45

alinkColor, 46

ALT, 102; 108

anchor, 46

anchors, 46

applets, 46

Array, 26; 32

asin, 53

atan, 53

BACKGROUND, 45

BGCOLOR, 45; 46

blur, 70; 73; 76; 80

bold, 12

Boolean, 26

BORDER, 31; 94; 102

break, 16; 21

button, 61; 62

case, 16

catch, 16

ceil, 53

CGI, 60; 61; 82; 119; 135

checkbox, 61; 63; 64

CHECKED, 63; 64

class, 16

clear, 46

clearTimeout, 33; 35; 41

click, 64

close, 33; 34; 36; 46

CODE, 108

CODEBASE, 108

COLS, 76; 94

confirm, 33

const, 16

continue, 16; 22

cookie, 46; 119

cos, 53

Data, 27

Date, 26; 54; 121

debugger, 16

default, 16

defaultChecked, 64

defaultSelected, 70

defaultStatus, 32

defaultValue, 73; 80

delete, 16

directories, 34

do, 16

document, 8; 28; 46

document.applets, 109

E, 52

elements, 61

else, 16

else-if, 20

embeds, 46

encoding, 61

ENCTYPE, 61

enum, 16

escape, 57

eval, 57

exp, 54

export, 16

extends, 16

false, 16

fgColor, 46

finally, 16

floor, 54

focus, 70; 73; 76; 80

for, 16; 21

for-in, 21

form, 46; 61

forms, 46

frame, 28

FRAMEBORDER, 94; 95

frames, 32

FRAMESPACING, 94

function, 16; 26

GET, 61

getAppletInfo, 113

getDate, 27; 55

getDay, 55


getHours, 27; 55

getMinutes, 27; 55

getMonth, 27; 55

getSeconds, 27; 55

getTime, 55; 121

getTimeZoneOffset, 56

getYear, 27; 56

GIF, 102; 104

Global, 26

GMT, 121

hash, 48

height, 34; 102; 108

hidden, 61

history, 46

host, 48

hostname, 48

HREF, 48; 101

HSPACE, 102; 108

HTML версии 4.0, 10

HTTP, 119; 132; 139

HTTP_COOKIE, 132; 139

HTTP_COOKIES, 132

HTTPS, 120

if, 16

images, 46

Img, 107

import, 16

in, 16

index, 70

ISAPI, 60; 61; 82; 119; 132

ISMAP, 102

isNaN, 17

Java, 7; 108

JavaScript, 7; 101

JPEG, 102

LANGUAGE, 8

lastModified, 46

length, 32; 48; 61; 64; 69; 70

LINK, 45; 46

linkColor, 46

links, 46; 48

LN10, 53

LN2, 53

location, 28; 34; 46

log, 54

LOG10E, 53

LOG2E, 53

Lynx, 10

MARGINHEIGHT, 95

MARGINWIDTH, 95

Math, 26; 52

max, 54

menubar, 34

METHOD, 61

MIME, 46; 61

min, 54

MULTIPLE, 69

name, 32; 48; 61; 62; 63; 64; 69; 70; 73; 76; 80; 95; 102; 108; 109

NAME,, 64

NaN, 17

navigator, 15

navigator.appName, 15

navigator.appVersion, 15

new, 16; 121

NORESIZE, 95

Not a Number, 17

null, 16; 17

Number, 26

Object, 26

off, 76

onBlur, 70; 73; 76

onChange, 70; 73; 76

onClick, 46; 48; 113

onFocus, 70; 73; 76; 96

onLoad, 28; 35; 38; 43; 45; 46; 94

onMouseover, 14; 46; 48

onSelect, 73; 76

onUnload, 28; 35; 38; 45; 46; 94

open, 33; 34; 46

options, 69

parent, 28; 32

parse, 56

parseFloat, 17; 57

parseInt, 17; 18; 57

password, 61; 79; 80

pathname, 48

physical, 76

PI, 52

plug-in, 46

port, 48

POST, 61

pow, 54

prompt, 33; 34; 44

protocol, 48

QUERY_STRING, 139

radio, 61; 64

random, 54

referrer, 46

reset, 61

resizable, 34

return, 16; 23

round, 54

ROWS, 76; 94

scrollbars, 34

SCROLLING, 95

search, 48

select, 61; 69; 73; 76; 80

SELECTED, 69; 70

selectedIndex, 69; 70

self, 32

Set-Cookie, 119; 136; 139

setDate, 56

setHours, 56

setMinutes, 56

setMonth, 56

setSeconds, 56

setTime, 56

setTimeout, 33; 34; 39; 40; 41

setYear, 57

sin, 54

SIZE, 69; 73; 80

sqrt, 54

SQRT1_2, 53

SQRT2, 53

SRC, 9; 42; 95; 102; 103



SSL, 120

status, 32; 34; 39

String, 26

SUBMIT, 61; 82

super, 16

switch, 16

tan, 54

TARGET, 32; 48; 61

TEXT, 45; 61; 70; 73

textarea, 62; 75; 76

this, 16; 29

throw, 16

title, 46; 108

toGMTString, 57; 121

toLocaleString, 57

toolbar, 34

top, 28; 32

true, 16

try, 16

TYPE, 10; 62

typeof, 16

unescape, 57

Unicode, 17

URL, 46

USEMAP, 102

UTC, 57

VALUE, 62; 63; 64; 69; 70; 73; 80; 109

var, 16; 21

var , 16

VBScript, 7

virtual, 76

VLINK, 45

vlinkColor, 46

void, 16

VSPACE, 102; 108

while, 16; 21

width, 34; 102; 108

window, 28; 32; 33; 39

with, 16

WRAP, 76

write, 8; 46

writeln, 46

адрес IP, 48

адрес URL, 48

аплеты Java, 102

бинарные операторы, 18

встроенные объекты, 26

встроенные функции, 57

выделение комментариев, 8

диалоговая панель, 12

зарезервированные ключевые слова JavaScript, 16

кодовая страница 1251, 43

комментарий, 8

компоненты ActiveX, 102

логические данные, 17

массивы, 32

неопределенный тип, 17

нечисло, 17

обработка событий, 13

оператор присваивания, 19

оператор присвоения, 16

операторы отношения, 19

операторы сдвига, 19

операторы цикла, 21

операторы языка HTML, 8

определение типа и версии браузера, 14

переменные, 10; 15

символ неразделяющего пробела, 17

таблица старшинства операторов JavaScript, 22

текстовые строки, 17

типы данных, 16

унарные операторы, 18

условные операторы, 20

функции, 10; 23

числа, 16

язык LiveScript, 8

язык Perl, 7

язык пакетных заданий MS-DOS, 7

язык сценариев UNIX, 7


Преобразование типов данных


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

Поясним это на примере (листинг 1.9).

Листинг 1.9. Файл Conversion/Conversion.html

<HTML>

  <HEAD>

    <TITLE>Type conversion sample</TITLE>

  </HEAD>

  <BODY BGCOLOR=white>

    <H1>Type conversion sample</H1>

    <TABLE>

    <SCRIPT LANGUAGE="JavaScript">

    <!--

      var szTextBuf = "";

      szTextBuf = 4 + "&nbsp;- число четыре" + "<BR>";

      szBuf2 = (parseInt("2") + 2) + "&nbsp;- число четыре" + "<BR>";

      document.write(szTextBuf + szBuf2);

    // -->

    </SCRIPT>

    </TABLE>

  </BODY>

</HTML>

Здесь мы объявили переменную szTextBuf и проинициализировали ее пустой строкой. Далее мы присвоили этой строке сумму числа 4 и двух текстовых строк:

szTextBuf = 4 + "&nbsp;- число четыре" + "<BR>";

При вычислении этого выражения значение 4 было автоматически преобразовано в текстовую строку. Дальнейшее суммирование выполнялось как слияние (конкатенация) трех текстовых строк.

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

В следующей строке мы преобразовываем текстовую строку “2” в численное значение с помощью функции parseInt, прибавляем к результату преобразования число 2, а затем выполняем конкатенацию с двумя текстовыми строками:

szBuf2 = (parseInt("2")+2)+"&nbsp;- число четыре"+ "<BR>";

В результате переменная szBuf2 будет содержать ту же самую строку, что и переменная szTextBuf, в чем нетрудно убедиться, взглянув на рис. 1.8.

Рис. 1.8. Результат работы сценария, представленного в листинге 1.9

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



Работа с отладчиком Microsoft Script Debugger


Для отладки создаваемых вами сценариев JavaScript удобно использовать специальные отладчики, например, отладчик Microsoft Script Debugger. Вы можете получить его бесплатно с сервера Microsoft, расположенного в Internet по адресу http://www.microsoft.com.



формы с переключателями


В этом разделе мы приведем исходный текст документа HTML со сценарием, предназначенным для динамического создания новой страницы при помощи сценария JavaScript. Параметры этой страницы определяются состоянием переключателей типа checkbox и radio, расположенными в этом документе (рис. 3.3).

Рис. 3.3. Форма с переключателями различных типов

Наш документ содержит одну форму, в которой есть три переключателя с независимой фиксацией типа checkbox (расположенные в группе Page elements), три переключателя с зависимой фиксацией (образующие группу Text color), и две кнопки - Create Page и Reset.

Если включен переключатель Show title, создаваемый сценарием JavaScript документ HTML будет снабжен заголовком. При включении переключателя Show horizontal lines информация о состоянии переключателей, отображаемая в документе, будет выделена сверху и снизу горизонтальными разделительными линиями.

Переключатель Table view влияет на способ отображения информации. Если он включен, информация будет показана в табличном виде, а если выключен - в виде списка (рис. 3.4).

Рис. 3.4. Отображение состояния переключателей в виде списка

Внешний вид страницы при включении всех трех переключателей группы Page elements показан на рис. 3.5.

Рис. 3.5. Отображение состояния переключателей в виде таблицы с заголовком, выделенной линиями

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

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

Текст документа HTML со сценарием, выполняющим все описанные выше действия, представлен в листинге 3.2.


Листинг 3.2. Файл chapter3/checkradio/checkradio.html
<HTML>
  <HEAD>
  <SCRIPT>
    <!--
    function resetRCHBox()
    {
      bTitle=false;
      bHorzLine=false;
      bTable=false;
      szColor="Red";
    }
    function chkRadio(form,value)
    {
      szColor = value;
    }
    function btnClick(form)
    {
      var szTxt="";
      document.write("<HEAD></HEAD><BODY>");    
      if(bTitle)
        document.write("<H1> Switches Checkbox and Radio</H1>");    
      if(bHorzLine)
        document.write("<HR>");    
      if(bTable)
      {
        document.write("<TABLE>");    
        szTxt=" " + bTitle;
        document.write("<TR><TD><FONT COLOR=" + szColor
+ ">Title:</TD><TD>" + szTxt.bold() + "</TD></TR>");    
        szTxt=" " + bHorzLine;
        document.write("<TR><TD><FONT COLOR=" + szColor
+ ">HorzLine:</TD><TD>" + szTxt.bold() + "</TD></TR>");    
        szTxt=" " + bTable;
        document.write("<TR><TD><FONT COLOR=" + szColor
+ ">Table:</TD><TD>" + szTxt.bold() + "</TD></TR>");    
        document.write("<TR><TD><FONT COLOR=" + szColor
+ ">Color:</TD><TD>" + szColor.bold() + "</TD></TR>");    
        document.write("</TABLE>");    
      }
      else
      {
        document.write("<FONT COLOR=" + szColor + ">");    
        szTxt=" " + bTitle;
        document.write("<BR>Title: " + szTxt.bold());    
        szTxt=" " + bHorzLine;


        document.write("<BR>HorzLine: " + szTxt.bold());    
        szTxt=" " + bTable;
        document.write("<BR>Table: " + szTxt.bold());    
        document.write("<BR>Color: " + szColor.bold());    
        document.write("</FONT>");    
      }
      if(bHorzLine)
        document.write("<HR>");    
      document.write("</BODY>");    
    }
    // -->
  </SCRIPT>
    <TITLE> Переключатели checkbox и radio</TITLE>
  </HEAD>
  <BODY>
  <SCRIPT>
    <!--
    var bTitle=false;
    var bHorzLine=false;
    var bTable=false;
    var szColor="Red";
    // -->
  </SCRIPT>
    <FORM NAME="myform">
     <B>Page elements:</B>
     <P><INPUT TYPE="checkbox" NAME="chkTitle"
        onClick="if(this.checked) {bTitle=true;}"> Show title
     <BR><INPUT TYPE="checkbox" NAME="HorzLine"
        onClick="if(this.checked) {bHorzLine=true;}"> Show horizontal lines
     <BR><INPUT TYPE="checkbox" NAME="Table"
        onClick="if(this.checked) {bTable=true;}"> Table view
     <P><B>Text color:</B>
     <P><INPUT TYPE="radio" NAME="Color" CHECKED VALUE="Red"
        onClick="if(this.checked) {chkRadio(this.form,this.value);}"> Red
     <BR><INPUT TYPE="radio" NAME="Color" VALUE="Green"
        onClick="if(this.checked) {chkRadio(this.form,this.value);}"> Green
     <BR><INPUT TYPE="radio" NAME="Color" VALUE="Blue"
        onClick="if(this.checked) {chkRadio(this.form,this.value);}"> Blue


     <TABLE>
       <TR><TD><INPUT TYPE="button" NAME="btn" VALUE="Create Page"
       onClick="btnClick(this.form);"></TD>
       <TD><INPUT TYPE="reset" NAME="resetBtn" VALUE="Reset"
        onClick="resetRCHBox();"></TD></TR>
     </TABLE>
    </FORM>
  </BODY>
</HTML>
В области заголовка документа HTML мы определили три функции с именами resetRCHBox, chkRadio и btnClick.
Первая из этих функций предназначена для инициализации переменных, в которых хранится текущее состояние переключателей:
function resetRCHBox()
{
  bTitle=false;
  bHorzLine=false;
  bTable=false;
  szColor="Red";
}
Функция resetRCHBox вызывается в тот момент, когда пользователь нажимает в исходном документе кнопку Reset. Она устанавливает значения четырех переменных.
Переменные bTitle, bHorzLine и bTable отражают состояние, соответственно, переключателей с независимой фиксацией Show title, Show horizontal lines и Table view. Если переключатель включен, в соответствующей переменной хранится значение true, если выключен - false.
В переменной szColor находится цвет текста, выбранный с помощью группы переключателей с зависимой фиксацией Text color.
Начальное состояние переменных, задаваемое функцией resetRCHBox, соответствует начальному состоянию переключателей сразу после загрузки исходного документа HTML в окно браузера.
Для того чтобы обеспечить вызов функции resetRCHBox при нажатии на кнопку Reset, в определении этой кнопки задан обработчик события onClick, как это показано ниже:
<INPUT TYPE="reset" NAME="resetBtn" VALUE="Reset"
        onClick="resetRCHBox();">
Обработка события заключается в простом вызове функции.
Теперь мы займемся переключателями с зависимой фиксацией.
Эти переключатели определены в форме следующим образом:
<INPUT TYPE="radio" NAME="Color" CHECKED VALUE="Red"


  onClick="if(this.checked)
    {chkRadio(this.form,this.value);}"> Red
<BR><INPUT TYPE="radio" NAME="Color" VALUE="Green"
  onClick="if(this.checked)
    {chkRadio(this.form,this.value);}"> Green
<BR><INPUT TYPE="radio" NAME="Color" VALUE="Blue"
  onClick="if(this.checked)
    {chkRadio(this.form,this.value);}"> Blue
Когда пользователь изменяет состояние переключателя, делая по нему щелчок левой клавишей мыши, вызывается обработчик события onClick. Для всех кнопок этот обработчик выглядит одинаково:
if(this.checked)
{
  chkRadio(this.form,this.value);
}
Прежде всего обработчик проверяет состояние переключателя, вызывая для этого метод checked. Ссылка на объект, для которого вызывается этот метод (то есть на переключатель), выполняется с помощью ключевого слова this.
В том случае, когда переключатель включен, обработчик вызывает функцию chkRadio, определенную в заголовке документа следующим образом:
function chkRadio(form,value)
{
  szColor = value;
}
Хотя мы передаем функции два параметра (ссылку на форму, содержащую переключатель, и значение параметра VALUE текущего переключателя), используется только второй параметр. Значение этого параметра, определяющее цвет текста, сохраняется в переменной szColor.
Работа с переключателями типа checkbox выполняется немного проще:
<INPUT TYPE="checkbox" NAME="chkTitle"
  onClick="if(this.checked) {bTitle=true;}"> Show title
<BR><INPUT TYPE="checkbox" NAME="HorzLine"
  onClick="if(this.checked) {bHorzLine=true;}"> Show horizontal lines
 <BR><INPUT TYPE="checkbox" NAME="Table"
  onClick="if(this.checked) {bTable=true;}"> Table view
Когда пользователь включает переключатель, обработчик события onClick устанавливает в состояние true соответствующую переменную. Например, при изменении состояния переключателя Show title выполняются следующие действия:


if(this.checked)
{
  bTitle=true;
}
Последний орган управления, который мы рассмотрим, это кнопка Create Page. Эта кнопка запускает процесс создания нового документа HTML. Для нее также определен обработчик события onClick:
<INPUT TYPE="button" NAME="btn" VALUE="Create Page"
  onClick="btnClick(this.form);">
Этот обработчик вызывает функцию btnClick, передавая ей в качестве параметра ссылку на форму.
Функция btnClick определена в области заголовка документа HTML, исходный текст которого представлен в листинге 3.2.
Внутри этой функции мы определили рабочую текстовую переменную szTxt, присвоив ей значение пустой строки:
var szTxt="";
Когда функция btnClick получает управление, прежде всего она формирует пустую область заголовка документа HTML:
document.write("<HEAD></HEAD><BODY>");    
Далее функция анализирует содержимое переменной bTitle:
if(bTitle)
  document.write("<H1>Switches Checkbox and Radio</H1>");
Если перед тем как нажать кнопку Create Page пользователь включил переключатель Show title, в переменной bTitle будет находиться значение true. В этом случае сценарий снабдит формируемый документ заголовком “Switches Checkbox and Radio”, оформив его стилем <H1>.
Аналогичным образом анализируется содержимое переменной bHorzLine:
if(bHorzLine)
  document.write("<HR>");
Эта переменная отражает состояние переключателя Show horizontal lines.
Далее функция btnClick анализирует содержимое переменной bTable, отвечающей за способ отображения информации о состоянии переключателей в создаваемом документе HTML:
if(bTable)
{
  . . .
}
else
{
  . . .
}
Если переключатель Table view находится во включенном состоянии, информация отображается в виде таблицы.
При формировании первого столбца таблицы цвет текста внутри ячейки устанавливается в соответствии с содержимым переменной szColor:
szTxt=" " + bTitle;
document.write("<TR><TD><FONT COLOR=" + szColor
  + ">Title:</TD><TD>" + szTxt.bold() + "</TD></TR>");     
Напомним, что эта переменная хранит значение цвета текста, установленное группой переключателей с зависимой фиксацией Text color.
Если состояние переключателей отображается в виде списка строк, цвет текста устанавливается следующим образом:
document.write("<FONT COLOR=" + szColor + ">");    

Пример сценария


В качестве первого примера мы приведем сценарий, выполняющего обработку щелчка по кнопке с надписью Click me, расположенной в форме (рис. 3.1).

Рис. 3.1. Форма в документе HTML с кнопкой

Если нажать на эту кнопку, сценарий отобразит в окне браузера свойства кнопки как объекта класса button (рис. 3.2).

Рис. 3.2. Отображение свойств кнопки как объекта класса button

Исходный текст документа HTML со встроенным в него сценарием JavaScript приведен в листинге 3.1.

Листинг 3.1. Файл chapter3/button/button.html

<HTML>

  <HEAD>

    <TITLE>Button demo</TITLE>

    <SCRIPT LANGUAGE="JavaScript">

    <!--

    function btnClick()

    {

      var szTxt="";

      var szTxt1="";

      szTxt=document.TestForm.bt.value;

      szTxt1=document.TestForm.bt.name;

      document.write("<HR>");    

      document.write("You press button: " + szTxt.bold()

+ ", name=" + szTxt1.bold());    

      document.write("<HR>");    

    }

    // -->

    </SCRIPT>

  </HEAD>

  <BODY BGCOLOR=white>

    <H1>Click Button</H1>

    <FORM NAME="TestForm">

      <P><INPUT TYPE="button" NAME="bt" VALUE="Click me!"

      onClick="btnClick();">

    </FORM>   

  </BODY>

</HTML>

В теле документа HTML определена форма с именем TestForm, для чего в операторе <FORM> мы указали параметр NAME. Другие параметры этого оператора здесь не нужны.

Форма содержит одну-единственную кнопку с именем bt и надписью Click me. Для этой кнопки в качестве обработчика события мы назначили функцию btnClick, определенную в заголовке документа HTML.

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

szTxt=document.TestForm.bt.value;

szTxt1=document.TestForm.bt.name;

Затем функция выводит в окно браузера строку, ограниченную сверху и снизу разделительной линией, отображающую значение свойств value и name:

document.write("<HR>");    

document.write("You press button: " + szTxt.bold()

  + ", name=" + szTxt1.bold());    

document.write("<HR>");    



Пример сценария, заполняющего поле textarea


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

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

Рис. 3.11. Форма для отправки отзыва о работе программы

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

Для отправки отзыва нажмите кнопку Complete. В результате на экране появится диалоговая панель с текстом положительного отзыва (рис. 3.12).

Рис. 3.12. Диалоговая панель с текстом положительного отзыва

Для того чтобы сообщить изготовителю программы об ошибках, включите переключатель “Проблемы”. Сразу после этого сценарий запишет в многострочное поле текст соответствующего сообщения. Этот текст надо будет отредактировать и дополнить, описав, например, внешние проявления обнаруженной ошибки (рис. 3.13).

Рис. 3.13. Отправка сообщения об ошибке

Нажав кнопку Complete, вы увидите текст сообщения (рис. 3.14).

Рис. 3.14. Полный текст сообщения об ошибке, обнаруженной в программе

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

Листинг 3.5. Файл chapter3/textarea/textarea.html

<HTML>

  <HEAD>

    <TITLE>Работа с многострочным текстовым полем</TITLE>

    <SCRIPT LANGUAGE="JavaScript">

    <!--

    var szOK = "Спасибо!\nВаша программа работает без ошибок.";

    var szTrouble = "К сожалению, с вашей программой у нас возникли проблемы.";

    var szProbList = "\nСерийный номер программы: ХХХХХХ\nДата покупки: ХХ-ХХ-ХХ";


    function getDate()
    {
      var szDate = "";
      szDate = new Date();
      return szDate.toLocaleString() + "\n";
    }
    function chkRadio(form,value)
    {
      if(value == "Thanks")
        Sel.Comment.value = getDate() + szOK;
      else
        Sel.Comment.value = getDate() + szTrouble + szProbList;
    }
    function init()
    {
        Sel.Comment.value = getDate() + szOK;
    }
    function Complete()
    {
      szMsg = Sel.Comment.value;
      alert(szMsg);     
    }
    // -->
    </SCRIPT>
  </HEAD>
  <BODY BGCOLOR=white>
    <H1>Пришлите ваш отзыв</H1>
    <FORM NAME="Sel">
      <P><INPUT TYPE="radio" NAME="TextSelect" CHECKED VALUE="Thanks"
        onClick="if(this.checked) {chkRadio(this.form,this.value);}"> Благодарность
      <BR><INPUT TYPE="radio" NAME="TextSelect" VALUE="Trouble"
        onClick="if(this.checked) {chkRadio(this.form,this.value);}"> Проблемы
      <P><TEXTAREA NAME="Comment"
        ROWS="5"   COLS="25" WRAP="physical">
      </TEXTAREA>
      <P><INPUT TYPE="button" VALUE="Complete" onClick="Complete();">
    </FORM>
    <SCRIPT LANGUAGE="JavaScript">
    <!--
      init();
    // -->
    </SCRIPT>
  </BODY>
</HTML>
Обратите внимание, что в нашей форме многострочное поле редактирования текста textarea создано пустым:
<TEXTAREA NAME="Comment"
  ROWS="5" COLS="25" WRAP="physical">
</TEXTAREA>
Это поле называется “Comment”, имеет пять строк, в которых размещается до 25 символов, и режим свертки текста physical, предполагающий добавление символов новой строки, разделяющих отдельные строки введенного текста.


Как происходит заполнение этого поля?
В самом конце области тела документа HTML, ограниченного операторами <BODY> и </BODY>, мы вставили вызов функции init:
<SCRIPT LANGUAGE="JavaScript">
<!--
  init();
// -->
</SCRIPT>
Эта функция вызывается после завершения загрузки тела документа и выполняет начальное заполнение многострочного поля редактирования textarea:
Sel.Comment.value = getDate() + szOK;
Строка, которая записывается в это поле, образуется путем сложения строки текущей даты, полученной от функции getDate (эту функцию мы определили в нашем сценарии), со строкой szOK, содержащей текст положительного отзыва.
Функция getDate определена следующим образом:
function getDate()
{
  var szDate = "";
  szDate = new Date();
  return szDate.toLocaleString() + "\n";
}
В этой функции мы сначала создаем объект класса Data, а затем вызываем для этого объекта метод toLocaleString, возвращающий текстовую строку даты.
В верхней части формы находятся два переключателя с зависимой фиксацией. С помощью этих переключателей пользователь может выбрать вид отзыва (благодарность или сообщение об ошибке):
<INPUT TYPE="radio" NAME="TextSelect" CHECKED VALUE="Thanks"
   onClick="if(this.checked)
     {chkRadio(this.form,this.value);}"> Благодарность
<BR><INPUT TYPE="radio" NAME="TextSelect" VALUE="Trouble"
   onClick="if(this.checked)
     {chkRadio(this.form,this.value);}"> Проблемы
Оба переключателя относятся к одной группе и потому имеют одинаковое значение параметра NAME. Для первого из них мы дополнительно указали параметр CHECKED, поэтому по умолчанию он находится во включенном состоянии (здесь мы предположили, что количество положительных отзывов будет превышать количество сообщений об ошибках).
Каждый из переключателей имеет обработчик события onClick, определенный следующим образом:
if(this.checked)


{
  chkRadio(this.form,this.value);
}
При изменении состояния переключателя вызывается функция chkRadio. Эта функция проверяет имя включенного переключателя и заполняет поле многострочного редактора textarea соответствующим сообщением:
function chkRadio(form,value)
{
  if(value == "Thanks")
    Sel.Comment.value = getDate() + szOK;
  else
    Sel.Comment.value = getDate() + szTrouble + szProbList;
}
Функция chkRadio комбинирует тексты сообщений из текущей даты и заранее проинициализированных строк szOK, szTrouble и szProbList.
Теперь о том, как наш сценарий получает текст из поля редактирования и отображает его в диалоговой панели.
Для кнопки Complete мы определили обработчик события onClick:
<INPUT TYPE="button" VALUE="Complete" onClick="Complete();">
Этот обработчик вызывает функцию Complete, отображающую подготовленный отзыв на экране:
function Complete()
{
  szMsg = Sel.Comment.value;
  alert(szMsg);     
}
Здесь текст извлекается из поля textarea как значение свойства value для соответствующего объекта, а затем отображается на экране при помощи встроенной функции alert.

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


Приведем три примера использования операторов цикла for и while.

Во всех этих примерах сценарий отображает в окне документа десять строк “Hello, world!”, как это показано на рис. 1.9.

Рис. 1.9. Сценарий отображает в документе HTML десять одинаковых строк

Исходный текст первого сценария представлен в листинге 1.10.

Листинг 1.10. Файл chapter1/Operators/for.html

<HTML>

  <HEAD>

    <TITLE>Hello, world!</TITLE>

    <SCRIPT LANGUAGE="JavaScript">

    <!--

    var n = 10;

    var szHelloMsg = "Hello, world!";

    function printNString(szString, n)

    {

      var i;

      for(i = 0; i < n; i++)

      {

        document.write(szString.bold() + "<BR>");

      }

    }

    function printHello()

    {

      printNString(szHelloMsg, 10);

    }

    // -->

    </SCRIPT>

  </HEAD>

  <BODY BGCOLOR=white>

    <H1>JavaScript Test</H1>

    <P>Message:<BR>

    <SCRIPT LANGUAGE="JavaScript">

    <!--

    printHello();

    // -->

    </SCRIPT>  </BODY>

</HTML>

Здесь сразу после загрузки документа вызывается функция printHello. В теле этой функции, в свою очередь, вызывается функция printNString, которой передаются два параметра:

printNString(szHelloMsg, 10);

Через первый параметр этой функции мы передаем текстовую строку szHelloMsg, а через второй - количество повторов этой строки при выводе.

Вывод строки выполняется функцией printNString в цикле:

for(i = 0; i < n; i++)

{

  document.write(szString.bold() + "<BR>");

}

Здесь значение переменной цикла i изменяется от нуля до n, где n - количество повторов. Когда значение переменной цикла достигнет значения n, цикл будет завершен.

В листинге 1.11 показан сценарий, решающий ту же самую задачу другим методом - с использованием оператора while.

Листинг 1.11. Файл chapter1/Operators/while.html

<HTML>

  <HEAD>


    <TITLE>Hello, world!</TITLE>
    <SCRIPT LANGUAGE="JavaScript">
    <!--
    var n = 10;
    var szHelloMsg = "Hello, world!";
    function printNString(szString, n)
    {
      var i;
      i = 0;
      while(i < n)
      {
        document.write(szString.bold() + "<BR>");
        i++;
      }
    }
    function printHello()
    {
      printNString(szHelloMsg, 10);
    }
    // -->
    </SCRIPT>
  </HEAD>
  <BODY BGCOLOR=white>
    <H1>JavaScript Test</H1>
    <P>Message:<BR>
    <SCRIPT LANGUAGE="JavaScript">
    <!--
    printHello();
    // -->
    </SCRIPT>  </BODY>
</HTML>
Здесь i также используется как переменная цикла:
i = 0;
while(i < n)
{
  document.write(szString.bold() + "<BR>");
  i++;
}
Как работает этот цикл?
После вывода строки методом write значение переменной цикла увеличивается на единицу. Затем перед началом следующей итерации проверяется, достигла ли переменная цикла значения n. Если достигла, цикл завершает свою работу.
Совместное применение операторов while и break демонстрируется в сценарии, показанном в листинге 1.12.
Листинг 1.12. Файл chapter1/Operators/break.html
<HTML>
  <HEAD>
    <TITLE>Hello, world!</TITLE>
    <SCRIPT LANGUAGE="JavaScript">
    <!--
    var n = 10;
    var szHelloMsg = "Hello, world!";
    function printNString(szString, n)
    {
      var i;
      i = 0;
      while(true)
      {
        document.write(szString.bold() + "<BR>");
        i++;
        if(i > n)
          break;
      }
    }
    function printHello()
    {
      printNString(szHelloMsg, 10);
    }
    // -->
    </SCRIPT>
  </HEAD>
  <BODY BGCOLOR=white>
    <H1>JavaScript Test</H1>
    <P>Message:<BR>
    <SCRIPT LANGUAGE="JavaScript">
    <!--
    printHello();
    // -->
    </SCRIPT>  </BODY>
</HTML>
Так же как и в предыдущем случае, i используется как переменная цикла, однако в операторе while на месте условия завершения цикла стоит значение true:
i = 0;
while(true)
{
  document.write(szString.bold() + "<BR>");
  i++;
  if(i > n)
    break;
}
Для того чтобы прервать цикл, мы применили оператор break. Этот оператор вызывается в том случае, если значение переменной цикла i превысило значение n.

Примеры сценариев, работающих со списками


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



Присвоение значения переменным


Вы можете присвоить значение переменной при помощи оператора присвоения “=”. Например, ниже мы объявляем переменную и затем записываем в нее текстовую строку:

var szHelloMsg;

szHelloMsg = “Hello, world!”;

В любом месте программы мы можем присвоить переменной szHelloMsg численное значение, например, так:

szHelloMsg = 4;

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

Вы можете присвоить переменной специальное значение null:

szHelloMsg = null;

Такое присвоение не назначает переменной никакого типа. Оно  применяется в тех случаях, когда вам нужно объявить переменную и проинициализировать ее, не присваивая этой переменной никакого начального значения и типа. В частности, в только что приведенном примере переменной szHelloMsg не присваивается ни численное значение 0, ни пустая текстовая строка.



Процесс отладки сценария


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



Прочие операторы


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

Оператор

Описание

.

Доступ к полю объекта

[]

Индексирование массива

()

Скобки

,

Запятая

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

Ниже, например, мы вызвали метод write, определенный в объекте document:

document.write("Hello, world!");

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

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

Оператор запятая предназначен для разделения выражений, которые должны оцениваться последовательно. Этот прием называется многократным вычислением. Например, в фрагменте исходного текста, показанном ниже, на каждой итерации цикла выполняется увеличение содержимого переменных i и nCycleCount:

var i;

var nCycleCount = 0;

for(i = 0; i < 25; i++, nCycleCount++)

{

  . . .

}



Просмотр открытых документов в окне отладчика


Чтобы загрузить в отладчик документ HTML, выберите из меню View строку Running Documents. С помощью этой строки вы можете открыть окно Running Documents, в котором отображается список документов, доступных для отладки (рис. 8.5).

Рис. 8.5. В отладчик загружены два документа HTML

Чтобы открыть документ, достаточно сделать двойной щелчок левой клавишей мыши по соответствующей строке списка.



Просмотр стека вызова функций


Выбрав из меню View строку Call Stack, вы можете просмотреть содержимое стека вызова функций.

В примере, показанном на рис. 8.10, функция printString была вызвана из функции printHello, которая, в свою очередь, была вызвана в глобальном контексте.

Рис. 8.10. Просмотр стека вызова функций

Окно просмотра Call Stack может оказать вам помощь при отладке сценариев с большой глубиной вложенности вызовов функций.



Просмотр значений переменных и свойств объектов


Для того чтобы просмотреть значения переменных или свойств объектов, вам необходимо открыть окно Command Window (рис. 8.7). Это можно сделать при помощи строки Command Window, расположенной в меню View.

Рис. 8.7. Работа с окном Command Window

Для того чтобы просмотреть значение переменной или свойства объекта, достаточно набрать имя этой переменной или ссылку на объект в окне Command Window и нажать клавишу <Enter>.

На рис. 8.7 мы определили значение свойств navigator.appName, navigator.appVersion, а также значение, записанное в строке szHelloMsg.



Проверка анкеты


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

Рис. 3.9. Форма для ввода анкеты

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

Если после заполнения анкеты нажать кнопку Complete, на экране появится диалоговая панель, отображающая содержимое отдельных полей формы (рис. 3.10).

Рис. 3.10. Отображение содержимого полей анкеты

Кнопка Reset устанавливает поля в исходное состояние.

Исходный текст документа HTML с описанной выше формой и сценарием JavaScript вы найдете в листинге 3.4.

Листинг 3.4. Файл chapter3/text/text.html

<HTML>

  <HEAD>

    <TITLE>Работа с текстовыми полями</TITLE>

    <SCRIPT LANGUAGE="JavaScript">

    <!--

    function Complete()

    {

      var szElement="";

      szElement="Фамилия: " + Sel.family.value +

        "\nИмя: " + Sel.Name.value +

        "\nТелефон: " + Sel.PhoneNumber.value +

        "\nВозраст: " + Sel.Age.value;

      alert(szElement);     

    }

    function CheckAge(age)

    {

      if(age < 18)

        return "0";

      else

        return age;

    }

    // -->

    </SCRIPT>

  </HEAD>

  <BODY BGCOLOR=white>

    <H1>Заполните анкету</H1>

    <FORM NAME="Sel">

      <TABLE>

       <TR><TD><B>Фамилия:</B></TD><TD><INPUT TYPE="text"

        NAME="family"

        onChange="this.value=this.value.toUpperCase()"

        SIZE="20" ></TD></TR>

      <TR><TD><B>Имя:</B></TD><TD><INPUT TYPE="text"


        NAME="Name" SIZE="20"></TD></TR>

      <TR><TD><B>Телефон:</B></TD><TD><INPUT TYPE="text"

        NAME="PhoneNumber" SIZE="10"></TD></TR>

      <TR><TD><B>Возраст:</B></TD><TD><INPUT TYPE="text"

        NAME="Age" VALUE="18" SIZE="4"

        onChange="this.value=CheckAge(this.value)"

        onFocus="this.select()"

        ></TD></TR>

      <P>

      <TABLE>

        <TR><TD><INPUT TYPE="button" VALUE="Complete"

        onClick="Complete();"></TD>

        <TD><INPUT TYPE="reset" VALUE="Reset"></TD></TR>

      </TABLE>

    </FORM>

  </BODY>

</HTML>

Для того чтобы преобразовать символы фамилии в прописные, для поля family мы определили обработчик события onChange:

onChange="this.value=this.value.toUpperCase()"

После внесения изменений в содержимое поля этот обработчик вызывает метод toUpperCase, определенный в классе строк. Преобразованное значение записывается снова в свойство this.value.

Поле Age имеет два обработчика для событий onChange и onFocus:

onChange="this.value=CheckAge(this.value)"

onFocus="this.select()"

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

Функция CheckAge выглядит очень просто:

function CheckAge(age)

{

  if(age < 18)

    return "0";

  else

    return age;

}

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



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

Кнопку Complete пользователь нажимает после заполнения анкеты. Для нее мы определили обработчик события onClick:

<INPUT TYPE="button" VALUE="Complete"

   onClick="Complete();">

Этот обработчик вызывает функцию с именем Complete, в задачу которой входит отображение содержимого полей формы. Исходный текст функции Complete мы привели ниже:

function Complete()

{

  var szElement="";

  szElement="Фамилия: " + Sel.family.value +

    "\nИмя: " + Sel.Name.value +

    "\nТелефон: " + Sel.PhoneNumber.value +

    "\nВозраст: " + Sel.Age.value;

  alert(szElement);     

}

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


Проверка заполнения формы


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

Если вы ранее занимались созданием расширений сервера Web, обрабатывающих данные, полученные от форм, то знаете, что для посылки данных расширению используется кнопка типа submit. Эта кнопка встраивается в форму следующим образом:

<INPUT TYPE="submit"

  NAME="Имя_кнопки_submit"

  VALUE="Текст_на_поверхности_кнопки"

  onClick="Обработчик_события">

Параметры NAME и VALUE здесь имеют такое же назначение, что и для изученной нами ранее кнопки типа button.

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

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

Простейший выход из этой ситуации - замена кнопки типа submit на обычную кнопку button. С этой кнопкой должен быть связан сценарий JavaScript, который проверяет данные, введенные пользователем в поля формы, и посылающий их серверу Web явным образом.

В этом разделе мы приведем исходные тексты документа HTML, предназначенного для ввода идентификатора пользователя и пароля (листинг 3.7). Это документ аналогичен приведенному в предыдущем разделе. В нашем примере с помощью сценария JavaScript мы не только проверяем пароль, но и отправляем данные расширению сервера Web, если пароль введен правильно.

Листинг 3.7. Файл chapter3/validation/validation.html


<HTML>

  <HEAD>

    <TITLE>Ввод и проверка пароля</TITLE>

    <SCRIPT LANGUAGE="JavaScript">

    <!--

    function Complete()

    {

      if(Sel.pwd.value != Sel.pwd1.value)

        alert("Ошибка при вводе пароля\nПопробуйте еще раз"); 

      else   

      {

        var szId="";

        var szPwd="";

        szId = Sel.id.value;

        szPwd = Sel.pwd.value;

        alert("Регистрация выполнена:\n" + "ID=" +

          szId + "\nPassword=" + szPwd); 

       

        document.forms[0].submit();

      }

    }

    // -->

    </SCRIPT>

  </HEAD>

  <BODY BGCOLOR=white>

    <H1>Регистрация</H1>

    <FORM METHOD=POST NAME="Sel" ACTION="http://frolov/scripts/controls.exe">

      <TABLE>

       <TR><TD><B>Идентификатор:</B></TD><TD><INPUT TYPE="text"

        NAME="id" onChange="this.value=this.value.toUpperCase()"

        SIZE="20" ></TD></TR>

      <TR><TD><B>Пароль:</B></TD><TD><INPUT TYPE="password"

        NAME="pwd" SIZE="20"></TD></TR>

      <TR><TD><B>Проверка пароля:</B></TD><TD><INPUT TYPE="password"

        NAME="pwd1" SIZE="20"></TD></TR>

      </TABLE>

      <P>

      <TABLE>

        <TR><TD><INPUT TYPE="button" VALUE="Complete"

        onClick="Complete();"></TD>

        <TD><INPUT TYPE="reset" VALUE="Reset"></TD></TR>

      </TABLE>

    </FORM>

  </BODY>

</HTML>

При определении формы для оператора <FROM> мы указали параметр ACTION:



<FORM METHOD=POST NAME="Sel" ACTION="http://frolov/scripts/controls.exe">

Этот параметр задает путь к загрузочному файлу программы CGI, расположенному в каталоге сценариев сервера Web. Отметим, что такой каталог создается администратором сервера Web. С помощью специальной программы администратор указывает права доступа к этому каталогу, разрешающие исполнение расположенных там загрузочных файлов CGI и библиотек динамической компоновки DLL приложений ISAPI. Подробно об этом вы можете прочитать в 29 томе нашей “Библиотеки системного программиста”, который называется “Сервер Web своими руками”.

Функция Complete, которая вызывается при нажатии на одноименную кнопку, проверяет пароли, введенные в полях pwd и pwd1. Если эти пароли совпадают, сценарий посылает данные серверу с помощью метода submit, определенного в форме:

document.forms[0].submit();

Здесь мы обращаемся к первой (и единственной) форме, определенной в нашем документе HTML.

Программа CGI с именем control.exe отображает полученные данные в динамически создаваемом документе HTML (рис. 3.18).



Рис. 3.18. Данные, полученные программой CGI от формы

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

Исходный текст программы CGI, с которой работает наш документ HTML, показан в листинге 3.8.

Листинг 3.8. Файл chapter3/validation/controls/controls.c

// ===============================================

// Программа CGI controls.c

// Получение данных от формы и их

// отображение в документе HTML,

// создаваемом динамически

//

// (C) Фролов А.В., 1997, 1998

// E-mail: frolov@glas.apc.org

// WWW:    http://www.glasnet.ru/~frolov

//         или

//         http://www.dials.ccas.ru/frolov

// ===============================================

#include <stdio.h>

#include <stdlib.h>

#include <string.h>

// Прототипы функций перекодировки

void DecodeStr(char *szString);

char DecodeHex(char *str);



// ------------------------------------------------

// Функция main

// Точка входа программы CGI

// ------------------------------------------------

void main(int argc, char *argv[])

{

  int lSize;

  FILE * fileReceived;

  char * szMethod;

  char szBuf[8196];

  char szSrcBuf[8196];

  char * szPtr;

  char * szParam;

  // Вывод заголовка HTTP и разделительной строки

  printf("Content-type: text/html\n\n");

  // Вывод начального форагмента документа HTML,

  // формируемого динамически

  printf("<!DOCTYPE HTML PUBLIC"

    " \"-//W3C//DTD HTML 3.2//EN\">");

  printf("<HTML><HEAD><TITLE>User Registration"

    "</TITLE></HEAD><BODY BGCOLOR=#FFFFFF>");

  // Определяем метод передачи данных

  szMethod = getenv("REQUEST_METHOD");

  // Обработка метода POST

  if(!strcmp(szMethod, "POST"))

  {

    // Определяем размер данных, полученных от браузера

    // при передаче данных из полей формы

    lSize = atoi(getenv("CONTENT_LENGTH"));

    // Читаем эти данные в буфер szBuf из

    // стандартного потока ввода STDIN

    fread(szBuf, lSize, 1, stdin);

    // Создаем файл, в который будут записаны

    // принятые данные

    fileReceived = fopen("received.dat", "w");

    // Выполняем запись принятых данных

    fwrite(szBuf, lSize, 1, fileReceived);

    // Закрываем файл принятых данных

    fclose(fileReceived);

    // Отображаем значения некоторых переменных среды

    printf("<H2>Переменные среды</H2>");

   

    // Метод доступа

    printf("REQUEST_METHOD = %s", getenv("REQUEST_METHOD"));

    // Размер полученных данных в байтах

    printf("<BR>CONTENT_LENGTH = %ld", lSize);

    // Тип полученных данных

    printf("<BR>CONTENT_TYPE = %s", getenv("CONTENT_TYPE"));



    // Закрываем буфер данных двоичным нулем,

    // превращая его таким образом в строку

    szBuf[lSize] = '\0';

    // Делаем копию принятых данных в буфер szSrcBuf

    strcpy(szSrcBuf, szBuf);

    // Отображаем принятые данные без обработки

    printf("<H2>Принятые данные</H2>");

    printf("<P>%s", szSrcBuf);

    // Выполняем перекодировку принятых данных

    DecodeStr(szSrcBuf);

    // Отображаем результат перекодировки

    printf("<H2>Данные после перекодировки</H2>");

    printf("<P>%s", szSrcBuf);

    // Выводим список значений полей формы

    printf("<H2>Список значений полей</H2>");

   

    // Дописываем в конец буфера принятых данных

    // символ "&", который используется в качестве

    // разделителя значений полей

    szBuf[lSize] = '&';

    szBuf[lSize + 1] = '\0';

    // Цикл по полям формы

    for(szParam = szBuf;;)

    {

      // Ищем очередной разделитель

      szPtr = strchr(szParam, '&');

     

      // Если он найден, раскодируем строку параметров

      if(szPtr != NULL)

      {

        *szPtr = '\0';

        DecodeStr(szParam);

     

        // Выводим в документ значение параметра

        printf("%s<BR>", szParam);

        // Переходим к следующему параметру

        szParam = szPtr + 1;

        // Если достигнут конец буфера, завершаем цикл

        if(szParam >= (szBuf + lSize))

          break;

      }

      else

        break;

    }

   

    // Выводим завершающий фрагмент документа HTML

    printf("</BODY></HTML>");

    return;

  }

}

// ------------------------------------------------

// Функция DecodeStr

// Раскодирование строки из кодировки URL

// ------------------------------------------------

void DecodeStr(char *szString)

{

  int src;

  int dst;



  char ch;

  // Цикл по строке

  for(src=0, dst=0; szString[src]; src++, dst++)

  {

    // Получаем очередной символ перекодируемой строки

    ch = szString[src];

    // Заменяем символ "+" на пробел

    ch = (ch == '+') ? ' ' : ch;

   

    // Сохраняем результат

    szString[dst] = ch;

   

    // Обработка шестнадцатеричных кодов вида "%xx"

    if(ch == '%')

    {

      // Выполняем преобразование строки "%xx"

      // в код символа

      szString[dst] = DecodeHex(&szString[src + 1]);

      src += 2;

    }

  }

 

  // Закрываем строку двоичным нулем

  szString[dst] = '\0';

}

// ------------------------------------------------

// Функция DecodeHex

// Раскодирование строки "%xx"

// ------------------------------------------------

char DecodeHex(char *str)

{

  char ch;

  // Обрабатываем старший разряд

  if(str[0] >= 'A')

    ch = ((str[0] & 0xdf) - 'A') + 10;

  else

    ch = str[0] - '0';

  // Сдвигаем его влево на 4 бита

  ch <<= 4;

  // Обрабатываем младший разряд и складываем

  // его со старшим

  if(str[1] >= 'A')

    ch += ((str[1] & 0xdf) - 'A') + 10;

  else

    ch += str[1] - '0';

  // Возвращаем результат перекодировки

  return ch;

}

Это упрощенный вариант программы CGI, которую мы описали в упомянутом выше 29 томе “Библиотеки системного программиста”. Там вы найдете ее полное описание.


Работа с готовым списком


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

Рис. 3.6. Форма с двумя списками различного размера

Первый из этих списков предназначен для выбора цвета, а второй - размера некоторого предмета (в данном случае не имеет значение, какого именно).

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

Рис. 3.7. Форма с раскрытым списком

Помимо списков, в форме есть две кнопки с надписями Complete и Reset. Кнопка Reset возвращает списки в исходное состояние, в котором они находились сразу после отображения документа HTML. Если же сделать щелчок по кнопке Complete, управление получит сценарий JavaScript, который отобразит выбранный цвет и размер на экране в виде диалоговой панели с сообщением (рис. 3.8).

Рис. 3.8. Выбранный цвет и размер

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

Листинг 3.3. Файл chapter3/select/select.html

<HTML>

  <HEAD>

    <TITLE>Работа со списками</TITLE>

    <SCRIPT LANGUAGE="JavaScript">

    <!--

    function Complete()

    {

      var szElement="";

      szElement="Цвет: " +

        Sel.ColorList.options[Sel.ColorList.selectedIndex].value +

        " (" + Sel.ColorList.selectedIndex + ")" +

        "\nРазмер: " +

        Sel.SizeList.options[Sel.SizeList.selectedIndex].value +

        " (" + Sel.SizeList.selectedIndex + ")";

      alert(szElement);     

    }

    // -->

    </SCRIPT>


  </HEAD>

  <BODY BGCOLOR=white>

    <H1>Работа со списками</H1>

    <FORM NAME="Sel">

      <P>Выберите цвет:<P>   

      <SELECT NAME="ColorList">

        <OPTION VALUE=Черный SELECTED> Черный  

        <OPTION VALUE=Белый> Белый  

        <OPTION VALUE=Красный> Красный  

        <OPTION VALUE=Оранжевый> Оранжевый

        <OPTION VALUE=Желтый> Желтый  

        <OPTION VALUE=Зеленый> Зеленый

        <OPTION VALUE=Голубой> Голубой

        <OPTION VALUE=Синий> Синий

        <OPTION VALUE=Фиолетовый> Фиолетовый

      </SELECT>

      <P>Выберите размер:<P>   

      <SELECT NAME="SizeList" SIZE=3>

        <OPTION VALUE=Стандартный SELECTED> Стандартный

        <OPTION VALUE=Большой> Большой  

        <OPTION VALUE=Средний> Средний  

        <OPTION VALUE=Маленький> Маленький

        <OPTION VALUE=Очень_маленький> Очень маленький

      </SELECT>

      <P>

      <TABLE>

        <TR><TD><INPUT TYPE="button" VALUE="Complete"

        onClick="Complete();"></TD>

        <TD><INPUT TYPE="reset" VALUE="Reset"></TD></TR>

      </TABLE>

    </FORM>

  </BODY>

</HTML>

Как видно из этого листинга, в документе определена форма с именем Sel, содержащая списки ColorList и SizeList. Во втором списке мы задали размер видимой части, указав в операторе <SELECT> параметр SIZE со значением, равным трем. В результате, как это видно из рис. 3.6, в видимой части списка отображается три элемента.

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

szElement="Цвет: " +

Sel.ColorList.options[Sel.ColorList.selectedIndex].value +

  " (" + Sel.ColorList.selectedIndex + ")" +

  "\nРазмер: " +

Sel.SizeList.options[Sel.SizeList.selectedIndex].value +

  " (" + Sel.SizeList.selectedIndex + ")";

alert(szElement);

При этом прежде всего определяются номера элементов, выбранных из списков. Эти номера равны, соответственно, Sel.ColorList.selectedIndex (для списка цветов) и Sel.SizeList.selectedIndex (для списка размеров).

Далее эти номера используются как индексы в массивах options соответствующих списков, содержащих свойства элементов списков. Нас интересует свойство value, при помощи которого можно определить значение для выбранных элементов списков. Каждый элемент наших списков имеет такое значение, заданное при помощи параметра VALUE оператора <OPTION>.


Random


Метод random возвращает случайное число в интервале от 0 до 1.

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

var nRandomValue;

nRandomValue = Math.random();



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


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

<IMG SRC="Адрес_файла_изображения"

  NAME="Имя_изображения"

    . . .

  WIDTH="Ширина"

  HEIGHT="Высота">

Здесь мы указали только три параметра. Полный список параметров оператора <IMG> с кратким их описанием вы найдете ниже:

Параметр

Описание

SRC

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

NAME

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

ALT

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

ALIGN

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

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

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

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

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

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

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

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

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

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

HEIGHT

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

WIDTH

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

BORDER

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

HSPACE

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

VSPACE

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

USEMAP

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

ISMAP

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

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

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

Применение сегментированной графики мы подробно рассмотрели в 29 томе “Библиотеки системного программиста.

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

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


Round


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

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

var nValue;

nValue = Math.round(1.8);

После выполнения округления значение nValue будет равно 2.



Сценарии, работающие с объектами window


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



Счетчик посещений на базе cookie и программы CGI


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

Внешний вид исходного документа HTML, вызывающего программы CGI, показан на рис. 7.10.

Рис. 7.10. Документ HTML, вызывающий программу CGI

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

Если нажать на кнопку с надписью Go to page, программа GCI создаст документ HTML, предварительно проанализировав заголовок пришедшего к ней запроса на предмет наличия в нем информации о cookie. Кнопка Remove All Cookies предназначена для вызова программы CGI с целью удаления cookie.

В том случае, когда этой информации нет, программа CGI динамически сформирует документ HTML, добавив к его заголовку HTTP заголовок Set-Cookie (рис. 7.11).

Рис. 7.11. Документ HTML, создаваемый программой CGI при первом посещении

При последующих посещениях cookie уже определен, и наша программа CGI получает его значение, интерпретируя это значение как счетчик посещений. Затем она увеличивает значение счетчика на единицу, и записывает заголовок Set-Cookie в заголовок HTTP создаваемого документа HTML с новым значением cookie.

Значение счетчика посещений отображается в теле документа (рис. 7.12).

Рис. 7.12. Документ HTML, создаваемый программой CGI при третьем посещении

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

Исходный документ HTML представлен в листинге 7.7.

Листинг 7.7. Файл chapter7/AgainCGI/AgainCGI.html

<HTML>

  <HEAD>

    <TITLE>Cookies demo</TITLE>

  </HEAD>

  <BODY BGCOLOR=white>

    <H1>Visit our page!</H1>

    <FORM METHOD=POST ACTION="http://frolov/scripts/again.exe?go">


      <P><INPUT TYPE="submit" VALUE="Go to page">

    </FORM>   

    <FORM METHOD=POST ACTION="http://frolov/scripts/again.exe?clear">

      <P><INPUT TYPE="submit" VALUE="Remove All Cookies">

    </FORM>   

  </BODY>

</HTML>

В этом документе определены две формы.

Первая форма предназначена для вызова программы CGI с параметром go, а вторая - с параметром clear.

Исходный текст программы CGI, использованной в нашем примере, вы найдете в листинге 7.8.

Листинг 7.8. Файл chapter7/AgainCGI/Again.c

// ===============================================

// Расширение CGI, предназначенное для

// работы с cookie

//

// (C) Фролов А.В., 1998

// E-mail: frolov@glas.apc.org

// WWW:    http://www.glasnet.ru/~frolov

//         или

//         http://www.dials.ccas.ru/frolov

// ===============================================

#include <windows.h>

#include <stdio.h>

#include <stdlib.h>

#include <string.h>

// Прототипы функций, определенных в нашей программе

char *findCookie(char * szName);

void insertHTML(char * pszFileName, char * pszBuf);

void main(int argc, char *argv[])

{

  char * pszQueryString;

  char * pszCookie;

  char * pszMyCookie;

  int nCount;

  char szBuf[4096];

  char szBuf1[20];

 

  // Заголовок для добавления cookie

  char szCookieHeader[] =

    "Set-Cookie: AgainCount=0;\r\nContent-type: text/html\r\n\r\n";

 

  // Заголовок для удаления cookie

  char szCookieRemoveHeader[] =

    "Set-Cookie: AgainCount=0;expires=Mon 03-May-1993 12:00:00 GMT;"

    "\r\nContent-type: text/html;\r\n\r\n";

  // Получаем параметр запуска CGI

  pszQueryString = getenv("QUERY_STRING");

  // Получаем строку Cookie из заголовка HTTP

  pszCookie = getenv("HTTP_COOKIE");

  // Посещение страницы

  if(!strcmp(pszQueryString, "go"))

  {



    // Если cookie не обнаружен, создаем его

    if(pszCookie == NULL)

    {

      // Выводим заголовок для создания cookie

      printf("Content-type: text/html\r\n");

      printf(szCookieHeader);

     

      // Выводим приглашение для первого посещения

      printf("<HTML><HEAD><TITLE>Cookie

demo</TITLE></HEAD><BODY>");

      printf("<H2>Welcome to our page!</H2>");

    }

    else

    {

      // Получаем значение параметра cookie

      // с именем AgainCount

      pszMyCookie = findCookie("AgainCount");

      if(pszMyCookie != NULL)

      {

        // Преобразуем это значение в число и увеличиваем

        // на единицу при каждом посещении

        nCount = atoi(pszMyCookie);

        nCount++;

        sprintf(szBuf1, "%d", nCount);

        // Выводим заголовок для обновления cookie

        printf("Content-type: text/html\r\n");

        strcpy(szBuf, "Set-Cookie: AgainCount=");

        strcat(szBuf, szBuf1);

        strcat(szBuf, ";\r\nContent-type: text/html\r\n\r\n");

        printf(szBuf);

        // Выводим приглашение для повторных посещений

        printf("<H2>Welcome to our page AGAIN!</H2>");

       

        // Выводим счетчик посещений

        printf("<P>Access count: %s",szBuf1);

        // Вставляем документ HTML с текстом сценария

        // JavaScript, который тоже работает с cookie

        insertHTML("script.ht", szBuf);

        printf(szBuf);

      }

    }

  }

  // Удаление cookie

  else if(!strcmp(pszQueryString, "clear"))

  {

    // Выводим заголовок для удаления cookie

    printf("Content-type: text/html\r\n");

    printf(szCookieRemoveHeader);

    // Выводим сообщение об успешном удалении cookie

    printf("<HTML><HEAD><TITLE>Cookie demo</TITLE></HEAD><BODY>");



    printf("<P>Cookie Removed");

  }

  printf("</BODY></HTML>");

}

// -----------------------------------------------

// findCookie

// Получение значение параметра cookie по его

// имени

// -----------------------------------------------

char *findCookie(char * szName)

{

  char * pszCookie;

  char * pszBegin;

  char * pszEnd;

  char szBuf[4096];

  // Получаем текстовую строку cookie

  pszCookie = getenv("HTTP_COOKIE");

  if(pszCookie != NULL)

  {

    // Копируем ее в рабочий буфер

    strcpy(szBuf, pszCookie);

    // Ищем в строке имя параметра

    pszBegin = strstr(szBuf, szName);

    if(pszBegin == NULL)

      return NULL;

   

    else

    {

      // Пропускаем символ равенства

      pszBegin += strlen(szName) + 1;

      // Ищем символ ; и заменяем его на

      // двоичный нуль

      pszEnd = strstr(pszBegin, ";");

      if(pszEnd != NULL)

        *pszEnd = 0;

      // Возвращаем значение параметра

      return pszBegin;

    }

  }

}

// -----------------------------------------------

// insertHTML

// Вставка в буфер содержимого текстового файла

// -----------------------------------------------

void insertHTML(char * pszFileName, char * pszBuf)

{

  HFILE hSrcFile;

  DWORD dwFileSize;

  // Открываем файл

  hSrcFile = _lopen(pszFileName, OF_READ);

  // Определяем его длину

  dwFileSize = _llseek(hSrcFile, 0, 2);

 

  // Устанавливаем указатель на начало файла

  _llseek(hSrcFile, 0, 0);

  // Читаем файл в буфер

  _hread(hSrcFile, pszBuf, dwFileSize);

  // Закрываем буфер двоичным нулем

  pszBuf[dwFileSize] = '\0';

  // Закрываем файл

  _lclose(hSrcFile);

}

В переменной szCookieHeader мы подготовили заголовок Set-Cookie, предназначенный для создания параметра cookie с именем AgainCount:

char szCookieHeader[] =

 "Set-Cookie: AgainCount=0;\r\nContent-type: text/html\r\n\r\n";



Начальное значение этого параметра равно нулю.

Заголовок, хранящийся в переменной szCookieRemoveHeader, предназначен для удаления cookie:

char szCookieRemoveHeader[] =

  "Set-Cookie: AgainCount=0;expires=Mon 03-May-1993 12:00:00 GMT;\r\nContent-type: text/html;\r\n\r\n";

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

Сразу после запуска программа CGI получает значение переменных среды QUERY_STRING и HTTP_COOKIE:

pszQueryString = getenv("QUERY_STRING");

pszCookie = getenv("HTTP_COOKIE");

В первой из них хранится параметр запуска программы CGI, а во второй - строка cookie (если она определена).

Далее наша программа анализирует параметр запуска.

Если программа вызвана с параметром go, она проверяет переменную pszCookie. В эту переменную функция getenv записывает строку cookie или значение NULL, если cookie не определено.

При первом посещении cookie еще нет, поэтому наша программа добавляет к заголовку HTTP формируемого документа заголовок Set-Cookie:

printf("Content-type: text/html\r\n");

printf(szCookieHeader);

Затем программа выводит приглашение для первого посещения и завершает свою работу.

В том случае, если в принятом запросе уже имеется информация о cookie, программа CGI извлекает значение параметра cookie с именем AgainCount, вызывая для этого функцию findCookie:

pszMyCookie = findCookie("AgainCount");

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

Полученная строка преобразуется в численное значение при помощи функции atoi, после чего это значение увеличивается на единицу, преобразуется обратно в тестовую строку и записывается в буфер szBuf1:

nCount = atoi(pszMyCookie);

nCount++;

sprintf(szBuf1, "%d", nCount);

На следующем этапе программа формирует заголовок Set-Cookie с новым значением параметра AgainCount:

printf("Content-type: text/html\r\n");

strcpy(szBuf, "Set-Cookie: AgainCount=");



strcat(szBuf, szBuf1);

strcat(szBuf, ";\r\nContent-type: text/html\r\n\r\n");

printf(szBuf);

Этот заголовок вместе с заголовком Content-type записывается в создаваемый документ HTML.

Далее после вывода приглашения для повторного посещения страницы программа CGI записывает в документ новое значение счетчика посещений:

printf("<P>Access count: %s",szBuf1);

И, наконец, перед завершением своей работы программа вставляет в текст документа HTML файл со сценарием JavaScript, вызывая для этого функцию insertHTML:

insertHTML("script.ht", szBuf);

Эта функция определена в нашей программе, как и функция findCookie.

Когда программа CGI вызывается для удаления cookie с параметром clear, она выводит специально предназначенный для этого заголовок с просроченной датой:

printf("Content-type: text/html\r\n");

printf(szCookieRemoveHeader);

Теперь мы кратко расскажем о работе функции findCookie.

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

Далее, вызывая функцию strstr, мы ищем в рабочем буфере имя нужного нам параметра cookie. Если это имя найдено, то мы пропускаем символ равенства, ищем символ разделителя ‘;’ и заменяем его на двоичный нуль. После выполнения всех этих действий наша функция возвращает адрес искомой строки со значением нужного нам параметра cookie.

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

Текст сценария, вставляемого функцией insertHTML в динамически формируемый документ HTML, представлен в листинге 7.9.

Листинг 7.9. Файл chapter7/AgainCGI/script.ht

<HR>

<P>Cookie information from JavaScript:

<FORM NAME="TestForm">

  <P><TEXTAREA NAME="Comment"



    ROWS="3" COLS="25">

  </TEXTAREA>

</FORM>   

<SCRIPT LANGUAGE="JavaScript">

<!--

function findCookie(szName)

{

  var i = 0;

  var nStartPosition = 0;

  var nEndPosition = 0; 

  var szCookieString = document.cookie; 

  var szTemp = "";

  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;

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

      return unescape(szTemp);

      break;   

    }

    i++; 

  }

  return "";

}

var szMyText="";

szMyText = findCookie("AgainCount");

if(szMyText != "")

{

  TestForm.Comment.value =

   "Cookie: " + document.cookie + "\nAccess count: " + szMyText;

}

// -->

</SCRIPT>

С функцией findCookie вы уже знакомы. Она предназначена для получения значения параметра cookie по его имени.

После завершения загрузки документа HTML наш сценарий при помощи этой функции получает текущее значение параметра cookie с именем AgainCount, установленное программой CGI:

var szMyText="";

szMyText = findCookie("AgainCount");

Далее это значение добавляется к полной строке cookie и отображается в многострочном поле редактирования:

TestForm.Comment.value =

 "Cookie: " + document.cookie + "\nAccess count: " + szMyText;

Форма, содержащая поле редактирования, определена в начале вставляемого файла сценария JavaScript.


Семь вариаций на тему “Hello, world!”


Мы продолжим хорошую традицию начинать изучение нового языка программирования с классической программы “Hello, world!”, впервые составленной создателями языка С. В этом разделе вы найдете несколько вариантов такой программы, демонстрирующих различные (но пока не самые впечатляющие) возможности JavaScript.



SetDate


Метод setDate используется для установки календарной даты в объекте класса Date.

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

dtNewDate.setDate(nDateNumber);

Параметр nDateNumber может принимать значения от 1 до 31.



SetHours


Метод setHours используется для установки количества часов, прошедших после полуночи, в объекте класса Date.

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

dtNewDate.setHours(nHours);

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



SetMinutes


Метод setMinutes используется для установки количества минут, прошедших после начала часа, в объекте класса Date.

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

dtNewDate.setMinutes(nMinutes);

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



SetMonth


Метод setMonth используется для установки номера месяца, прошедшего с начала года, в объекте класса Date.

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

dtNewDate.setMonth(nMonth);

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



SetSeconds


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

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

dtNewDate.setSeconds(nSeconds);

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



SetTime


С помощью метода setTime можно установить дату в объекте класса Date, соответствующую заданному количеству миллисекунд, прошедших после 1 января 1970 года.

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

dtNewDate.setTime(nMilliseconds);



SetYear


Метод setYear используется для установки номера года, в объекте класса Date.

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

dtNewDate.setYear(nsetYear);



Шестнадцатеричный калькулятор


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

Рис. 3.19. Калькулятор, выполненный на языке сценариев JavaScript

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

С помощью кнопок 0 - F можно вводить шестнадцатеричные числа, которые будут отображаться в текстовом поле Hex. В поле Dec находится десятичное значение введенного шестнадцатеричного числа или результата вычислений.

Кнопки “+”, “-“, “*” и “/” предназначены, соответственно, для выполнения операции сложения, вычитания, умножения и деления. При помощи кнопки “Enter” можно получить результат вычислений. Кнопка CE позволяет стереть текущее введенное число, а кнопка C - сбросить промежуточный результат вычислений и текущее введенное число.

Исходный текст документа HTML с калькулятором представлен в листинге 3.9.

Листинг 3.9. Файл chapter3/hexcalc/hexcalc.html

<HTML>

<HEAD>

  <TITLE>Hexadecimal calculator</TITLE>

  <SCRIPT>

  <!--

  var total = 0;

  var lastOperation = "+";

  var newnumber = true;

 

  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);

    }

   

    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;

  }

  function putNumber(btn,form)

  {

    var szOld = "";

    var szNew = "";

    if(newnumber)

    {

      form.displayHex.value = "";

      form.displayDec.value = "";

      newnumber = false; 

    }

   

    szOld = form.displayHex.value;

  

    szNew = szOld.concat(btn.name);

    nCurrent = eval("0x" + szNew);

  

    form.displayHex.value = szNew;

    form.displayDec.value = nCurrent;

  }

  function clearNumber(form)

  { 

    form.displayHex.value = "0";

    form.displayDec.value = "0";

    newnumber = true; 

  }

  function clearAll(form)

  {

    total = 0; 

    lastOperation = "+"; 

    clearNumber(form);

  }

  function plusOp(form)

  {

    var result;

    result = total + " " + lastOperation + " " + form.displayDec.value;

    total = eval(result);

    lastOperation = "+"; 

    form.displayHex.value = dec2hex(total); 

    form.displayDec.value = total; 

    newnumber = true;

  }

  function minusOp(form)

  {

    var result;

 

    result = total + " " + lastOperation + " " + form.displayDec.value;

    total = eval(result);

    lastOperation = "-"; 

    form.displayHex.value = dec2hex(total); 

    form.displayDec.value = total; 

    newnumber = true;

  }

  function mulOp(form)

  {

    var result;

 

    result = total + " " + lastOperation + " " + form.displayDec.value;

    total = eval(result);

    lastOperation = "*"; 

    form.displayHex.value = dec2hex(total); 

    form.displayDec.value = total; 

    newnumber = true;

  }

  function divOp(form)

  {

    var result;

 

    result = total + " " + lastOperation + " " + form.displayDec.value;



    total = eval(result);

    lastOperation = "/"; 

    form.displayHex.value = dec2hex(total); 

    form.displayDec.value = total; 

    newnumber = true;

  }

  function getResult(form)

  {

    var result;

    result = total + lastOperation + eval("0x" + form.displayHex.value);

    total = eval(result);

    form.displayHex.value = dec2hex(total); 

    form.displayDec.value = total; 

    newnumber = true;

  }

  // -->

  </SCRIPT>

  </HEAD>

  <BODY>

    <FORM>

      <TABLE BORDER=2 BORDERCOLOR="Black" BGCOLOR="Yellow">

        <TR>

          <TD>Hex:</TD>

          <TD COLSPAN=3><INPUT TYPE=text NAME="displayHex" VALUE="0" onFocus="this.blur();"></TD>

        </TR>

        <TR>

          <TD>Dec:</TD>

          <TD COLSPAN=3><INPUT TYPE=text NAME="displayDec" VALUE="0" onFocus="this.blur();"></TD>

        </TR>

        <TR>

          <TD ALIGN=CENTER><INPUT TYPE="button" NAME="C" VALUE=" C " onClick="putNumber(this,this.form);"></TD>

          <TD ALIGN=CENTER><INPUT TYPE="button" NAME="D" VALUE=" D " onClick="putNumber(this,this.form);"></TD>

          <TD ALIGN=CENTER><INPUT TYPE="button" NAME="E" VALUE=" E " onClick="putNumber(this,this.form);"></TD>

          <TD ALIGN=CENTER><INPUT TYPE="button" NAME="F" VALUE=" F " onClick="putNumber(this,this.form);"></TD>

        </TR>

        <TR>

          <TD ALIGN=CENTER><INPUT TYPE="button" NAME="8" VALUE=" 8 " onClick="putNumber(this,this.form);"></TD>



          <TD ALIGN=CENTER><INPUT TYPE="button" NAME="9" VALUE=" 9 " onClick="putNumber(this,this.form);"></TD>

          <TD ALIGN=CENTER><INPUT TYPE="button" NAME="A" VALUE=" A " onClick="putNumber(this,this.form);"></TD>

          <TD ALIGN=CENTER><INPUT TYPE="button" NAME="B" VALUE=" B " onClick="putNumber(this,this.form);"></TD>

        </TR>

        <TR>

          <TD ALIGN=CENTER><INPUT TYPE="button" NAME="4" VALUE=" 4 " onClick="putNumber(this,this.form);"></TD>

          <TD ALIGN=CENTER><INPUT TYPE="button" NAME="5" VALUE=" 5 " onClick="putNumber(this,this.form);"></TD>

          <TD ALIGN=CENTER><INPUT TYPE="button" NAME="6" VALUE=" 6 " onClick="putNumber(this,this.form);"></TD>

          <TD ALIGN=CENTER><INPUT TYPE="button" NAME="7" VALUE=" 7 " onClick="putNumber(this,this.form);"></TD>

        </TR>

        <TR>

          <TD ALIGN=CENTER><INPUT TYPE="button" NAME="0" VALUE=" 0 " onClick="putNumber(this,this.form);"></TD>

          <TD ALIGN=CENTER><INPUT TYPE="button" NAME="1" VALUE=" 1 " onClick="putNumber(this,this.form);"></TD>

          <TD ALIGN=CENTER><INPUT TYPE="button" NAME="2" VALUE=" 2 " onClick="putNumber(this,this.form);"></TD>

          <TD ALIGN=CENTER><INPUT TYPE="button" NAME="3" VALUE=" 3 " onClick="putNumber(this,this.form);"></TD>

        </TR>

        <TR>



          <TD ALIGN=CENTER><INPUT TYPE="button" NAME="+" VALUE=" + " onClick="plusOp(this.form);"></TD>

          <TD ALIGN=CENTER><INPUT TYPE="button" NAME="-" VALUE="  -  " onClick="minusOp(this.form);"></TD>

          <TD ALIGN=CENTER><INPUT TYPE="button" NAME="*" VALUE=" * " onClick="mulOp(this.form);"></TD>

          <TD ALIGN=CENTER><INPUT TYPE="button" NAME="/" VALUE="  /  " onClick="divOp(this.form);"></TD>

        </TR>

        <TR>

          <TD ALIGN=CENTER><INPUT TYPE="button" NAME="C" VALUE=" C " onClick="clearAll(this.form);"></TD>

          <TD ALIGN=CENTER><INPUT TYPE="button" NAME="CE" VALUE="CE" onClick="clearNumber(this.form);"></TD>

          <TD COLSPAN=2 ALIGN=CENTER><INPUT TYPE="button" NAME="Enter" VALUE="Enter" onClick="getResult(this.form);"></TD>

        </TR>

      </TABLE>

    </FORM>

  </BODY>

</HTML>

Рассмотрим наиболее интересные моменты.

Когда калькулятор отображается в первый раз, в текстовых полях displayHex и displayDec, предназначенных, соответственно, для отображения чисел в шестнадцатеричном и десятичном виде, находятся нулевые значения:

  . . .

<INPUT TYPE=text NAME="displayHex" VALUE="0" onFocus="this.blur();">

  . . .

<INPUT TYPE=text NAME="displayDec" VALUE="0" onFocus="this.blur();">

  . . .

Это значение устанавливается параметром VALUE.

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



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

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

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

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

function putNumber(btn,form)

{

  var szOld = "";

  var szNew = "";

  if(newnumber)

  {

    form.displayHex.value = "";

    form.displayDec.value = "";

    newnumber = false; 

  }

   

  szOld = form.displayHex.value;

  

  szNew = szOld.concat(btn.name);

  nCurrent = eval("0x" + szNew);

  

  form.displayHex.value = szNew;

  form.displayDec.value = nCurrent;

}

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

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

На следующем этапе к введенному шестнадцатеричному числу добавляется префикс “0x”, после чего происходит вычисление текущего значения функцией eval. Эта функция пытается интерпретировать текстовую строку, переданную ей в качестве параметра, как арифметическое выражение, возвращая результат интерпретации в виде численного значения. Этот результат сохраняется в переменной nCurrent и отображается в текстовом поле displayDec (исходное шестнадцатеричное число отображается в поле displayHex).

Если после ввода числа пользователь нажимает одну из четырех кнопок, предназначенных для выполнения операций сложения, вычитания, умножения и деления, вызываются функции, назначенные для этих кнопок в обработчике события onClick. Это функции plusOp (сложение), minusOp (вычитание), mulOp (умножение) и divOp (деление).



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

function plusOp(form)

{

  var result;

  result = total + " " + lastOperation + " " +

    form.displayDec.value;

  total = eval(result);

  lastOperation = "+"; 

  form.displayHex.value = dec2hex(total); 

  form.displayDec.value = total; 

  newnumber = true;

}

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

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

С помощью функции eval функция plusOp вычисляет результат операции и записывает его в переменную total. Затем в переменную lastOperation записывается код операции сложения - строка “+”.

На следующем этапе функция plusOp преобразует значение total с помощью функции dec2hex и отображает результат в шестнадцатеричном виде в поле displayHex, а также в двоичном - в поле displayDec.

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

Функция getResult вызывается, когда пользователь нажимает на клавишу нашего калькулятора с надписью “Enter”:

function getResult(form)

{

  var result;

  result = total + lastOperation + eval("0x" +

    form.displayHex.value);

  total = eval(result);

  form.displayHex.value = dec2hex(total); 

  form.displayDec.value = total; 

  newnumber = true;

}

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



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

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

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

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

szBuf=szHexTable.charAt(nRem);

szResult = szBuf.concat(szResult);

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


Sin


Вычисление синуса.

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

var nValue;

nValue = Math.sin(nAngle);



События для объекта window


С объектом класса window связаны два события - onLoad и onUnload. Первое из них возникает, когда браузер заканчивает загрузку окна или всех окон фреймов, определенных оператором <FRAMESET>, а второе - когда пользователь завершает работу с документом HTML.

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

В качестве примера рассмотрим следующий фрагмент документа HTML, содержащий сценарий:

. . .

function Hello()

{

  window.alert("Welcome to my home page!")

}

function Bye()

{

  window.alert("Bye! Come back again!")

}

  . . .

<BODY BGCOLOR=white onLoad="Hello()" onUnload="Bye()">

  . . .

Здесь в операторе <BODY> мы определили обработчики событий onLoad и onUnload. При возникновении первого события будет вызываться функция Hello, а при возникновении второго события - функция Bye. Заметим, что так как документ HTML интерпретируется в направлении сверху вниз, функции Hello и Bye необходимо определить до появления оператора <BODY>. Лучшее место для определения этих функций - заголовок документа HTML.

Если вам нужно проследить загрузку всех фреймов, вы можете указать обработчик события onLoad в операторе <FRAMESET>.