<% ASP на блюдечке %>. Часть 12
Просмотр списка сообщений чата (файл Text.asp)
Теперь нам нужно разработать страничку, содержащую все пользовательские сообщения. Она, по сути, должна отображать содержимое соответствующей таблицы нашей базы данных (таблицы Chat). Страничка должна самообновляться каждые Session("RefreshTime") секунд:
<!--#include file="utils.asp"--> <html> <% Response. Write "<META http-equiv='refresh' content='" & CInt(Session("RefreshTime")) & "'>" %> <head> <meta http-equiv="Content-Type" content="text/html; charset=windows-1251"> </head> <body bgcolor="#D7D5C0" text="#000000" link="#000000" vlink="#FFFFFF" alink="#FFFFFF"> <% Dim MaxLines, Str MaxLines = CInt(Session("LNum")) Call Connect sSQL = "SELECT TOP " & CStr (MaxLines) & " * FROM Chat Order By DateSaid DESC" Rs.open sSQL, Conn Do While Not Rs.Eof Str = Rs.Fields("Said").value Response.Write Str Rs.MoveNext Loop Response.Write "<br>" Call Close %> </body> </html>
Посылка сообщения в чат (файл Chat.asp)
Теперь нам потребуется страничка посылки сообщений в чат. Для этого понадобится HTML-форма с текстовым полем ввода сообщения, парой кнопок и «радиопереключателем» смайликов к сообщениям. Последние лежат в каталоге Images к исходникам настоящей статьи. После нажатия пользователем на кнопку «Сказать» необходимое сообщение, обрамленное соответствующими тэгами (цвет, смайлик) попадет в базу данных.
<!--#include file="utils.asp"--> <SCRIPT LANGUAGE = VBScript RUNAT=Server> <!-- Metadata type="typelib" File="c:\program files\common files\system\ado\msado15.dll" --> </SCRIPT> <% Dim TextStr, ImageFileName Session.TimeOut = 1 If Session("UserName") <> "" Then Response.Write "Пользователь: " & Session("UserName") & "<br>" Else Response.Write "Вы покинули чат. <br>" End If If Request("go") = "Войти" Then Response.Redirect("Entrance.asp") End If If Request("exit") = "Выйти" Then TextStr = "<table><tr><td><b><font color='" & Session("UserColor") &_ "'>" & Session("UserName") & "</font></B> : " &_ "покинул чат - " & date & " " & time & "</td></tr></table>" Call Connect() sSQL = "SELECT * FROM Chat" RS.Open sSQL, Conn, 3, adLockOptimistic rs.AddNew rs("UserID") = 0 rs("DateSaid") = Now() rs("Said") = TextStr rs.Update Call Close() Call Connect() sSQL = "UPDATE ChatUsers Set IsOnLine = 0 WHERE UserID = " & Session("UserID") Conn.Execute(sSQL) Conn.close set Conn = nothing Session("UserName") = "" Session("UserID") = 0 End If %> <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=windows-1251"> </head> <script> function ReEnter() { window.navigate("Entrance.asp"); } </script> <body bgcolor="#D7D5C0" text="#000000" link="#000000" vlink="#FFFFFF" alink="#FFFFFF"> <% TextStr = Trim (Request.Form("txtbox")) If InStr(TextStr, "<") < 1 Then If TextStr <> "" Then Select Case CInt(Request.Form("MsgIcon")) Case 0 'Smile ImageFileName = "" Case 7 'Smile ImageFileName = "Images\icon7.gif" Case 2 'Smile ImageFileName = "Images\icon2.gif" Case 3 'Smile ImageFileName = "Images\icon3.gif" Case 4 'Smile ImageFileName = "Images\icon4.gif" Case 5 'Smile ImageFileName = "Images\icon5.gif" Case 6 'Smile ImageFileName = "Images\icon6.gif" Case 8 'Smile ImageFileName = "Images\icon8.gif" Case 9 'Smile ImageFileName = "Images\icon9.gif" Case 10 'Smile ImageFileName = "Images\icon10.gif" Case 11 'Smile ImageFileName = "Images\icon11.gif" Case 12 'Smile ImageFileName = "Images\icon12.gif" Case 13 'Smile ImageFileName = "Images\icon13.gif" Case 14 'Smile ImageFileName = "Images\icon14.gif" End Select TextStr = Replace(TextStr, vbCrLf, "<br>") If (ImageFileName <> "") Then TextStr = "<table><tr><td width=15 valign='top'><img src = '" & _ ImageFileName & "'></td>" &_ "<td width=70 valign='top'><B><font color = '" & Session("UserColor") &_ "'>" & Session("UserName") & "</td><td>" &_ "</font></B>" & " : " & TextStr & "</td></tr></table>" Else TextStr = "<table><tr><td width=15 valign='top'></td>" &_ "<td width=70 valign='top'><B><font color = '" & Session("UserColor") &_ "'>" & Session("UserName") & "</td><td>" &_ "</font></B>" & " : " & TextStr & "</td></tr></table>" End If Call Connect() sSQL = "SELECT * FROM Chat" RS.Open sSQL, Conn, 3, adLockOptimistic rs.AddNew rs("UserID") = Session("UserID") rs("DateSaid") = Now() rs("Said") = TextStr rs.Update Call Close() Application("IsRefresh") = True End If End If %> <FORM name= "ChatForm" method="post" action="chat.asp"> <table> <tr> <td valign="top" align="right"> <INPUT type="radio" name="MsgIcon" value="0" CHECKED>нет <INPUT type="radio" name="MsgIcon" value="10"><IMG SRC="Images/icon10.gif" alt="улыбка" HEIGHT=15 WIDTH=15 ALIGN=ABSCENTER> <INPUT type="radio" name="MsgIcon" value="11"><IMG SRC="Images/icon11.gif" alt="возмущение" HEIGHT=15 WIDTH=15 ALIGN=ABSCENTER> <INPUT type="radio" name="MsgIcon" value="12"><IMG SRC="Images/icon12.gif" alt="подмигивание" HEIGHT=15 WIDTH=15 ALIGN=ABSCENTER> <INPUT type="radio" name="MsgIcon" value="13"><IMG SRC="Images/icon13.gif" alt="плохо" HEIGHT=15 WIDTH=15 ALIGN=ABSCENTER> <INPUT type="radio" name="MsgIcon" value="14"><IMG SRC="Images/icon14.gif" alt="хорошо" HEIGHT=15 WIDTH=15 ALIGN=ABSCENTER> <INPUT type="radio" name="MsgIcon" value="2" ><IMG SRC="Images/icon2.gif" alt="поговорим" HEIGHT=15 WIDTH=15 ALIGN=ABSCENTER> <BR> <INPUT type="radio" name="MsgIcon" value="3" ><IMG SRC="Images/icon3.gif" alt="лампочка" HEIGHT=15 WIDTH=15 ALIGN=ABSCENTER> <INPUT type="radio" name="MsgIcon" value="4" ><IMG SRC="Images/icon4.gif" alt="внимание" HEIGHT=15 WIDTH=15 ALIGN=ABSCENTER> <INPUT type="radio" name="MsgIcon" value="5" ><IMG SRC="Images/icon5.gif" alt="вопрос" HEIGHT=15 WIDTH=15 ALIGN=ABSCENTER> <INPUT type="radio" name="MsgIcon" value="6" ><IMG SRC="Images/icon6.gif" alt="радость" HEIGHT=15 WIDTH=15 ALIGN=ABSCENTER> <INPUT type="radio" name="MsgIcon" value="7" ><IMG SRC="Images/icon7.gif" alt="одобрение" HEIGHT=15 WIDTH=15 ALIGN=ABSCENTER> <INPUT type="radio" name="MsgIcon" value="8" ><IMG SRC="Images/icon8.gif" alt="раздражение" HEIGHT=15 WIDTH=15 ALIGN=ABSCENTER> <INPUT type="radio" name="MsgIcon" value="9" ><IMG SRC="Images/icon9.gif" alt="грусть" HEIGHT=15 WIDTH=15 ALIGN=ABSCENTER> <BR> </td> <td> <textarea cols="56" rows="5" style="font: 8pt 'Verdana'; background-color: #FCFBE8;" value="" name="txtbox"></textarea> </td> <td valign="top"> <table><tr><td> <% If Session("UserName") <> "" Then %> <Input type = Submit Style="font: 8pt 'Verdana'; Width: 65" value="Сказать" name="go"> </td></tr> <tr><td> <Input type = Submit Style="font: 8pt 'Verdana'; Width: 65" value="Шепнуть" name="whisper"> </td></tr> <tr><td> <Input type = Submit Style="font: 8pt 'Verdana'; Width: 65" value="Выйти" name="exit"> </form> <% Else %> </form> <form method="post" action="chat.asp" target="_top"> <Input type = Submit Style="font: 8pt 'Verdana'; Width: 55" value="Войти" name="go" Onclick="ReEnter()";> </form> <% End If %> </td></tr></table> </td> </tr> </table> </body> </html>
Как видите, все довольно просто; в результате у нас получился инструмент ввода сообщений в чат. Нам осталось только разработать страничку, аналогичную Text.asp, но показывающую не текстовые сообщения, а список псевдонимов (кто в чате), и упорядочить все страницы проекта с помощью фреймов.
Показ псевдонимов (кто в чате) — файл Nicks.asp
Все делается аналогично страничке Text.asp: самообновление страницы, показ списка пользователей. Здесь нет ничего сложного, и нам необходимо просто извлечь из таблицы пользователей список имен-псевдонимов тех, кто в чате, и показать его:
<!--#include file="utils.asp"--> <html> <% Response. Write "<META http-equiv='refresh' content='" & CInt(Session("RefreshTime")) & "'>" %> <head> <meta http-equiv="Content-Type" content="text/html; charset=windows-1251"> </head> <body bgcolor="#D7D5C0" text="#000000" link="#000000" vlink="#FFFFFF" alink="#FFFFFF"> <p><b>Сейчас в чате:</b></p> <% Dim CurUser, Odd, Str, Who, Umail CurUser = 0 Odd = 0 Call Connect sSQL = "SELECT * FROM ChatUsers WHERE IsOnline = 1" Response.Write "<table>" Rs.open sSQL, Conn Do While Not rs.EOF If Odd = 0 Then If Rs.Fields("UserNickName").value <> "" Then Who = Rs.Fields("UserName").value UMail = Rs.Fields("UserMail").value Str = "<tr><td><font color=" & Session("UserColor") & ">[" Str = Str & "<A HREF='mailto:" & UMail & "'>" Str = Str & "<font color=" & Session("UserColor") & ">" & Rs.Fields("UserNickName").value & "</font>" Str = Str & "</a>]</font></td></tr>" Response.Write Str Odd = 1 CurUser = CurUser + 1 End If Else Odd = 0 Rs.MoveNext End If Loop Response.Write "</table>" If CurUser = 0 Then Response.Write "<p>нет пользователей</p>" Else Response.Write "<p>Всего " & CurUser & "</p>" End If Call Close %> </body> </html>
Немного об оформлении
Теперь нам надлежит оформить одну страницу из трех (Chat.asp, Nicks.asp и Text.asp) с помощью фреймов. Для начала создадим вертикальный фрейм:
<%@ LANGUAGE = VBScript%> <% If Session("UserName") = "" Then Response.Redirect("Entrance.asp") End If %> <HTML> <head> <meta http-equiv="Content-Type" content="text/html; charset=windows-1251"> <TITLE> Чат</TITLE> </head> <Frameset frameborder="NO" border="0" framespacing="0" rows="80%, 19%, 1%"> <frame name="textFrame" src="RightFS.asp"> <frame name="chatFrame" src="chat.asp"> <frame name="FalseFrame" src="FF.asp"> </Frameset> </HTML>
затем представим горизонтальный фрейм следующим образом:
<html> <head> <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1"> </head> <frameset cols="85%,15%" frameborder="YES" border="1" framespacing="0"> <frame name="mainFrame" src="text.asp"> <frame name="rightFrame" src="Nicks.asp"> </frameset> <noframes> <body bgcolor="#FFFFFF" text="#000000"> </body> </noframes> </html>
И еще об одной немаловажной проблеме…
Если помните, в предыдущей версии чата (в его файл-основанной версии) задача перевода пользователя в режим офлайн не была решена. Точнее, была предпринята попытка ее решения с использованием соответствующей функции файла global.asa. Теперь мы будем делать это гарантированно, ведь пользователь может покинуть чат, не нажав кнпоку выхода (в этом случае система получает сигнал о том, что необходимо выставить соответствующее значение флажка режима пользователя). В случае же непредсказуемого выхода (переход по другому адресу или закрытие окна браузера) таким сигналом может служить лишь сообщение, получаемое при наступлении соответствующего события непосредственно в браузере. Для этой цели в тэг <body> html-документа можно вставить следующий код:
<body onunload="open('term.asp');self.close()">
который, как вы видите, во-первых, инициализует выполнение функций выхода в модуле “term.asp”, а во-вторых — приводит к закрытию окна, породившего само событие (директива self.close()).
Однако в нашем случае ситуация несколько усложняется наличием фреймов. Поэтому, как вы, наверное, заметили, при оформлении набора фреймов умышленно был создан скрытый фрейм «FalseFrame», который специально предназначен для решения этой проблемы и исходный текст модуля которого выглядит следующим образом:
<html> <head> <meta http-equiv="Content-Type" content="text/html; charset=windows-1251"> </head> <script Language="JavaScript"> var timerID = null; var timerRunning = false; function stopclock () { if (timerRunning) clearTimeout(timerID); timerRunning = false; } function showtime () { var now = new Date(); var hours = now.getHours(); var minutes = now.getMinutes(); var seconds = now.getSeconds() var timeValue = "" + ((hours >12) ? hours -12 :hours) timeValue += ((minutes < 10) ? ":0" : ":") + minutes timeValue += ((seconds < 10) ? ":0" : ":") + seconds timeValue += (hours >= 12) ? " дня" : " утра" window.status = "Время на сервере: " + timeValue; timerID = setTimeout("showtime()",1000); timerRunning = true; } function startclock () { stopclock(); showtime(); } </script> <body onLoad="startclock()" onunload="open('term.asp');self.close()" bgcolor="#D7D5C0" text="#000000" link="#000000" vlink="#FFFFFF" alink="#FFFFFF"> </body> </html>
Как видите, модуль, помимо последних строк, решающих проблему «самозакрытия» и переадресации функции завершения сеанса работы определенного пользователя, содержит еще и код, отображающий серверное время в статусной строке (строке состояния) окна браузера.
Завершение сеанса работы при выходе пользователя (файл term.asp)
Теперь нам осталось разобраться с действиями, которые должен выполнять пользователь, покидая чат-систему, если он не воспользовался кнопкой выхода:
<!--#include file="utils.asp"--> <SCRIPT LANGUAGE = VBScript RUNAT=Server> <!-- Metadata type="typelib" File="c:\program files\common files\system\ado\msado15.dll" --> </SCRIPT> <html> <body onLoad = "self.close()"> <% Dim TextStr TextStr = "<table><tr><td><b><font color='" & Session("UserColor") &_ "'>" & Session("UserName") & "</font></B> : " &_ "вышел из чата - " & date & " " & time & "</td></tr></table>" Call Connect() sSQL = "SELECT * FROM Chat" RS.Open sSQL, Conn, 3, adLockOptimistic rs.AddNew rs("UserID") = 0 rs("DateSaid") = Now() rs("Said") = TextStr rs.Update Call Close() Call Connect() sSQL = "UPDATE ChatUsers Set IsOnLine = 0 WHERE UserID = " & _ Session("UserID") Conn.Execute(sSQL) Conn.close set Conn = nothing %> </body> </html>
Заключение
В заключение хотелось бы остановиться на сильных и слабых сторонах рассмотренной нами чат-системы. Прежде всего очевидное достоинство базо-основанной системы заключается в производительности по сравнению с файл-основанным аналогом. Данный пример, хоть и намеренно создан с целью обучения, тем не менее вполне может служить «двигателем» для реального, активно посещаемого чата. Недостаток здесь, пожалуй, кроется в некотором усложнении программного подхода, увеличении числа выполняемых действий, усложнении структуры Web-приложения, тем не менее, как вы видите теперь, задача довольно проста и все эти сложности скорее кажущиеся, чем реальные.
С автором статьи можно связаться по следующему адресу: rouben@iname.com
КомпьютерПресс 8'2001