ПРИМЕРЫ СКРИПТОВ
Современные гипертекстовые информационные системы условно можно представить в виде совокупности нескольких компонентов: систем хранения гипертекстовых объектов, систем отображения гипертекстовых объектов, систем подготовки гипертекстовых объектов и систем программирования просмотра совокупности гипертекстовых объектов. С этой точки зрения, технология World Wide Web только к 1996 году получила законченный, функционально полный вид. Первыми были разработаны системы хранения и просмотра (1989-1991), которые продолжают развиваться и в настоящее время. После 1990 года стали появляться первые системы подготовки документов. Наконец, в 1995 году были предложены первые языки управления сценариями просмотра. В данной статье речь пойдет как раз об одном из них - JavaScript.
Программирование процедуры просмотра гипертекстовой базы данных не является изобретением Netscape, Microsoft или Sun. Практически все локальные гипертекстовые системы в той или иной степени имеют программные средства манипулирования гипертекстовыми объектами.
В ряде случаев вся гипертекстовая база данных может быть представлена как одна большая программа, в которой гипертекстовые узлы - это программные модули, а связи между ними - это передача управления от одного модуля другому.
Преимущества такого подхода перед традиционной статической разметкой очевидны: гибкость построения гипертекстовой сети, возможность создания программ прокрутки фрагментов базы данных, генерация составных гипертекстовых объектов из существующих элементарных компонентов. Динамические объекты могут быть легко получены из статических, так как в случае существования браузера система может быть переведена из интерактивного режима просмотра гипертекстовой базы данных в пакетный, когда действия оператора будут заменяться командами программы.
Браузеры гипертекстовых страниц традиционно называют скриптами (scripts), по аналогии с исполняемыми файлами, написанными для командных интерпретаторов типа sh. Собственно, как это было и раньше в локальных системах, в программировании просмотра гипертекстовых документов World Wide Web существуют два подхода: создание интерпретируемых браузером скриптов или компиляция байт-кода. Первый подход не выходит за рамки традиции World Wide Web, согласно которой для разработки гипертекстовой страницы нужен только обычный текстовый редактор, и сам гипертекстовый документ должен легко читаться человеком-оператором. Второй подход позволяет повысить эффективность исполнения программы и защищенность кода от несанкционированных модификаций. Как первый, так и второй способы опираются на объектно-ориентированный подход к программированию. По поводу байт-кодов, или, как их еще называют, мобильных кодов, написано в контексте технологии программирования Java достаточно много, поэтому сосредоточим свое внимание на скриптах, а точнее, на скриптах, написанных на языке JavaScript.
Идея JavaScript очень проста. Все операции, которые можно исполнять в программе на JavaScript, описывают действия над хорошо известными и понятными объектами, которыми являются элементы рабочей области программы Netscape Navigator и контейнеры языка HTML. Собственно объектная ориентированность JavaScript на этом и кончается. Никаких классов объектов, а тем более, наследования в JavaScript нет. Есть только объекты с набором свойств и набор функций над объектами, которые называются методами. Кроме методов существуют и другие функции, больше похожие на функции из традиционных языков программирования, которые позволяют работать со стандартными математическими типами или управлять процессом выполнения программы. Еще в JavaScript есть события - аналог программных прерываний. Эти события также ориентированы на работу в World Wide Web, например загрузка страницы в рабочую область Navigator или выбор гипертекстовой ссылки. Используя события, автор гипертекстовой страницы и программы, ее отображающей, может организовать просмотр динамических объектов, например бегущей строки, или управление многооконным интерфейсом.
Для встраивания скриптов в тело HTML-документа используется контейнер SCRIPT. Не все браузеры способны распознавать и исполнять скрипты, поэтому само тело скрипта помещается в контейнер комментария. Рассмотрим пример 1.
В этом примере в заголовок документа (контейнер HEAD) включен контейнер SCRIPT. До недавнего времени атрибут LANGUAGE в этом контейнере не являлся обязательным. Но с момента выхода VBSCRIPT появился смысл в указании типа языка - Navigator не понимает скриптов на других языках. Отсутствие атрибута может привести к ошибкам при отображении гипертекстовых страниц.
Далее, в тексте страницы определен комментарий, в который включен текст скрипта. Начинается комментарий со строки:
<!- The JavaScript Function Definition
И кончается строкой:
// The end of JavaScript Functions Definition ->
Внутри контейнера SCRIPT определены две функции пользователя: help_win() и main_menu(). Смысл этих функций достаточно прозрачен. Help_win() предназначена для организации контекстно зависимого help, а main_menu() осуществляет допуск пользователя к главному меню Website. Обе функции используют один и тот же метод open (встроенную в JavaScript функцию, которая определена над объектом window) для того, чтобы открыть новое окно Netscape Navigator и загрузить в него гипертекстовые документы. При этом функция main_menu порождает стандартное окно (с кнопочками, иконками и т.п.), а функция help_win() - окно без стандартных атрибутов. У этого окна имеются только линейки прокрутки (scroll bars).
Вызов функций осуществляется после нажатия на соответствующие кнопки, которые определены в HTML-форме help_call. Таким образом, функции будут выполняться только в том случае, если произойдет событие, описанное атрибутом onClick в контейнере INPUT соответствующего поля формы.
Если быть более точным, то приведенный пример - это фрагмент, реализующий регистрацию пользователя. К моменту его выполнения окно главного меню уже открыто, поэтому при выборе кнопки NEXT окно не создается, а текст загружается в уже открытое окно.
Теоретизировать на предмет написания скриптов на JavaScript можно долго. Но самый продуктивный способ получить представление о языке - это разбор примеров. Если посмотреть на список этих примеров, который можно найти в соответствующей директории Yahoo, легко убедиться, что больше всего там различного сорта калькуляторов. Разберем программу такого же типа, только это будет не калькулятор, а программа обучения устному счету.
Приведенный пример 2 содержит датчик случайных чисел (функции init и rand), таблицу, реализующую функции кнопок клавиатуры, и блок проверки результата вычислений. После загрузки программы пользователь должен выбрать тип вычислений (+,-), интервал вычислений (в пределах 10, 20, 100) и нажать кнопку "?" для генерации примера. После ввода числа с отображаемой клавиатуры пользователь нажимает на символ "=", что означает исполнить, и система проверяет правильность ответа. Если ответ правильный, то программа выдает "Молодец!", если нет - "Думай!". В системе Windows 3.x нет встроенного датчика случайных чисел, поэтому стандартная функция rand в этой версии JavaScript не реализована. Используемый в данной программе датчик был позаимствован из телеконференции по JavaScript. В скрипте, кроме этого, применяются объект типа "дата" и его методы, а также встроенные функции контроля вводимых данных. Как явствует из примера, обращение к полям HTML-формы представляет собой обращение к структуре, корнем которой является объект "окно", в котором определен объект "документ", внутри которого определена форма, а также ее поля и атрибуты полей. Не у всех полей можно менять значения атрибутов, так, например, атрибут VALUE в кнопке не меняет своего значения, если только не перезагрузить страницу.
Другой часто встречающийся пример - бегущая строка. Строка может бежать либо в поле статуса (низ экрана), либо внутри поля формы. Рассмотрим пример 3.1.
Здесь приведен фрагмент страницы компании "Демос", разработанный Дмитрием Алтуховым (ady@demos.su). Как видно из этого примера, прокрутка осуществляется за счет изменения содержания отображаемой переменной msg1. Запускается бегущая строка в момент загрузки страницы по событию onLoad. Из комментария к примеру следует, что автор не несет ответственности за проблемы, которые может данный скрипт породить при его отображении браузером на компьютере пользователя. Собственно проблема вызвана применением функции setTimeout. Изначально предполагалось, что браузер, который поддерживает JavaScript, будет исполняться в среде многопоточных операционных систем. В этом случае к моменту порождения нового потока старый уже завершится, и setTimeout будет, таким образом, порождать последовательно исполняемые потоки. Однако при реализации JavaScript в Netscape Navigator 2.0 не все было выполнено аккуратно, и setTimeout стала просто "пожирать" ресурсы компьютера. Системы Windows 3.x вообще не являются многопоточными, и в них просто происходит переполнение стека при выполнении данного скрипта. Весь вопрос заключается только в том, как быстро "упадет" система, а это зависит от объема исполняемой по setTimeout функции. Самое лучшее, что можно посоветовать, если вдруг на экране появляется прокрутка, - поскорее покинуть такую страницу. Справедливости ради, следует отметить, что прокрутку можно организовать и другими способами, поэтому ее появление не обязательно должно вызывать крах системы или браузера.
Прокручивать можно и вертикальные фрагменты. Достигается это за счет использования полей типа TEXTAREA (пример 3.2).
Собственно все организовано так же, как и в предыдущем примере, только прокрутка осуществляется в поле формы; для этого поля введен параметр переноса текста на новую строку, ширина поля подобрана под размер выводимых строк. Прокрутка осуществляется как по событию onLoad, так и при нажатии на кнопку Start/Stop. В этом случае не надо немедленно покидать страницу с прокруткой - достаточно просто ее остановить.
Другой, часто встречающийся пример на странице со скриптами JavaScript - идущие часы (пример 4).
В этом примере реализовано сразу три приема использования JavaScript: часы, бегущая строка и предупреждение.
Часы реализованы в строках, которые следуют за комментарием "//Clock". В них также применяется функция setTimeout и объект DATE. Прежде чем отобразить время, программа получает текущее значение времени через объект DATE. Считается, что после выполнения программы все объекты будут удалены из памяти, что реально не всегда происходит. Для отображения времени используются методы, которые определены для объекта DATE. Значения часов минут и секунд объединяются в строку при помощи операции конкатенации "+", и результат отображается в поле формы.
О бегущей строке мы уже говорили достаточно подробно, поэтому теперь предлагаю обратить внимание на функцию alert в форме kuku. Это встроенная в JavaScript функция, которая предупреждает пользователя о том, что он запускает на сервере программу.
Выполнение вычислений и работа с таблицами весьма популярны, но не столь значимы, как управление окнами браузера. Рассмотрим пример такого управления. Идея состоит в том, чтобы средствами JavaScript реализовать "свертывание" и "развертывание" окна браузера. Примеры 5.1 и 5.2 демонстрируют связанные друг с другом HTML-страницы.
Пример 5.1 сворачивает окно. Для этой цели сначала создается маленькое окно с иконкой, а потом текущее окно удаляется. На самом деле в данном случае надежность работы этого скрипта будет зависеть от алгоритма интерпретации и назначения текущего окна программой интерпретации. В Netscape Navigator 2.0 текущим оставалось окно, в котором исполняется скрипт, поэтому наша программа будет работать правильно. Маленькое окно становится текущим только после удаления большого окна.
Максимизация окна показана на примере 5.2. Данный фрагмент по алгоритму точно совпадает с предыдущим, но выполняет прямо противоположную функцию - разворачивает (восстанавливает) свернутое окно. При этом маленькое окно также удаляется. Собственно, первая страница - это файл iconize.htm, а вторая - test_icon.htm.
В заключение вернемся к первому примеру. В нем был описан вызов, который приводит к открытию окна контекстного help и загрузки в него HTML-страницы. На этой странице есть форма с кнопкой close, при нажатии на которую текущее окно закрывается. Так как в этом случае текущим является окно с help, то закрывается именно оно. Все это замечательно, если не используются фреймы в help. При применении фреймов текущим окном будет не главное окно, а окно фрейма. Если help состоит из нескольких фреймов, то простое выполнение функции window.close() не приведет к ожидаемому результату - закрытию всего окна. Корректнее всего будет загрузить в окно-предшественник (имя по умолчанию - _parent) пустую страницу, сделать ее текущей и после этого удалить. Вся страница, удаляющая окно _parent, состоит из контейнера SCRIPT (пример 6).
Вообще говоря, использовать такие страницы-терминаторы следует аккуратно. Ведь загрузка этой страницы может привести к завершению работы браузера, если других открытых страниц в данный момент нет.
Написание данных скриптов заставляет сожалеть о том, что в JavaScript нет наследования. Дело в том, что, даже если некоторое окно порождено из другого окна, функции, определенные в окне-родителе, в новое окно не передаются. Это означает, что автору придется их дублировать в каждом документе или прибегать к помощи включаемых файлов, что разрывает технологический процесс разработки страниц.
Следует отметить, что JavaScript - это не единственный язык управления сценариями просмотра документов. Microsoft подготовила свою версию аналогичного языка - VBScript на основе Visual Basic. Кроме того, управлять сценарием просмотра можно и из Java-апплетов, что, конечно, сложнее, но зато более надежно и безопасно. При этом программист получает все преимущества наследования и прочие атрибуты объектно-ориентированного программирования. В конце концов, для создания фреймов и окон можно использовать атрибуты соответствующих контейнеров HTML, которые позволяют делить рабочую область экрана на фрагменты, перекрывать объекты и восстанавливать первоначальный вид страницы. Таким образом, к настоящему времени существует по меньшей мере три способа управления сценариями просмотра гипертекстовых баз данных Web, каждый из которых по-своему хорош. Какой из них выбрать - это дело автора Website.
<HTML> <!- Author: Pavel Khramtsov Date: March 5, 1996 -> <HEAD> <TITLE>Registration</TITLE> <SCRIPT LANGUAGE="JavaScript"> <!- The JavaScript Functions Definition function help_win() {Help = window.open("reg_help.htm","Help","scrollbars=yes,resizable=yes") } function main_menu() {Main_menu = window.open("main_m.htm","Main_menu") } // The end of JavaScript Functions //Definition -> </SCRIPT> </HEAD> <BODY> <CENTER> <TABLE> <TR><TH><IMG SRC="radleg3.gif"></TH> <TH><H2>ISTC. Project RADLEG(#245)</H2> RRC "Kurchatov Institute"<BR> <I>Dec, 25, 1995</I> </TH></TR> </TABLE> </CENTER> <HR> <CENTER> <h2>Registration Form</h2> <hr> ...... Текст страницы ..... <hr> <FORM NAME=help_call> <TABLE BORDER=0> <TR> <TD><INPUT NAME=next TYPE=button VALUE=Next onClick="main_menu()"> </TD> <TD><INPUT NAME=help TYPE=button VALUE=Help onClick="help_win()"></TD> </TR> </TABLE> </FORM> <hr> </CENTER> </BODY> </HTML>
<HTML> <!- Author: Pavel Khramtsov Date: February 23, 1996 URL: http://144.206.192.100/radleg/ mo_input.htm -> <HEAD> <TITLE>Проверка устного счета.</TITLE> <SCRIPT LANGUGE="JavaScript"> <!- var max_value = 0; var operand1 = 0 var operand2 = 0; var result = 0 var flag = 0; var sign = "+" var input = ""; var v_date = new Date() var number = v_date.getTime() function init(factor){ var today = new Date() return (factor*today.getTime() /1000)%30000 } //Инициализировать датчик //случайных чисел IX = init(2); IY = init(3); IZ = init(4) //2, 3, and 4 below were arbitrarily cho- //sen. They put some distance between // the initial values of IX, IY, and IZ //Датчик случайных чисел. function random(){ IX = Math.floor(171 * IX % 30269) IY = Math.floor(172 * IY % 30307) IZ = Math.floor(170 * IZ % 30323) return ( IX/30269.0 + IY/30307.0 + IZ/30323.0 ) % 1.0 } //Выбрать сложение или вычитание function set_sign(x){ if( x == "+"){ flag = 0; sign = "+" } if( x == "-"){ flag = 1; sign = "-" } return true } // Определить первый операнд function f_operand(){ operand1 = random()*max_value return parseInt(operand1) } // Определить второй операнд function s_operand(){ if(flag == 0){ operand2 = random()* (max_value-operand1) } else { operand2 = random()* operand1 } return parseInt(operand2) } // Проверить введенные данные function input_sign(x){ if(x == 10){ if(flag == 0){ if(operand1+operand2 == parseInt(input)){ window.document.test. r0.value = "Молодец!" } else { window.document.test.r0.value = "Думай!?" window.document.test.input = ""; input = "" } } if(flag == 1){ if(operand1-operand2 == parseInt(input)){ window.document.test.r0.value ="Lі-іі-ір!" } else{ window.document.test.r0.value = "Думай!?" window.document.test.input = ""; input = "" } } return true } input += x window.document.test.result.value = input return true } // Генерация варианта function main_calc(){ operand1 = f_operand() window.document.test.op1.value = operand1 operand2 = s_operand() window.document.test.op2.value = operand2 window.document.test.s_sign.value = sign input = ""; window.document.test.input = "" window.document.test.r0.value = " ???" return true } // -> </SCRIPT> </HEAD> <BODY> <CENTER> <H1>Математический тест</H1> <HR> <FORM NAME=test> <TABLE BORDER=0> <TR> <TD><INPUT NAME=i10 TYPE=button VALUE="0-10" onClick="max_value=10"></TD> <TD><INPUT NAME=i20 TYPE=button VALUE="0-20" onClick="max_value=20"></TD> <TD><INPUT NAME=i100 TYPE=button VALUE="0-100" onClick="max_value=100"></TD> <TD><INPUT NAME=i+ TYPE=button VALUE="+" onClick="set_sign("+")"></TD> <TD><INPUT NAME=i- TYPE=button VALUE="-" onClick="set_sign("-")"></TD> </TR> </TABLE> <HR> <TABLE BORDER=0> <TR> <TD><INPUT NAME=op1 SIZE=2 MAXLENGTH=2></TD> <TD><INPUT NAME=s_sign SIZE=1 MAXLENGTH=1></TD> <TD><INPUT NAME=op2 SIZE=2 MAXLENGTH=2></TD> <TD>=</TD> <TD><INPUT NAME=result SIZE=3 MAXLENGTH=3></TD> <TD><INPUT NAME=award TYPE=button VALUE="?" onClick="main_calc()"> <TD><INPUT NAME=r0 VALUE="???"> </TR> </TABLE> <HR> <TABLE BORDER=2> <TR> <TD><INPUT NAME=b1 TYPE=button VALUE="1" onClick="input_sign("1")"></TD> <TD><INPUT NAME=b2 TYPE=button VALUE="2" onClick="input_sign("2")"></TD> <TD><INPUT NAME=b3 TYPE=button VALUE="3" onClick="input_sign("3")"></TD> </TR> <TR> <TD><INPUT NAME=b4 TYPE=button VALUE="4" onClick="input_sign("4")"></TD> <TD><INPUT NAME=b5 TYPE=button VALUE="5" onClick="input_sign("5")"></TD> <TD><INPUT NAME=b6 TYPE=button VALUE="6" onClick="input_sign("6")"></TD> </TR> <TR> <TD><INPUT NAME=b7 TYPE=button VALUE="7" onClick="nput_sign("7")"></TD> <TD><INPUT NAME=b8 TYPE=button VALUE="8" onClick="input_sign("8")"></TD> <TD><INPUT NAME=b9 TYPE=button VALUE="9" onClick="input_sign("9")"></TD> </TR> <TR> <TD><INPUT NAME=b0 TYPE=button VALUE="0" onClick="input_sign("0")"></TD> <TD COLSPAN=2><INPUT NAME=bs TYPE=button VALUE="OK" onClick="input_sign("10")"></TD> </TR> </TABLE> </FORM> </CENTER> <HR> </BODY> </HTML>
<HTML> <!- ady@demos.su, Saturday, January 20, 1996 7:23:31 PM-> <!- Demos WWW cover page -> <HEAD> <TITLE>Welcome to Demos Company - Moscow, Russia</TITLE> <!- yet another scroller. (C) 1996 Dmitry Altukhov, ady@demos.su -> <!- Use this code for whatever purposes... provided that you retain the copyright notice. I accept no responsibility for any disasters caused by this monster. Cannot guess any other cool places for scrollers. And MSIE marquee emulation in JS?! Er... Mozilla clears windows too slow in JS... -> <SCRIPT LANGUAGE="JavaScript"> <!- roll it var rate, pos=0; function roll(){ var loop, top, msg1; var msg="Hello World"; for(var i=0; i<10; i++){ msg = msg + (" Hello World"); } //move on, make a scrolly... and who said that //scrollers suck?! ;-) top=(130/msg.length)+1; for(loop=0; loop<top; loop++) msg+=""+msg; msg1=msg.substring (pos, pos+130); window.defaultStatus=msg1; if (pos++ == 130) pos=0; //come on, the poor thing can"t roll any faster... buy a Ferrari. ;-) rate=setTimeout("roll()",30); } // that"s all folks ;-) // end -> </SCRIPT> </HEAD> <BODY BACKGROUND="back.gif" BGCOLOR="#FFFFFF" TEXT="#000040" LINK="#000080" VLINK="#400080" ALINK="#FF0000" onLoad="roll()"> ..... </BODY> </HTML>
<HTML> <!- Author: Pavel Khramtsov Date: February 25, 1996 -> <HEAD> <TITLE>Text Block Scrolling</TITLE> <SCRIPT LANGUAGE="JavaScript"> var line_beak = "\n"; var screen = "" //123456789012345678901234567890 screen+= "Будем прокручивать" screen += "Данный фрагмент текста" screen += "В поле типа" screen += "TEXTAREA" screen += "Формы term" for(i=0;i<6;i++) screen += " " var i=0; var j=40; flag = 0 function scroll(){ if( flag== 0){ display_str = "" for(k=0;k<11;k++){ display_str += screen.substring(i,j) i+=40; j=i+40; if(i>400) i = 0 } window.document.term.work_field.value = display_str; i += 40; if(i>400) i =0 } id = setTimeout("scroll()",1000); return true } function change_button(){ if(flag==0){ flag = 1; return true } if(flag == 1){ flag = 0; return false } } </SCRIPT> </HEAD> <BODY onLoad="scroll()"> <CENTER> <H1>Text Block Scrolling.</H1> <HR> <FORM NAME=term> <TEXTAREA NAME=work_field COLS=40 ROWS=10 WRAP=ON></TEXTAREA> <P> <INPUT NAME=alarm VALUE="Start/Stop" TYPE=button onClick="change_button()"> </FORM> </CENTER> <HR> </BODY> </HTML>
<HTML> <HEAD> <TITLE> type_Document_Title_here </TITLE> <SCRIPT LANGUAGE="JavaScript"> <!- var i=0; adv_message = " " advert = "Russian Research Center \"Kurchatov Institute\"" adv_message += advert; adv_message += " " adv_length = advert.length function move_clock(){ // Clock day = new Date() clock_screen = day.getHours()+":" +day.getMinutes()+":"+day.getSeconds() document.kuku.f_clock.value = clock_screen // Rolling Field document.kuku.adv_string.value = adv_message.substring(i,i+45) document.kuku.i_field.value = i; i++ if( i == adv_length + 44 ) i = 0 id = setTimeout("move_clock()",100) } // end -> </SCRIPT> </HEAD> <BODY onLoad="move_clock()"> This is the start point:<BR> <a href="#next"> This the document start point.</a> kukuku <a name=next> <FORM NAME=kuku onSubmit="alert("You submit data to server")" METHOD="GET"> <INPUT TYPE=SUBMIT NAME=SABMIT VALUE=SUBMIT> Make a clock here: <INPUT NAME=f_clock maxlength=8 size=8> <P> <INPUT NAME=adv_string maxlength=45 size=45> <INPUT NAME=i_field size=10> </FORM> </BODY> </HTML>
<HTML> <!- Author: HTMLed User Date: May 16, 1996 -> <HEAD> <title>Iconize</title> <script language="JavaScript"> function make_icon(){ window.open("test_icon.htm","test_icon", "resizable=yes,scrollbars=no,width=50, height=70"); window.close() } </script> </HEAD> <BODY> <h1>minimize page</h1> <form name=icon> <input name=icon_button type=button value=icon onClick="make_icon()"> </fomr> </BODY> </HTML>
<HTML> <!- Author: Pavel Khramtsov Date: May 16, 1996 -> <HEAD> <script> function max_window(){ window.open("iconize.htm","new", "toolbar=yes,scrollbars=yes,directories=yes, status=yes,menubar=yes,resizable=yes, location=yes,width=700,height=500") window.close() } </script> </HEAD> <BODY> <center> <a href="" onClick="max_window()"> <imgsrc=back.jpg></a> </center> </BODY> </HTML>
<HTML> <HEAD> <TITLE>page terminator</TITLE> </HEAD> <BODY> <SCRIPT> window.close() </SCRIPT> </BODY> </HTML>
ComputerWorld #46/96