Как создать сайт с нуля.

К учебнику по Dinamic HTML

"Все Технические Моменты Сайтостроения в Видеоформате". Коллекция видеокурсов, которая за 36 часов и 45 минут сделает из Вас профессионала во всех технических моментах создания сайта.



Реклама:


Глава 9. Программирование индивидуальных элементов



В главе 8 были введены элементы сценариев в динамическом HTML. В этой главе рассматриваются методы программирования некоторых наиболее часто встречающихся элементов сценариев. Глава 10 описывает методы программирования элементов в формах.

В данной главе рассмотрены следующие темы:



Программирование элементов Body и Frameset

Содержание HTML-документа может быть двух типов: содержание тела (body) или определение набора фреймов (frameset). Первый элемент Body или Frameset, который появляется в документе, определяет его тип. В обоих случаях используется сходная объектная модель документа.



Свойство body

Объект document содержит свойство body, которое представляет основу содержания документа. Имя данного свойства неопределенно, поскольку свойство body может представлять элемент Frameset или Body в зависимости от типа документа.

Как объясняется в главе 7, каждый документ имеет элемент Body или Frameset, независимо от того, описан данный элемент явно или нет.

Если набор фреймов в документе вложен в другие элементы Frameset, то свойство body представляет самый крайний элемент Frameset в документе.

Элемент Body или Frameset также находится внутри семейства all документа. Таким образом, к свойству body доступ может быть осуществлен прямо из документа:


// Возвращает свойство BODY или FRAMESET в зависимости от типа документа.
document.body.tagName;

Или доступ может быть осуществлен посредством семейства all:


// Для документов, содержащих элемент Body
document.all.tags("Body").item(0).tagName;       // Возвращает "BODY"
/* отображает "true"; демонстрирует, что данные два элемента совпадают */
alert(document.all.tags("Body").item(0) == document.body);

// Для документов, содержащих элемент Frameset
document.all.tags("Frameset").item(0).tagName;   // Возвращает "FRAMESET"
/* Отображает "true"; демонстрирует, что данные два элемента совпадают  */
alert(document.all.tags("Frameset").item(0) == document.body);

В приведенном выше коде метод tags возвращает семейство, состоящее из элементов Body или Frameset. Если документ имеет элемент Body, то определение типа документа (DTD) HTML ограничивает его одним элементом Body, и анализатор игнорирует любые дополнительные элементы. Если документ имеет элемент Frameset, то в документе может находиться множество элементов Frameset. Метод tags возвращает все элементы, начиная с самого крайнего. В любом случае первый элемент в семействе, возвращаемый методом tags, является элементом, который содержится в свойстве body. Код использует элемент item для доступа к данному элементу.



Доступ к свойству body

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

<HTML>
   <SCRIPT LANGUAGE="JavaScript">
      alert(document.body == null);    // true - предшествует тегу <BODY>
   </SCRIPT>
   <BODY>
      <SCRIPT LANGUAGE="JavaScript">
         alert(document.body == null); // false - следует после тега <BODY>
      </SCRIPT>
   </BODY>
</HTML>

Для документов с содержанием body тег не обязательно явно указывать в документе. Элемент Body создается по умолчанию, если документ содержит хотя бы один элемент - или просто текст - который должен быть частью тела. Элементы, которые составляют содержание тела, определены в DTD документа HTML.

В главе 1 объясняется как читать DTD, а дополнительная информация о процедуре анализа документа приведена в главе 7.



Различие между содержанием body и frameset

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

<HTML>
   <HEAD>
      <TITLE> Набор фреймов представлен как тело документа </TITLE>
   </HEAD>
   <FRAMESET ROWS="100%" ONLOAD="alert(document.body.tagName);">
      <FRAME SRC="foo.htm">
   </FRAMESET>
</HTML>

Проверка длины семейства frames в окне не является точным способом определения, является ли документ набором фреймов. Документ с элементом Body может содержать элементы IFrame, которые должны быть включены в семейство frames.



Окно клиента и размер документа

Ширина и высота окна на строке клиента представлены как свойства элементов Body и Frameset. Физический размер (physical size) документа является размером клиентской области - то есть, области экрана, которую занимает документ. Логический размер (logical size) документа определяется размером содержания. Документы, содержание которых не помещается в окне, содержат полосы прокрутки. На рис. 9.1 показаны свойства, представляющие физический и логический размеры документа. Данные свойства будут описаны в последующих разделах. Остальные элементы в документе могут представлять данные свойства для определения размера элементов.

Особые отношения данных свойств с другими элементами в документе обсуждаются в главе 12.


Физический размер

Физическая ширина и высота документа (типа frameset или body) представлены свойствами offsetWidth И offsetHeight элемента Frameset или Body. Физическая ширина и высота измеряют область текущего видимого окна, включая полосы прокрутки. Свойства clientWidth и clientHeight представлены для определения размера клиентской области - физического размера, определяемого свойствами offsetWidth и offsetHeight, который меньше на область, занимаемую полосами прокрутки и границами окна. Данные свойства доступны только для чтения и их нельзя использовать для изменения размера окна.

На рис. 9.1 горизонтальная полоса прокрутки не отображается, так что значения свойств offsetHeight и clientHeight будут одинаковы, если значение границы (border) установлено равным 0. Однако на экране отображается вертикальная полоса прокрутки, так что значения свойств offsetWidth и offsetHeight различны.

Рис. 9.1. Свойства для определения размера окна и документа


Логический размер

Четыре свойства элемента Body определяют логический размер документа и положения документа в окне просмотра: scrollWidth, scrollHeight, scrollTop и scrollLeft. Логический размер документа представляет общую высоту и ширину документа, а не размер окна браузера, в котором просматривается документ. Данные свойства недоступны или необязательны для документов с набором фреймов, поскольку логический размер набора фреймов эквивалентен его физическому размеру.

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

Свойства scrollTop и scrollLeft представляют значения смещения при прокручивании логического документа. Они представляют точку в документе, которая отображается в верхнем левом углу окна. Когда горизонтальные и вертикальные полосы прокрутки прокручиваются к левой и верхней границам документа, значения свойств scrollLeft и scrollTop равны 0. Эти свойства допускают чтение/запись и могут быть изменены для прямого прокручивания документа до определенного положения (определяемого в пикселах).

Если требуется одновременно установить значения свойств scrollLeft и scrollTop, то метод scroll окна является наиболее подходящим механизмом, поскольку в качестве аргументов он использует обе координаты - и по горизонтали и по вертикали.

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


upperLeftX = document.body.scrollLeft;
upperLeftY = document.body.scrollTop;
lowerRightX = upperLeftX + document.body.clientWidth;
lowerRightY = upperLeftY + document.body.clientHeight;

Свойства, связанные с прокручиванием, также представлены в любом элементе с возможностью прокручивания. Например, вы можете установить полосы прокрутки в элементе Div, используя свойство каскадных таблиц стилей (Cascading Style Sheets, CSS) overflow 3, а элемент TextArea отображает полосы прокрутки по умолчанию. Если в элементах имеются полосы прокрутки, то они представляют свойства, связанные с прокручиванием, для определения областей прокручивания содержания элементов.

Элемент TextArea подробно обсуждается в главе 10, а свойство overflow CSS обсуждается в главе 12.



События окна

Атрибуты элементов Body и Frameset соответствуют всем событиям уровня окна. Например, приведенный ниже код в документе с элементом Body определяет обработчик событий ONLOAD для окна:

<BODY ONLOAD="doThis();">

Код для документа типа frameset аналогичен:

<FRAMESET ONLOAD="doThis();" ROWS="*">

Если теги <BODY> или <FRAMESET> используются для определения обработчика событий окна, событие ограничено объектом window, а не объектом body. Данное различие важно, если указатель this используется в обработчике событий. В обработчике событий уровня тела документа указатель this указывает на объект body. В обработчике событий окна this указывает на объект window, даже если обработчик определен в теге <BODY>. Приведенный ниже код иллюстрирует работу указателя this для события окна (onload) и события тела документа (onclick):

<BODY ONLOAD="alert(this == document.body);  // false"
   ONCLICK="alert(this == document.body);    // true">
</BODY>

Более того, для событий окна свойство srcElement объекта event содержит значение null.

Документ может содержать несколько фреймов, но в документе может быть только один обработчик для каждого события окна. Если несколько элементов Frameset в документе определяют обработчики для события, то выполняется только код последнего обработчика. В приведенном ниже примере выполняется только второй обработчик события onload, отображая предупреждение b. Событие не генерируется, пока не загружен весь документ.

<HTML>
   <HEAD>
      <TITLE> Событие onload набора фреймов </TITLE>
   </HEAD>
   <FRAMESET ONLOAD="alert(`a');" ROWS="100, *">
      <FRAMESET ONLOAD="alert(`b');" COLS="*.*">
         <FRAME SRC="a.htm">
         <FRAME SRC="b.htm">
      </FRAMESET>
      <FRAME SRC="c.htm">
   </FRAMESET>
</HTML>

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


Событие onresize

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

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



Программирование содержания тела документа

Документы, которые содержат элемент Body, могут иметь дополнительные элементы, которые доступны для документов frameset, включая доступ к HTML и текстовому содержанию, которое находится внутри тела документа, и событию onscroll, которое возникает при прокручивании окна.

Вы можете написать сценарии для манипулирования текстом в элементе Body или любом другом элементе в теле документа. Подробнее это обсуждается в главе 13.


Событие onscroll

Событие onscroll объекта window возникает при прокручивании окна пользователем или программой только в документах с элементами Body и не генерируется в документах frameset, поскольку они не отображают полос прокрутки.



Программирование содержания набора фреймов

Документ frameset является типом HTML-документа и поддерживается объектной моделью документа. Семейство all документа frameset обеспечивает прямой доступ ко всем его элементам. С помощью семейства all можно получить доступ к отдельным атрибутам элементов Frame и Frameset. Во многих случаях данные атрибуты можно изменять динамически.

Число фреймов в наборе постоянно и не может быть изменено без создания нового документа, но ряд атрибутов элемента Frameset можно изменить. Например, атрибуты ROWS и COLS представляют собой атрибуты, доступные для чтения/записи, что позволяет динамически изменять расположение набора фреймов. Эта возможность может быть использована для добавления элементов индивидуального поведения в традиционный набор фреймов.

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

<HTML>
   <HEAD>
      <TITLE> Перемещающиеся фреймы </TITLE>
      <SCRIPT LANGUAGE="JavaScript">
         var defSize = 25;

         function display(f) {
            var newRows = "";
            // Проверка состояния.
            var elFrame = document.all.tags("FRAME");
            for (var intFrames = 0; intFrames < frames.length;
                  intFrames++) {
               var curF = frames[intFrames].document;
               if (curF.body == f.document.body) {
                  // Give selected frame all the space.
                  newRows += "*, ";
                  /* Make the header much bigger. */
                  curF.all.header.style.fontSize = "200%";
                  /* Turn on scrollbars for the active frame
                     by accessing the Frame element
                     in the frameset document. */
                  elFrame[intFrames].scrolling = "yes";
               }
               else {
                  // Set to default size.
                  newRows += defSize.toString() + ", ";
                  // Reset header font size.
                  curF.all.header.style.fontSize = "";
                  // Turn off scrolling.
                  elFrame[intFrames].scrolling = "no";
               }
            }
            document.body.rows = newRows;
         }
      </SCRIPT>
   </HEAD>
   <FRAMESET ROWS="*, 25, 25">
      <FRAME SRC="home.htm" NORESIZE>
      <FRAME SRC="news.htm" NORESIZE SCROLLING="No">
      <FRAME SRC="info.htm" NORESIZE SCROLLING="No">
   </FRAMESET>
</HTML>

На рис. 9.2 продемонстрирована работа данного кода. Когда пользователь щелкает по заголовку News или Information, то другие фреймы автоматически сворачиваются и на экране разворачивается выбранный фрейм.

Рис. 9.2. Пример автоматически всплывающих фреймов

В каждом документе в наборе фреймов обработчик событий onfocus должен вызывать процедуру display. Для вызова функции следует сослаться на свойство parent документа:

<!-- Для каждого документа в наборе фреймов должно быть определено 
     событие onfocus. -->
<BODY ONFOCUS="parent.display(this);">

Кроме того, в каждом документе в наборе фреймов идентификатор ID первого параграфа должен иметь значение header. Текст в этом параграфе будет увеличен при получении документом фокуса.

Данный пример демонстрирует модификацию индивидуальных фреймов. Элемент Frame в семействе all документа отличается от содержания семейства окна frames. Семейство frames окна возвращает экземпляр окна, созданный на основе источника документа. Элемент Frame в семействе all представляет фрейм как определенный источником HTML и используемый для создания окна. Изменение элемента Frame может привести к изменению окна и его содержания. Например, можно вручную активизировать или отключить полосы прокрутки. Полосы прокрутки были отключены в данном примере, так что они не мешают сжатому просмотру заголовка документа.



Программирование элемента Anchor

Элемент Anchor в HTML служит двум целям: для определения ссылок перехода к адресам URL и для установки закладок внутри документа. Элемент Anchor ведет себя как ссылка, если определен его атрибут HREF, или как закладка, если определено значение атрибута NAME:

<A HREF="http://www.insideDHTML.com#Chapter2"><!-- Link --></A>
<A NAME="Chapter2"><!-- Bookmark --></A>

Семейство all документа содержит все элементы Anchor. Документ имеет два дополнительных семейства, которые по отдельности содержат ссылки и закладки. Ссылки представлены семейством links, а закладки - семейством anchors. Простой элемент Anchor может находиться в обоих семействах, если определены атрибуты NAME и HREF.

Свойства href и name могут быть изменены в коде, так что объект якоря может динамически переключать семейства. Например, если якорю с пустым свойством href назначается строка, то он автоматически добавляется в семейство links и автоматически воспроизводится на экране как ссылка. Независимо от типа якоря и семейства, в котором он находится, объект якоря представляет тот же набор свойств, методов и событий.

Примечание: Начиная с этого места, якоря, определенные как <А NAME=>, называются закладками, а якоря, определенные как <А HREF=>, называются ссылками для различия между двумя типами якорей. Данные ссылки отличаются от элемента Link, который обсуждается ниже в разделе данной главы "Программирование элемента Link". Ter <LINK> определяет элемент Link.



Свойство href

Объект якоря имеет ряд свойств, которые содержат части URL, представленные свойством href. Свойства protocol, hostname, pathname, search и hash ссылаются на индивидуальные части URL, а свойство host содержит имя хоста и номер порта.

Данные свойства, которые также принадлежат к объекту location, описаны в главе 4.


Якоря и базовый HREF

Между значениями HREF, определенными относительно, и объектной моделью существуют интересные отношения. Относительный HREF является адресом URL, который не начинается символами // (например, href= "goHere.htm") Всем относительным HREF предшествует местоположение по умолчанию. Если не определено обратное, то местоположение по умолчанию является местоположением текущего документа. Вы можете использовать элемент Base для изменения местоположения по умолчанию. Для относительных URL, назначенных атрибутам, местоположение по умолчанию добавляется при анализе документа. Местоположение по умолчанию не добавляется в относительные URL, назначенные свойствам сценариями, пока не будет сделана ссылка на URL. Приведенный ниже код иллюстрирует иные положения:

<HTML>
   <HEAD>
      <TITLE> Демонстрация базового HREF </TITLE>
      <BASE HREF="http://scotti/">
   </HEAD>
   <BODY>
      <A HREF="page1.htm">page 1</A>
      <A HREF="http://ji/page2.htm">page 2</A>
      <SCRIPT LANGUAGE="JavaScript">
         alert(document.links[0].href); // http://scotti/page1.htm
         alert(document.links[1].href); // http://ji/page2.htm
         document.links[0].href = "newpage.htm";
         alert(document.links[0].href); // newpage.htm
      </SCRIPT>
   </BODY>
</HTML>


Атрибут HREF, определяемый сценарием

Атрибут HREF элемента Anchor иначе может быть определен как строка кода, которая должна быть выполнена. Данный метод полезен, когда фрейм содержит короткую строку, поскольку уменьшается число циклов обмена информацией между сервером и клиентом. Например, когда пользователь нажимает следующий якорь, запускается простой документ, отображающий строку "Hello, world!":

<A HREF="JavaScript:'Hello, world!'">

Свойство protocol представляет собой имя языка, после которого указаны точка с запятой и pathname является остальной частью строки. Свойство href содержит всю строку с соответствующими escape-последовательностями (такими как % 20 для каждого пробела).

Определяемые сценарием атрибуты HREF выполняются после окончания генерации событий onclick. Кроме того, поскольку атрибут HREF не является событием, то объект event недоступен в момент выполнения определяемого сценарием атрибута HREF.

Примечание: При использовании VBScript для определяемых сценарием атрибутов HREF следует быть осторожным. Netscape Navigator распознает только язык JavaScript и будет отображать ошибку перехода, если определен VBScript.



События элемента Anchor

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

Таблица 9.1. События элемента Anchor


Событие Источник

onblur Якоря ссылок
onclick Все якоря
ondblclick Все якоря
onfocus Якоря ссылок
onkeydown Якоря ссылок
onkeypress Якоря ссылок
onkeyup Якоря ссылок
onmousedown Все якоря
onmousemove Все якоря
onmouseout Все якоря
onmouseover Все якоря
onmouseup Все якоря

С помощью всплывания событий элемент Anchor может получить событие от дочернего события (такого как изображение в якоре), даже если он явно не поддерживает его. В приведенной выше таблице перечислены события, для которых все типы якорей могут являться источником. Все события могут быть определены как атрибуты элемента, посредством синтаксиса <SCRIPT FOR=EVENT=> или с помощью свойств элемента Anchor. Чтобы служить источником для событий фокуса и клавиатуры, элемент должен иметь возможность получать фокус. Якоря, которые являются ссылками, могут получать фокус. Закладки не могут получать фокус.

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

<A HREF="foo.htm#100" ONCLICK="event.returnValue = false;">

Чтобы обеспечить совместимость с другими браузерами, следует вернуть эначение прямо:

<A HREF="foo.htm#100" ONCLICK="return false;">

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

<SCRIPT FOR="document" EVENT="onclick()" LANGUAGE="JavaScript">
   // Объект события содержит глобальную информацию для обработчика событий.
   if ("A" == event.srcElement.tagName) {
      event.returnValue = false;
      // Запись индивидуального обработчика кода для якоря.
   }
</SCRIPT>

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



Настройка ссылок на многочисленные фреймы

Одним из методов добавления элементов индивидуального поведения в модель якоря является определение нескольких новых атрибутов для элемента Anchor.

Этот метод моделирования выделения подкласса был введен в главе 8. В данном разделе продемонстрировано расширение традиционного поведения якорей.

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

Приведенный ниже код добавляет два определяемых пользователем атрибута в элемент Anchor: mhref и mtarget. Оба атрибута используют список значений, разделенных точкой с запятыми - для mhref это список URL, а для mtarget - список местоположений для данных URL. Когда пользователь выполняет щелчок по якорю, код сначала проверяет, имеет ли якорь эти специальные атрибуты, и при их наличии код заменяет поведение по умолчанию одиночной ссылки на индивидуальный код ссылки.

<HTML>
   <HEAD>
      <TITLE> Указание в качестве цели многочисленных фреймов </TITLE>
      <SCRIPT LANGUAGE="JavaScript">
         function checkElementTree(el, strTag) {
            /* Данная простая функция просматривает дерево от элемента 
               е1 ищет элемент с тегом strTag. Возвращается первый 
               найденный элемент. */
            while ("HTML" != el.tagName) {
               if (strTag == el.tagName)
                  return el;
               el = el.parentElement;
            }
            return null;
         }

         function multiJump() {
            // Поиск якоря.
            var el = checkElementTree(event.srcElement, "A");
            if (null != el) { // Found an anchor.
               // Проверяет, имеет ли якорь множество целей.
               if ((null != el.getAttribute("mhref")) &&
                     (null != el.getAttribute("mtarget"))) {
                  event.returnValue = false;
                  var mhref = new Array();
                  var mtarget = new Array();
                  // Разлагает атрибуты на массивы.
                  mhref = el.getAttribute("mhref").split("; ");
                  mtarget =
                     el.getAttribute("mtarget").split("; ");
                  /* Убедитесь в совпадении числа целей и адресов URL. */
                  if (mtarget.length == mhref.length)
                     for (var intLoop = 0; intLoop < mtarget.length;
                           intLoop++)
                        if (null != parent[mtarget[intLoop]])
                           parent[mtarget[intLoop]].location.href =
                              mhref[intLoop];
               }
            }
         }
      </SCRIPT>
   </HEAD>
   <BODY ONCLICK="multiJump();">
      <A HREF="#"
            mhref="http://www.microsoft.com; http://www.netscape.com"
            mtarget="left; right">
         Browser Web sites
      </A>
   </BODY>
</HTML>

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

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



Псевдоклассы для якорей

Таблицы стилей обеспечивают метод определения стилей для трех состояний ссылки: просмотренная (visited), не просмотренная (not visited) и активная (active). Данные состояния могут иметь различные стили, которые можно установить, используя псевдоклассы (pseudoclass) в CSS. Псевдоклассы обеспечивают метод повышения уровня взаимодействия с пользователем без добавления кода.

Более подробную информацию о псевдоклассах и языке CSS вы можете найти в главе 1 или в спецификации CSS на Web-узле консорциума W3C.

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



Удаление якорей

Простое назначение пустой строки свойству href или name не приводит к удалению элемента Anchor из документа. Однако данный метод позволяет удалить элемент из семейства links или anchors. (Удаляемый элемент всегда остается в семействе all).

Элемент Anchor и его содержание могут быть полностью удалены из документа путем использования свойств outerHTML или outerText. Для удаления влияния якоря с сохранением его содержания может быть использован объект TextRange. Приведенный ниже код демонстрирует манипулирование объектом TextRange.

Объект TextRange и его методы подробно обсуждаются в главе 14.

<SCRIPT LANGUAGE="JavaScript">
   function removeAnchor(aElement) {
      // Удаляемый якорь передается как аргумент.
      // Создание объекта TextRange.
      var tr = aElement.parentTextEdit.createTextRange();
      // Размещение элемента Anchor в объекте.
      tr.moveToElementText(aElement);
      // Выполнение команды для удаления элемента Anchor.
      tr.execCommand("Unlink", false);
   }
</SCRIPT>



Программирование элемента Link

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

На момент написания книги браузер Internet Explorer использовал отношения ссылок для таблиц стилей. Однако написав несколько сценариев, вы можете использовать атрибут REL для определения других отношений. Определение отношений не только делает Web-узел более управляемым, но также может обеспечить доступ к Web-узлу инструментов анализа Web-узлов.

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

На рис. 9.3 показана работа панели перехода. Доступность кнопок в верхней панели и место назначения, на которое они указывают, определяется отношениями Link.

Рис. 9.3. Панель перехода на основе элементов Link



Документ links.htm

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

<HTML>
   <HEAD>
      <TITLE> Отношения ссылок </TITLE>
      <SCRIPT LANGUAGE="JavaScript">
         function setButton(b, dis, title, href) {
            b.disabled = dis;
            b.title = title;
            b.href = href;
         }

         function clearLinks() {
            var navDoc = window.navigation.document.all;
            // Инициализация кнопок путем их отключения и удаления их 
            // надписей. 
            with (navDoc) {
               setButton(previous, true, "", "");
               setButton(next, true, "", "");
            }
         }

         function setupLinks(doc) {
            // Вызывающий документ должен быть передан функции. 
            // Получение всех элементов Link.
            var links = doc.all.tags("LINK");
            var navDoc = navigation.document.all;
            clearLinks();
            for (var intLink = 0; intLink < links.length; intLink++) {
               var el = links[intLink];
               if ("previous" == el.rel) {
                  /* Если предыдущие отношения были определены, то 
                     обновите кнопки.  */
                  setButton(navDoc.previous, false, el.title,
                     el.href);
               }
               if ("next" == el.rel) {
                  /* Если определено следующее отношение, то обновите
                     кнопки */
                  setButton(navDoc.next, false, el.title, el.href);
               }
            }
         }
      </SCRIPT>
   </HEAD>
   <FRAMESET ROWS="28, *" BORDER=0>
      <FRAME SRC="navigate.htm" NAME="navigation" SCROLLING=NO>
      <FRAME SRC="contents.htm" NAME="contents">
   </FRAMESET>
</HTML>



Документ navigate.htm

Приведенный ниже код создает панель перехода:

<HTML>
   <HEAD>
      <TITLE> Панель перехода </TITLE>
      <STYLE TYPE="text/css">
         body {margin-top:2pt; margin-left:2pt; background:gray}
         input {font-weight:bold}
      </STYLE>
   </HEAD>
   <BODY>
      <INPUT TYPE=BUTTON VALUE="TOC" TITLE="Table of Contents"
         ONCLICK="top.contents.location = `contents.htm';">
      <INPUT TYPE=BUTTON ID="previous" VALUE=" < "
         ONCLICK="parent.contents.location = this.href;">
      <INPUT TYPE=BUTTON ID="next" VALUE=" > "
         ONCLICK="parent.contents.location = this.href;">
   </BODY>
</HTML>

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



Документ contents.htm

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

<HTML>
   <HEAD>
      <TITLE> Содержание </TITLE>
      <!-- Определен только переход вперед. Кнопка Previous будет
              отключена для данного документа. -->
      <LINK REL="next" HREF="chapter1.htm" TITLE="Chapter 1">
   </HEAD>
   <BODY ONLOAD="parent.setupLinks(window.document);"
         ONUNLOAD="parent.clearLinks();">
      <H1>Table of Contents</H1>
   </BODY>
</HTML>

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



Программирование элементов IMG и Map

Изображения и карты изображений (image maps) полностью программируются в Internet Explorer 4.0. Вы можете изменить атрибут SRC и размер изображения, а также изменять, добавлять и удалять элементы Area из карты изображений. Объектная модель также позволяет асинхронно загружать новые изображения в фоновом режиме во время работы пользователя со страницей. В данном разделе представлены методы загрузки изображений и манипулирования элементом IMG и связанными с ними картами изображений.



Анимация изображений

Одним из распространенных методов анимирования изображений является изменение изображения при подведении и отведении указателя мыши к элементу. В Internet Explorer 4.0 данная задача выполняется тривиально - используются события onmouseover и onmouseout на самом элементе IMG:

<IMG SRC="start.gif"
   ONMOUSEOVER="this.src = `over.gif';"
   ONMOUSEOUT="this.src = `start.gif';">

Netscape Navigator проигнорирует данный код, поскольку он на данный момент не поддерживает события onmouseover и onmouseout для элемента IMG. Однако Netscape Navigator поддерживает данные события для элемента Anchor. Поэтому после некоторого размышления можно изменить приведенный выше сценарий для работы в других браузерах. Помещая элемент MG в элемент Anchor, браузеры Netscape Navigator версий 3.0 и более поздней и Internet Explorer 4.0 будут правильно изменять изображение:

<A HREF=""
      ONMOUSEOVER="document.myImage.src = `over.gif';"
      ONMOUSEOUT="document.myImage.src = `start.gif';">
   <IMG BORDER=0 NAME="myImage" SRC="start.gif">
</A>

Атрибут BORDER=0 необходимо добавить, так как иначе по умолчанию вокруг изображения будет нарисована рамка. И хотя данный метод поддерживается и в Netscape Navigator и в Internet Explorer, имеется одно ключевое отличие. Поскольку не указан размер изображения, то в Internet Explorer размер контейнера изображения автоматически изменяется в соответствии с размером изображения с одновременным изменением окружающего содержания. В Netscape Navigator размер изображения фиксирован, когда загружается первое изображение, так что следующее изображение будет масштабироваться для соответствия указанному размеру. Для преодоления данного расхождения убедитесь, что изображения имеют одинаковый размер или укажите значения атрибутов width и height в элементе IMG.

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


Последовательность изображений

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

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

<HTML>
   <HEAD>
      <TITLE> Последовательное отображение рекламных объявлений </TITLE>
      <!-- Дополнительные объявления могут быть добавлены без расширения
              данного списка. -->
      <ADLIST src="ad1.gif" duration=3000>
      <ADLIST src="ad2.gif" duration=5000>
      <ADLIST src="ad3.gif">
      <ADLIST src="ad4.gif" duration=1000>
      <SCRIPT LANGUAGE="JavaScript">
         var adSet = document.all.tags("ADLIST");
         adSet.current = 0;
         var nextImage = document.createElement("IMG");

         function preLoad() {
            // Получение следующего изображения. 
            // Если возникает ошибка, то следующее изображение 
            //  пропускается.
            /* Всегда устанавливать обработчики событии изображений перед 
               назначением атрибута SRC для гарантии отсутствия пропусков 
               событий. */
            nextImage.onerror = preLoad;
            nextImage.src =
               adSet[adSet.current].getAttribute("src");
            // Атрибут duration определяет длительность отображения 
            // изображения. 
            nextImage.duration =
               adSet[adSet.current].getAttribute("duration");
            if (null == nextImage.duration)  // If not specified, use
               nextImage.duration = 2000;    // default 2 seconds.
            if (++adSet.current == adSet.length)
               adSet.current = 0;            // Start over.
         }

         function skipImage() {
            // Загружено ли следующее изображение?
            if (nextImage.complete) {
               document.all.ad.src = nextImage.src;
               var duration = nextImage.duration;
               preLoad();
               window.tm = setTimeout(`skipImage()', duration);
            }
            else  // Быстрый повтор до тех пор, пока изображение доступно.
               window.tm = setTimeout(`skipImage()', 10);
         }
         preLoad();
      </SCRIPT>
   </HEAD>
   <BODY ONLOAD="window.tm = setTimeout(`skipImage()', 1);"
         ONUNLOAD="clearTimeout(window.tm);">
      <IMG ID="ad" SRC="ad4.gif" STYLE="border:2px solid navy">
   </BODY>
</HTML>

Internet Explorer 4.0 также поддерживает создание новых изображений для фоновой загрузки с помощью оператора new помимо метода createElement. Данный оператор поддерживается для совместимости с реализацией JavaScript в Netscape Navigator. Оператор new является независимым от языка методом создания новых элементов. Например, в приведенном выше коде строка


nextImage = document.createElement("IMG");

может быть записана следующим образом:


nextImage = new Image();

Однако поскольку Netscape Navigator не использует индивидуальные элементы в сценариях, то данный код чередования рекламных объявлений требует дальнейшей модификации для запуска в Netscape Navigator: информация о графических изображениях в рекламных объявлениях должна храниться в сценарии, скорее всего в массиве, а не в индивидуальных элементах AdList.



Карты изображений

Карты изображений (image maps) позволяют разделить изображение на области, содержащие ссылки на различные документы. Чаще всего карты изображений используются для создания видимых карт перехода. Когда пользователь выполняет щелчок по определенной области изображения, действие по умолчанию осуществляет переход на указанную страницу. Используя модель событий, вы можете заменить действие по умолчанию на индивидуальные действия.


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

HTML предоставляет два типа карт изображений: серверные и клиентские. Серверная карта изображения определяется путем добавления атрибута ISMAP в изображение и создания файла карты изображения на сервере. Когда пользователь щелкает по изображению, то значения координат ху отправляется на сервер. Серверная карта изображения имеет два внутренних недостатка: как правило, требуется передача информации на сервер и не обеспечивается простой доступ, поскольку области нажатия (click regions) неизвестны браузеру или сценариям.

Клиентские карты изображений используют элемент Map и не требуют обмена информацией с сервером. Они позволяют браузерам выделять области нажатия изображения. Элемент Map содержит набор элементов Area, которые определяют координаты для каждой области нажатия.

Элементы Map должны быть названы, чтобы их можно было связать с изображением. Если указано имя элемента Map, то любое количество изображений может быть связано с ним посредством атрибута USEMAP изображений. Значение атрибута USEMAP должно быть определено как ссылка на адрес. Например, приведенный ниже код связывает изображение с картой изображения, названной diagram:

Клиентские карты изображений и их синтаксис продемонстрированы в приведенных ниже примерах. Однако полный синтаксис для определения серверной или клиентской карты изображения выходит за рамки данной книги. Более подробное описание синтаксиса карт изображений можно найти в справочнике по HTML или на Web-узле компании Microsoft (www.microsoft.com).


Карты изображений и события

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

При возникновении события в карте изображения элемент Area получает событие, затем событие получает элемент Map и затем - элемент IMG, по которому щелкнул пользователь. После получения события изображением событие продолжает подниматься вверх через родительские элементы изображения. Таким образом, может быть совместно использована одна карта изображения и события или, в зависимости от обстоятельств, изображение само может изменять или добавлять элементы собственного поведения в карту изображения. Элементы, которые содержат карту изображения в исходном коде HTML, могут никогда не получить события, которые возникли в карте изображения.


Доступ к карте изображений

Свойство useMap элемента IMG содержит имя связанной карты изображения, которому предшествует символ #. Удалив предшествующий символ # из свойства useMap, можно обратиться к карте изображения. Свойство useMap допускает операции чтения/записи, что позволяет динамически связывать карты изображений с изображением. Приведенный ниже код демонстрирует простую функцию для получения связанной карты изображения из элемента IMG:


function getMap(elImage) {
   // Убедитесь, что для изображения определена карта.
   if (null != elImage.useMap) {
      // Удаляет первый символ # из закладки.
      var strMap = elImage.useMap.substring(1);
      // Возвращает элемент с указанным именем.
      return document.all[strMap];
   }
   else
      return null;
}

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

Рис. 9.4. Изображение может иметь две различных карты изображения

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

<HTML>
   <HEAD>
      <TITLE> Переключение карт изображений </TITLE>
      <SCRIPT LANGUAGE="JavaScript">
         function setMap(mapName) {
            document.all.mapImage.useMap = mapName;
         }
      </SCRIPT>
   </HEAD>
   <BODY>
      <P>Select From:<BR>
         <INPUT TYPE=RADIO NAME="feature" ID="States" Value="#States"
            ONCLICK="setMap(this.value);" CHECKED>
         <LABEL FOR="States">States</LABEL><BR>
         <INPUT TYPE=RADIO NAME="feature" ID="Cities" Value="#Cities"
            ONCLICK="setMap(this.value);">
         <LABEL FOR="Cities">Cities</LABEL></P>
      <P><IMG ID="mapImage" SRC="places.gif" BORDER=0
         WIDTH=197 HEIGHT=448 USEMAP="#States"></P>
      <MAP NAME="Cities">
         <AREA SHAPE="POLYGON" HREF="la.htm"
            COORDS="108, 408, 164, 407, 165, 388, 111, 387,          
               109, 361, 86, 361, 73, 394, 94, 411">
         <AREA SHAPE="POLYGON" HREF="sanfran.htm"
            COORDS="12, 301, 58, 275, 75, 305, 80, 301, 87, 314,     
               92, 326, 119, 329, 121, 340, 45, 341, 44, 328,        
               9, 328">
         <AREA SHAPE="POLYGON" HREF="portland.htm"
            COORDS="34, 120, 47, 120, 49, 115, 68, 115, 69, 123,     
               86, 127, 86, 131, 140, 131, 137, 144, 86, 145,        
               91, 162, 22, 160, 22, 148, 26, 144">
         <AREA SHAPE="POLYGON" HREF="seattle.htm"
            COORDS="73, 86, 93, 84, 92, 73, 125, 73, 123, 59,        
               92, 57, 87, 43, 93, 22, 82, 2, 71, 21, 79, 45">
      </MAP>
      <MAP NAME="States">
         <AREA SHAPE="POLYGON" HREF="california.htm"
            COORDS="14, 204, 18, 200, 83, 209, 79, 278, 166, 386,    
               171, 403, 167, 409, 166, 419, 163, 423, 164, 430,     
               166, 436, 161, 439, 115, 438, 112, 433, 110, 420,     
               97, 409, 92, 401, 82, 399, 77, 392, 56, 385, 54       
               369, 46, 357, 46, 352, 34, 338, 39, 327, 35, 322,     
               32, 309, 34, 297, 25, 297, 24, 288, 14, 273, 15,      
               255, 9, 235, 12, 224, 12, 221, 16, 216">
         <AREA SHAPE="POLYGON" HREF="oregon.htm"
            COORDS="16, 199, 136, 216, 140, 178, 143, 171,           
               138, 164, 153, 132, 147, 122, 103, 120, 80, 123,      
               72, 121, 55, 121, 51, 109, 37, 105, 22, 163,          
               23, 166, 18, 173, 14, 189">
         <AREA SHAPE="POLYGON" HREF="washington.htm"
            COORDS="33, 50, 64, 64, 57, 74, 57, 86, 63, 81,          
               70, 65, 66, 41, 152, 55, 147, 123, 100, 119,          
               86, 124, 74, 120, 56, 119, 51, 108, 40, 104,          
               36, 99, 43, 93, 37, 87, 41, 84, 36, 80">
      </MAP>
   </BODY>
</HTML>

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


Доступ к элементам Area

Динамический HTML представляет элементы Area посредством следующих семейств:

Сценарии могут обращаться к атрибутам элемента Area любым из перечисленных выше трех способов для их динамического изменения. Элемент Area имеет атрибут HREF, который содержит адрес URL и представляет те же свойства, содержащие части данного адреса, которые представлены объектами location и anchor. Семейство areas обеспечивает дополнительные Функциональные возможности, что позволяет добавлять и удалять новые элементы Area из карты изображения.

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

<HTML>
   <HEAD>
      <TITLE> Динамическое масштабирование карт изображений </TITLE>
      <SCRIPT LANGUAGE="JavaScript">
         function getMap(elImage) {
            // Убедитесь, что для изображения определена карта изображения.
            if (null != elImage.useMap) {
               // Удаляет первый символ # из закладки.
               var strMap = elImage.useMap.substring(1);
               // Возвращает элемент с указанным именем.
               return document.all[strMap];
            }
            else
               return null;
         }

         function zoomImage(elImage, amount) {
            // Разворачивает изображение до указанного размера.
            var elMap = getMap(elImage);
            elImage.width *= amount;
            elImage.height *= amount;
            // Если доступна карта изображения, то она также будет 
            // масштабирована.
            if (null != elMap) {
               for (var intLoop = 0; intLoop < elMap.areas.length;
                     intLoop++) {
                  var elArea = elMap.areas[intLoop];
                  // Разбиение строки координат на массив.
                  var coords = elArea.coords.split(",");
                  var scaledCoords = "";
                  // Повторное построение новой масштабированной строки.
                  for (coord in coords) {
                     scaledCoords += (coords[coord] * amount) + ",";
                  }

                  // Помещение масштабированных координат обратно в изображение.
                  elArea.coords = scaledCoords;
               }
            }
         }

         function swapButtons(b1, b2) {
            // Смена кнопок активизировано/выключено.
            document.all[b1].disabled = true;
            document.all[b2].disabled = false;
         }
      </SCRIPT>
   </HEAD>
   <BODY>
      <P>
         <INPUT TYPE=BUTTON VALUE="Zoom In"
            ONCLICK="zoomImage(document.all.img1, 2);
               swapButtons(`zoomin', 'zoomout');"
            ID="zoomin">
         <INPUT TYPE=BUTTON VALUE="Zoom Out"
            ONCLICK="zoomImage(document.all.img1, .5);
               swapButtons(`zoomout', 'zoomin');"
            ID="zoomout" DISABLED>
      </P>
      <P>
         <IMG SRC="img001.gif" WIDTH=200 HEIGHT=200
            ID="img1" USEMAP="#map1">
         <MAP NAME="map1">
            <AREA SHAPE="POLYGON"
               COORDS="92, 140, 126, 114, 155, 139, 124, 163"
               HREF="home.htm">
            <AREA SHAPE="CIRCLE" COORDS="30, 105, 30" HREF="cool.htm">
            <AREA SHAPE="RECT" COORDS="62, 28, 200, 79"
               HREF="dhtml.htm">
         </MAP>
      </P>
   </BODY>
</HTML>


Добавление и удаление элементов Area

Используя семейство areas, динамический HTML поддерживает способ-кость динамического добавления и удаления элементов Area из карты изображения. При создании нового элемента Area используется тот же метод, что и при создании нового изображения. Главное отличие заключается в том, что новый элемент Area может быть непосредственно добавлен в существующее семейство all карты, тогда как объект нового изображения не может быть добавлен в документ.

Семейство areas представляет методы add и remove. Метод add принимает элемент Area, созданный с помощью метода createElement, и добавляет его в семейство areas. Метод remove используется для удаления существующего элемента Area из карты изображения. Приведенный ниже пример представит собой простой редактор карт изображений, написанный целиком на HTML:

<HTML>
   <HEAD>
      <TITLE> Редактор карт изображений </TITLE>
      <SCRIPT LANGUAGE="JavaScript">
         var curFocus = null;

         function areaFocus() {
            // Отслеживает последний выбранный элемент Area.
            if ("AREA" == event.srcElement.tagName)
               curFocus = event.srcElement;
         }

         function removeArea() {
            // Удаляет элемент Area.
            var coll = document.all.dynaMap.areas;
            if (null != curFocus) // Убедитесь, что элемент выбран.
               // Циклический просмотр элементов Area и поиск выбранного
               //  элемента.
               for (var intLoop = 0; intLoop < coll.length; intLoop++)
                  if (curFocus == coll[intLoop]) {
                     document.all.dynaMap.areas.remove(intLoop);
                     return;
                  }
            alert("No Area element is selected.");
         }

         function addArea(f) {
            /* Убедитесь, что выбраны координаты. Данный код не выполняет
               дополнительной проверки координа. */
            if ("" != f.coordinates.value) {
               var elArea = document.createElement("AREA");
               elArea.coords = f.coordinates.value;
               // Определение выбранной формы.
               for (var intLoop = 0; intLoop < f.shape.length;
                     intLoop++)
                  if (f.shape[intLoop].checked)
                     elArea.shape = f.shape[intLoop].id;
               document.all.dynaMap.areas.add(elArea);
            }
            else
               alert("You need to enter a Coords value.");
            event.returnValue = false;
         }
      </SCRIPT>
   </HEAD>
   <BODY>
      <H1>Image Map Editor</H1>
      <H2>Select a Shape</H2>
      <FORM NAME="area">
         <!-- Идентификатор ID используется для определения атрибута формы. -->
         <P>
            <INPUT TYPE=RADIO NAME="shape" ID="rect" CHECKED>
            <LABEL FOR="rect">Rect</LABEL>
         <BR>
            <INPUT TYPE=RADIO NAME="shape" ID="polygon">
            <LABEL FOR="polygon">Polygon</LABEL>
         <BR>
            <INPUT TYPE=RADIO NAME="shape" ID="circle">
            <LABEL FOR="circle">Circle</LABEL>
         </P>
         <P>
            <LABEL FOR="coords">Coords</LABEL>
            <INPUT TYPE=TEXT ID="coords" NAME="coordinates">
         </P>
         <P>
            <INPUT TYPE=SUBMIT VALUE="Add Area"
               ONCLICK="addArea(this.form)">
            <INPUT TYPE=BUTTON VALUE="Remove Area"
               ONCLICK="removeArea()">
         </P>
      </FORM>
      <IMG SRC="img001.gif" WIDTH=200 HEIGHT=200 USEMAP="#dynaMap">
      <MAP NAME="dynaMap" ONCLICK="areaFocus()">
      </MAP>
   </BODY>
</HTML>



Программирование элемента Marquee

Intemet Explorer 3.0 поддерживает простой элемент Marquee (бегущая строка) для горизонтального прокручивания текста. В Internet Explorer 4.0 элемент Marquee был улучшен с помощью полной объектной модели и за счет реализации поддержки и воспроизведения любого кода HTML. Новый элемент Marquee может даже содержать элементы управления, которые реагируют на нажатия кнопки мыши и клавиатурный ввод при воспроизведении элемента. В число других улучшений входит способность прокручивания в любом направлении - влево, вправо, вверх и вниз.

Бегущая строка может отображаться в одном из трех режимов: alternate, scroll и slide. В режиме alternate содержание бегущей строки перемещается вперед и назад, или вверх и вниз, всегда оставаясь на экране. В режимах scroll и slide содержание перемещается в одном направлении. Например, бегущая строка может перемещаться от правой границы экрана к его левой границе. В режиме scroll движение повторяется только после завершения прокручивания всего содержания бегущей строки. В режиме slide движение начинает повторяться после вывода на экран последнего элемента содержания бегущей строки. Используя эти три типа поведения, можно определить конечное число повторений или установить режим повторения до тех пор, пока пользователь не покинет страницу.



Свойства анимации бегущей строки

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

Таблица 9.2. Атрибуты бегущей строки


Атрибут/свойство Перезапускает бегущую строку? Описание

behavior Да Определяет режим alternate, scroll или slide для бегущей строки. Значение по умолчанию равно scroll
direction Нет Определяет направление движения. Поддерживаются все четыре направления движения: left, right, up И down. Значение по умолчанию равно right (вправо)
height Да Определяет физическую высоту бегущей строки
loop Да Определяет число повторений анимации. Значение по умолчанию равно infinite (бесконечное число раз)
scrollAmount Нет Определяет число пикселов перемещения при изменении содержания. Значение по умолчанию равно 6
scrollDelay Нет Определяет число миллисекунд между изменениями содержания. Значение по умолчанию равно 85
trueSpeed Нет Определяет, должна ли бегущая строка прерываться при пропущенных циклах. Значение по умолчанию равно false, что определяет поведение бегущей строки как в Internet Explorer 3.0
width Да Определяет физическую ширину бегущей строки



События бегущей строки

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

Таблица 9.3. События бегущей строки


Событие Описание

onstart Бегущая строка скоро начнет прокручиваться. Для бегущей строки в режимах scroll или slide данное событие возникает каждый раз перед запуском последовательности анимации. Для бегущей строки в режиме alternate данное событие возникает один раз в начале анимации
onbounce Анимация бегущей строки достигла конца и начнется в обратном направлении. Данное событие возникает, когда свойство behavior элемента Marquee установлено равным alternate
onfinish Бегущая строка прекратила прокручивание



Методы Marquee

Элемент Marquee представляет два метода для запуска и остановки анимации: start и stop, которые могут быть использованы для управления прокручиванием бегущей строки вручную.

Пользуя методы start и stop, приведенный ниже код позволяет пользователю останавливать и запускать бегущую строку путем удерживания и отпускания кнопки мыши над бегущей строкой. Остановив бегущую строку, пользователю легче прочитать ее содержание. Атрибут title бегущей строки отображается как подсказка (ТооlTiр), когда указатель мыши удерживается над элементом Marquee.

<HTML>
   <HEAD>
      <TITLE> Методы stop и start бегущей строки </TITLE>
   </HEAD>
   <BODY>
      <MARQUEE TITLE="Hold down the mouse button to stop the marquee."
            ONMOUSEDOWN="this.stop();"
            ONMOUSEUP="this.start();">
         <H1>Test Marquee</H1>
         <P>Clicking the mouse button and holding it down
            stops the marquee from scrolling.</P>
         <INPUT TYPE=BUTTON VALUE="Demo Button"
            ONCLICK="alert('clicked');">
      </MARQUEE>
   </BODY>
</HTML>



Программирование элемента Object

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



Обработка конфликтов свойств

Между членами объекта и членами общего элемента Object может возникнуть конфликт. Например, если объект представляет свойство id, то оно будет конфликтовать со свойством id, представленным элементом Object. При возникновении данного конфликта обращение к свойству id указывает версию элемента, а не объекта. Для ссылки на версию объекта свойства id, все элементы объекта представляют свойство object. Данное свойство восстанавливает доступ к внедренным членам объекта, как показано в приведенном ниже коде.


document.all.myObject.id         // Свойство id элемента HTML
document.all.myObject.object.id  // Свойство id внедренного объекта.



Альтернативный HTML

Элемент Object может содержать код HTML, отображаемый браузерами, не поддерживающими элемент Object. Содержание низкого уровня представлено как свойство altHTML элемента Object в HTML.

Свойство altHTML может быть использовано для передачи содержания пользователю, если объект не может быть инсталлирован. Если объект не может быть инсталлирован, то объект на странице заменяется альтернативным содержанием. В приведенном ниже коде значение свойства altHTML элемента Object является элементом paragraph (теги <р> и </р> между которыми заключен текст):

<OBJECT CLASSID="java:myClass">
   <PARAM NAME="color" VALUE="red">
   <P>
      Ваш браузер не поддерживает элемент Object или возникла 
      ошибка во время загрузки объекта.
   </P>
</OBJECT>



События объекта

Объект может генерировать собственные события. Вы можете связать обработчик с таким событием, используя не тег элемента, а синтаксис <SCRIPT FOR=EVENT=> или независимый от языка механизм. Элемент Object представляет атрибуты только для стандартных событий, а не для тех, которые генерируются внедренным объектом.

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



Программирование элемента Table

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

Таблицы были существенно улучшены в Internet Explorer 3.0 для поддержки элементов, которые теперь введены в HTML 4.0. Элементы THead, TBody и TFoot были добавлены для определения разделов заголовка, тела и примечаний в таблице. Элементы Col и ColGroup предоставляют большие возможности управления столбцами. При соответствующем использовании данные элементы могут улучшить производительность таблиц, особенно путем определения ширины столбцов и, обеспечивая большие возможности управления воспроизведением границ. Элемент Table представляет мощную объектную модель для динамического манипулирования таблицами.



Объект table

Каждый элемент Table включает объемную информацию о своем содержании. Объект table обеспечивает доступ к трем различным разделам таблицы: THead, TBody и TFoot. Таблица может содержать по одному элементу THead и TFoot, но много элементов TBody. Поэтому объектная модель представляет одиночные свойства tHead и tFoot и семейство tBodies.

Объект table представляет методы для создания и удаления элементов THead, TFoot и Caption. (На данный момент не существует метода вставки дополнительных элементов TBody в таблицу). Данные методы перечислены в табл. 9.4.

Таблица 9.4. Методы объекта table


Метод Описание

createTHead(),
createTFoot(),
createCaption()
Создает и удаляет определенный раздел, если раздел не существует. Если раздел уже существует, то вместо создания нового, метод возвращает существующий раздел
deleteTHead(),
deleteTFoot(),
deleteCaption()
Удаляет указанный раздел и его строки из таблицы, если раздел существует
insertRow([index]) Вставляет строку в таблицу перед строкой номер [index]. Данная строка добавляется в тот же раздел, в котором находится обозначенная индексом index строка. Если значение index не указано, то строка добавляется в конец таблицы в том же разделе как последняя строка. Данный метод возвращает строку, которая была вставлена
deleteRow(index) Удаляет строку с указанным значением index из таблицы

Объект table также использует семейство rows. Данное семейство rows представляет все строки в таблице, независимо от раздела, в котором находятся строки. Для определения раздела, который содержит строку, вы можете проверить свойство parentElement отдельной строки. Кроме того, каждый раздел представляет семейство rows, которое содержит содержащиеся в данном разделе строки.



Семейства rows и cells

Объект table представляет отношения между строками и ячейками таблицы. Как упоминалось выше, семейство rows объекта table содержит все элементы TR в таблице, а семейства rows объектов tHead, tBody и tFoot содержат элементы TR в соответствующих разделах. Каждая строка последовательно представляет семейство cells, которое ссылается на элементы TD или ТН внутри строки. Семейства rows и cells представляют те же методы tags и item, которые доступны в других семействах элементов. Вы можете использовать свойство id элемента для непосредственного просмотра семейств rows и cells.


Программирование семейства rows

Семейство rows в объекте table игнорирует положение строки в заголовке, теле или примечании таблицы, но, тем не менее, поддерживаются отношения элемента TR с родительским элементом:

<TABLE ID="myTable">
   <THEAD>
      <TR ID="header"><TH>City</TH><TH>State</TH></TR>
   </THEAD>
   <TBODY>
      <TR><TD>Issaquah</TD><TD>Washington</TD></TR>
      <TR><TD>Seattle</TD><TD>Washington</TD></TR>
   </TBODY>
</TABLE>

В данном примере семейство rows в объекте myTabie содержит три строки в таблице. Чтобы выяснить, находится ли строка внутри элемента TBody или THead можно проверить свойство parentElement отдельной строки:


document.all.myTable.rows.length                     // 3
document.all.myTable.THead.rows.length               // 1
document.all.myTable.rows[0].parentElement.tagName   // THEAD
document.all.myTable.rows[1].parentElement.tagName   // TBODY

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

Данное свойство, которое представлено во всех элементах, описано в главе 8.

Свойство rowIndex представляет индекс строк во всей таблице, а свойство sectionRowIndex представляет индекс строк в своем разделе. В предыдущем примере строка, содержащая Seattle, имеет значение свойства rowIndex, равное 2 и значение свойства sectionRowIndex, равное 1. (Значение свойства sourceIndex строки зависит от местонахождения таблицы в документе).

Все строки обеспечивают доступ к своим ячейкам посредством семейства cells. Методы insertCell и deleteCell добавляют и удаляют ячейки из строки и работают аналогично методам insertRow и deleteRow. Метод insertCell принимает в качестве аргумента необязательный параметр - индекс ячейки, перед которой будет вставлена новая ячейка, и возвращает вставленную ячейку. Аргументом метода deleteCell является индекс удаляемой ячейки. Приведенный ниже код показывает, как получить доступ и манипулировать ячейками в приведенной выше таблице:


document.all.myTable.rows[0].cells.length  // 2 ячейки
document.all.header.cells.length   // 2 ячейки, доступ посредством ID
document.all.header.deleteCell(0); // Удаление первой ячейки в строке заголовка.


Атрибуты ROWSPAN и COLSPAN

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

<HTML>
   <HEAD>
      <TITLE> Строки и ячейки HTML </TITLE>
   </HEAD>
   <BODY>
      <TABLE BORDER ID="tbl1">
         <CAPTION>Sample Table</CAPTION>
         <TR><TD ROWSPAN=3>0, 0</TD>
            <TD COLSPAN=2>0, 1</TD><TD>0, 2</TD></TR>
         <TR><TD>1, 0</TD><TD ROWSPAN=2 COLSPAN=2>1, 1</TD></TR>
         <TR><TD>2, 0</TD></TR>
      </TABLE>
      <SCRIPT LANGUAGE="JavaScript">
         // Вывод информации о таблице.
         document.write("<H2>Table Information</H2>");
         with (document.all.tbl1) {
            for (var intRows=0; intRows < rows.length; intRows++)
               document.write("Row " + intRows + " has " +
                  rows[intRows].cells.length + " cell(s).<BR>");
            document.write("<P>Here is the same table without " +
               "any cells spanning multiple rows or columns:");
            document.write("<TABLE BORDER>");
            for (var intRows = 0; intRows < rows.length; intRows++) {
               document.write("<TR>");
               for (var intCells = 0;
                     intCells < rows[intRows].cells.length;
                     intCells++)
                  document.write("<TD>" + intRows + "," + intCells +
                     "</TD>");
               document.write("</TR>");
            }
            document.write("</TABLE>");
         }
      </SCRIPT>
   </BODY>
</HTML>

На рис. 9.5 показано отображение данной таблицы в окне браузера. Строки и ячейки определены в основном коде, независимо от действительного воспроизведения таблицы. Числа в ячейках представляют индекс строки в семействе rows, после которого указан индекс этих ячеек в семействе cells. Вторая таблица не имеет атрибутов ROWSPAN и COLSPAN. Соответствующие ячейки имеют одинаковые индексы в обеих таблицах.

Рис. 9.5. Охватывающие ячейки и содержащие их семейства

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



Событие onresize

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



Таблицы глобальных стилей

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



Создание календаря

Приведенный ниже код демонстрирует процедуру манипулирования таблицей, используя семейства rows и cells. Сценарий генерирует большинство документов, используя метод document, write.

<HTML>
   <HEAD>
      <TITLE> Календарь </TITLE>
      <STYLE TYPE="text/css">
         .today {color:navy; font-weight:bold}
         .days {font-weight:bold}
      </STYLE>
      <SCRIPT LANGUAGE="JavaScript">
         // Инициализация рядов.
         var months = new Array("January", "February", "March",
            "April", "May", "June", "July", "August", "September",
            "October", "November", "December");
         var daysInMonth = new Array(31, 28, 31, 30, 31, 30, 31, 31,
            30, 31, 30, 31);
         var days = new Array("Sunday", "Monday", "Tuesday",
            "Wednesday", "Thursday", "Friday", "Saturday");

         function getDays(month, year) {
            // Проверка, является ли год високосным.
            if (1 == month)
               return ((0 == year % 4) && (0 != (year % 100))) ||
                  (0 == year % 400) ? 29 : 28;
            else
               return daysInMonth[month];
         }

         function getToday() {
            // Генерирование сегодняшней даты.
            this.now = new Date();
            this.year = this.now.getYear() + 1900; // Relative
                                                   // to 1900
            this.month = this.now.getMonth();
            this.day = this.now.getDate();
         }

         // Запуск календаря с сегодняшнего дня.
         today = new getToday();

         function newCalendar() {
            today = new getToday();
            var parseYear = parseInt(document.all.year
               [document.all.year.selectedIndex].text) - 1900;
            var newCal = new Date(parseYear,
               document.all.month.selectedIndex, 1);
            var day = -1;
            var startDay = newCal.getDay();
            var daily = 0;
            if ((today.year == newCal.getYear() + 1900) &&
                  (today.month == newCal.getMonth()))
               day = today.day;
            // Кэширование табличного элемента tBody по имени dayList.
            var tableCal = document.all.calendar.tBodies.dayList;
            var intDaysInMonth =
               getDays(newCal.getMonth(), newCal.getYear() + 1900);
            for (var intWeek = 0; intWeek < tableCal.rows.length;
                  intWeek++)
               for (var intDay = 0;
                     intDay < tableCal.rows[intWeek].cells.length;
                     intDay++) {
                  var cell = tableCal.rows[intWeek].cells[intDay];

                  // Запуск счета дней.
                  if ((intDay == startDay) && (0 == daily))
                     daily = 1;

                  // Выделение текущего дня.
                  cell.className = (day == daily) ? "today" : "";

                  // Вывод номера дня в ячейке.
                  if ((daily > 0) && (daily <= intDaysInMonth))
                     cell.innerText = daily++;
                  else
                     cell.innerText = "";
               }
         }

         function getDate() {
            // Данный код выполняется, когда пользователь выбирает день  
            // в календаре.
            if ("TD" == event.srcElement.tagName)
               // Test whether day is valid.
               if ("" != event.srcElement.innerText)
                  alert(event.srcElement.innerText);
         }
      </SCRIPT>
   </HEAD>
   <BODY ONLOAD="newCalendar()">
      <TABLE ID="calendar">
         <THEAD>
            <TR>
               <TD COLSPAN=7 ALIGN=CENTER>
                  <!-- Month combo box -->
                  <SELECT ID="month" ONCHANGE="newCalendar()">
                     <SCRIPT LANGUAGE="JavaScript">
                        // Вывод месяцев в документ.
                        // Выбор текущего месяца.
                        for (var intLoop = 0; intLoop < months.length;
                              intLoop++)
                           document.write("<OPTION " +
                              (today.month == intLoop ?
                                 "Selected" : "") + ">" +
                              months[intLoop]);
                     </SCRIPT>
                  </SELECT>

                  <!-- Year combo box -->
                  <SELECT ID="year" ONCHANGE="newCalendar()">
                     <SCRIPT LANGUAGE="JavaScript">
                        // Вывод лет в документ.
                        // Выбор текущего года.
                        for (var intLoop = 1995; intLoop < 2000;
                              intLoop++)
                           document.write("<OPTION " +
                              (today.year == intLoop ?
                                 "Selected" : "") + ">" +
                              intLoop);
                     </SCRIPT>
                  </SELECT>
               </TD>
            </TR>
            <TR CLASS="days">
               <!-- Генерация столбца для каждого дня. -->
               <SCRIPT LANGUAGE="JavaScript">
                  // Вывод дней.
                  for (var intLoop = 0; intLoop < days.length;
                        intLoop++)
                     document.write("<TD>" + days[intLoop] + "</TD>");
               </SCRIPT>
            </TR>
         </THEAD>
         <TBODY ID="dayList" ALIGN=CENTER ONCLICK="getDate()">
            <!-- Генерация сетки для отдельных дней. -->
            <SCRIPT LANGUAGE="JavaScript">
               for (var intWeeks = 0; intWeeks < 6; intWeeks++) {
                  document.write("<TR>");
                  for (var intDays = 0; intDays < days.length;
                        intDays++)
                     document.write("<TD></TD>");
                  document.write("</TR>");
               }
            </SCRIPT>
         </TBODY>
      </TABLE>
   </BODY>
</HTML>

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

На рис. 9.6 показан пример календаря в окне браузера.

Рис. 9.6. Календарь, созданный с помощью динамического HTML

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

Урок 10. Формы и внутренние элементы управления


Реклама: