Теперь нам нужно разработать страничку, содержащую все пользовательские сообщения. Она, по сути, должна отображать содержимое соответствующей таблицы нашей базы данных (таблицы 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>
Теперь нам потребуется страничка посылки сообщений в чат. Для этого понадобится 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, но показывающую не текстовые сообщения, а список псевдонимов (кто в чате), и упорядочить все страницы проекта с помощью фреймов.
Все делается аналогично страничке 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