From: <fza...@us...> - 2005-11-29 23:08:40
|
Update of /cvsroot/struts/ajaxchat In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv21020 Added Files: index.jsp lobby.jsp room.jsp Log Message: --- NEW FILE: index.jsp --- <%@ taglib prefix="html" uri="http://jakarta.apache.org/struts/tags-html" %> <%@ taglib prefix="bean" uri="http://jakarta.apache.org/struts/tags-bean" %> <%@ taglib prefix="logic" uri="http://jakarta.apache.org/struts/tags-logic" %> <%@ taglib prefix="c" uri="http://java.sun.com/jstl/core" %> <%@ taglib prefix="fmt" uri="http://java.sun.com/jstl/fmt" %> <html> <head> <link rel="stylesheet" href="css/styles.css" type="text/css"> <title><fmt:message key="messages.appTitle" /></title> </head> <body class="cssMain" onLoad="LoginActionForm.username.focus();"> <div class="cssHeading"><fmt:message key="messages.appTitle" /></div> <hr/><br/> <fmt:message key="messages.welcomeBlock1" /> <br/><br/> <fmt:message key="messages.welcomeBlock2" /> <br/><br/> <logic:messagesPresent> <font color="#ff0000"> <html:messages id="error"> <bean:write name="error" /> </html:messages> </font> <br/><br/> </logic:messagesPresent> <html:form action="login"> <fmt:message key="labels.username" /> <html:text property="username" size="25" styleClass="cssUsernameInput" /> <html:submit styleClass="cssButton"> <fmt:message key="labels.loginButton" /> </html:submit> </html:form> </body> </html> --- NEW FILE: lobby.jsp --- <%@ taglib prefix="html" uri="http://jakarta.apache.org/struts/tags-html" %> <%@ taglib prefix="c" uri="http://java.sun.com/jstl/core" %> <%@ taglib prefix="fmt" uri="http://java.sun.com/jstl/fmt" %> <html> <head> <link rel="stylesheet" href="css/styles.css" type="text/css"> <title><fmt:message key="messages.appTitle" /></title> <script> /** * This is the XMLHttpRequest object that is used to service this page * to update the stats (how many users are chatting in each room. */ xhrLobbyUpdateStats = null; /** * This is the timer that fires to continually update the room stats. */ timerLobbyUpdateStats = null; /** * This is the delay between AJAX requests to update room stats. */ lobbyUpdateStatsDelay = 2000; /** * When the user clicks the logout button, we need to immediately stop * firing AJAX events because if the timing is just right, the session could * be invalidated before another stats update is requested, which results * in an exception. So, this gets set to false when the logout button is * clicked, which stops the next request from being made. Note that there * is still a very small chance for the exception to occur, but the timing * would have to be pretty darned close! */ sendAJAXRequest = true; /** * This funtion is called on page load to initialize things. */ function init() { timerLobbyUpdateStats = setTimeout("lobbyUpdateStats()", 0); } // End init(). /** * This function is called as a result of the firing of the * timerLobbbyUpdateStats timer to make an AJAX request to get counts of * users chatting in each room. This happens continually as the user * sits in the lobby. */ function lobbyUpdateStats() { // Only fire a new event if a previous one has completed, or if the // XMLHttpRequest object is in an uninitialized state, or one has not // yet been instantiated. if (xhrLobbyUpdateStats == null || xhrLobbyUpdateStats.readyState == 0 || xhrLobbyUpdateStats.readyState == 4) { try { if (window.XMLHttpRequest){ xhrLobbyUpdateStats = new XMLHttpRequest(); } else { xhrLobbyUpdateStats = new ActiveXObject('Microsoft.XMLHTTP'); } xhrLobbyUpdateStats.onreadystatechange = lobbyUpdateStatsHandler; target = "<html:rewrite action="ajaxLobbyUpdateStats" />"; if (sendAJAXRequest) { xhrLobbyUpdateStats.open("post", target, true); xhrLobbyUpdateStats.send(null); } } catch(e) { alert("Error in lobbyUpdateStats() - " + e.message); } } // Restart the timer no matter what happened above. timerLobbyUpdateStats = setTimeout("lobbyUpdateStats()", lobbyUpdateStatsDelay); } // End lobbyUpdateStats(). /** * This is the AJAX callback handler that updates the display. */ function lobbyUpdateStatsHandler() { if (xhrLobbyUpdateStats.readyState == 4) { if (xhrLobbyUpdateStats.status == 200) { // Get the returned XML and parse it, creating our HTML for display. newHTML = ""; msgDOM = xhrLobbyUpdateStats.responseXML; root = msgDOM.getElementsByTagName("rooms")[0]; rooms = root.getElementsByTagName("room"); for (i = 0; i < rooms.length; i++) { room = rooms[i]; roomName = room.getAttribute("name"); users = room.getAttribute("users"); url = "<a href=\"<c:url value="joinRoom.do?name=" />"; newHTML += url + escape(roomName) + "\">" + roomName + "</a>"; newHTML += " (" + users + ")<br/>"; } // Update the display. objRoomList = document.getElementById("roomList"); objRoomList.innerHTML = newHTML; } else { alert("Error in lobbyUpdateStatsHandler() - " + xhrLobbyUpdateStats.status); } } } // End lobbyUpdateStatsHandler(). </script> </head> <body class="cssMain" onLoad="init();"> <div class="cssHeading"><fmt:message key="messages.appTitle" /></div> <hr/><br/> <fmt:message key="messages.inTheLobby" /> <br/><br/> <div id="roomList"> <c:forEach var="roomName" items="${LobbyActionForm.rooms}"> <a href="<c:url value="joinRoom.do"> <c:param name="name" value="${roomName}" /></c:url>"> <c:out value="${roomName}" /> </a> <br/> </c:forEach> </div> <br/> <fmt:message key="messages.joinRoomInstructions" /> <br/><br/><br/> <input type="button" class="cssButton" onClick="sendAJAXRequest=false;window.location='<html:rewrite action="logout" />';" value="<fmt:message key="labels.logoutButton" />" /> </body> </html> --- NEW FILE: room.jsp --- <%@ taglib prefix="html" uri="http://jakarta.apache.org/struts/tags-html" %> <%@ taglib prefix="fmt" uri="http://java.sun.com/jstl/fmt" %> <%@ taglib prefix="c" uri="http://java.sun.com/jstl/core" %> <html> <head> <link rel="stylesheet" href="css/styles.css" type="text/css"> <title><fmt:message key="messages.appTitle" /></title> <script> /** * This is the size of the font in the chat scroll. It is adjustable * between 8 and 48 using the magnification icons. Note that affects both * your text and other users' text together. */ scrollChatFontSize = 12; /** * This variable stores the last HTML that was inserted into the userList * div. When we get the list of users in the room, we compare this value * to the new HTML we construct. If they are identical, we DO NOT update * the div. This is to alleviate flickering that happens in Firefox priod * to v1.5 (supposed to have been fixed in 1.5, I have not tested it). */ oldUserListHTML = ""; /** * These variables are references to the XMLHttpRequest objects we'll use * to service our continual AJAX events. */ xhrListUsersInRoom = null; xhrGetMessages = null; /** * These variables are references to the Javascript timers that fire our * continuous AJAX events. */ timerListUsersInRoom = null; timerGetMessages = null; /** * These variables define how many milliseconds will elapse before each * of the continuous AJAX requests fire. In other words, the list of users * timer will fire every second to send an AJAX request to update the list. * Note that this DOES NOT mean an AJAX request will be sent... if one is * already in progress, that iteration is effectively skipped. This means * that a sever network problem could cause a new event to never fire (hey, * that would make a good enhancement... for each skipped request, see how * long it's been since the last successful one, and if it's been more than * a few seconds, allow the new event to fire anyway). */ listUsersInRoomDelay = 2000; getMessagesDelay = 1000; /** * This function initializes everything. Basically this amounts to kicking * off the user list and chat history scroll retrieval timers so that we * have two AJAX events constantly firing, one get update the list of users * in the room, the other to update the list of messages posted to the room. */ function init() { // Start the timers that fires the AJAX event to update the list of // users in the room and the chat history scroll. timerListUsersInRoom = setTimeout("listUsersInRoom()", 0); timerGetMessages = setTimeout("getMessages()", 0); } // End init(). /** * This function sends the AJAX request to get the list of users currently * in the room. */ function listUsersInRoom() { // Only fire a new event if a previous one has completed, or if the // XMLHttpRequest object is in an uninitialized state, or one has not // yet been instantiated. if (xhrListUsersInRoom == null || xhrListUsersInRoom.readyState == 0 || xhrListUsersInRoom.readyState == 4) { try { if (window.XMLHttpRequest){ xhrListUsersInRoom = new XMLHttpRequest(); } else { xhrListUsersInRoom = new ActiveXObject('Microsoft.XMLHTTP'); } xhrListUsersInRoom.onreadystatechange = listUsersInRoomHandler; target = "<html:rewrite action="ajaxListUsersInRoom" />"; xhrListUsersInRoom.open("post", target, true); xhrListUsersInRoom.send(null); } catch(e) { alert("Error in listUsersInRoom() - " + e.message); } } // Restart the timer no matter what happened above. timerListUsersInRoom = setTimeout("listUsersInRoom()", listUsersInRoomDelay); } // End listUsersInRoom(). /** * This function handles state changes for the listUsersInRoom AJAX request. */ function listUsersInRoomHandler() { if (xhrListUsersInRoom.readyState == 4) { if (xhrListUsersInRoom.status == 200) { // Get the returned XML and parse it, creating our HTML for display. newHTML = ""; msgDOM = xhrListUsersInRoom.responseXML; root = msgDOM.getElementsByTagName("users")[0]; users = root.getElementsByTagName("user"); for (i = 0; i < users.length; i++) { newHTML += users[i].getAttribute("name") + "<br/>"; } // Update the display. if (oldUserListHTML != newHTML) { oldUserListHTML = newHTML; document.getElementById("userList").innerHTML = newHTML; } } else { alert("Error in listUsersInRoomHandler() - " + xhrListUsersInRoom.status); } } } // End listUsersInRoomHandler(). /** * This function sends the AJAX request to get the messages to be shown * in the history scroll. With each such request, we record the index that * was last requested (which will be set to the index of the highest * message we get back), so that each subsequent request effectively only * gets new messages. */ function getMessages() { // Only fire a new event if a previous one has completed, or if the // XMLHttpRequest object is in an uninitialized state, or one has not // yet been instantiated. if (xhrGetMessages == null || xhrGetMessages.readyState == 0 || xhrGetMessages.readyState == 4) { try { if (window.XMLHttpRequest){ xhrGetMessages = new XMLHttpRequest(); } else { xhrGetMessages = new ActiveXObject('Microsoft.XMLHTTP'); } xhrGetMessages.onreadystatechange = getMessagesHandler; target = "<html:rewrite action="ajaxGetMessages" />"; xhrGetMessages.open("post", target, true); xhrGetMessages.send(null); } catch(e) { alert("Error in getMessages() - " + e.message); } } // Restart the timer no matter what happened above. timerGetMessages = setTimeout("getMessages()", getMessagesDelay); } // End getMessages(). /** * This function handles state changes for the listUsersInRoom AJAX request. */ function getMessagesHandler() { if (xhrGetMessages.readyState == 4) { if (xhrGetMessages.status == 200) { // Get the returned XML and parse it, creating our HTML for display. newHTML = ""; msgDOM = xhrGetMessages.responseXML; root = msgDOM.getElementsByTagName("messages")[0]; messages = root.getElementsByTagName("message"); for (i = 0; i < messages.length; i++) { message = messages[i]; postedBy = message.getElementsByTagName("postedBy")[0].firstChild.nodeValue; postedDateTime = message.getElementsByTagName( "postedDateTime")[0].firstChild.nodeValue; msgText = message.getElementsByTagName( "msgText")[0].firstChild.nodeValue; txtColor = ""; if (postedBy == "<c:out value="${user.username}" />") { txtColor = document.getElementById("yourColor").value; } else { txtColor = document.getElementById("theirColor").value; } newHTML += "<font color=\"" + txtColor + "\">" + "[" + postedDateTime + "] " + postedBy + ": " + msgText + "</font><br/>"; } // Update the display. Note that the first time through we want to // completely overwrite what's there (just ), all other times // we want to add on to ehat's there. This is done to avoid the // borders collapsing and there being a minor visual glitch. objChatScroll = document.getElementById("chatScroll"); if (newHTML != "") { if (objChatScroll.innerHTML == " ") { objChatScroll.innerHTML = newHTML; } else { objChatScroll.innerHTML += newHTML; } } // Lastly, always scroll to the bottom objChatScroll.scrollTop = 1000000; } else { alert("Error in getMessagesHandler() - " + xhrGetMessages.status); } } } // End getMessagesHandler(). /** * This function is called to leave the room. */ function leaveRoom() { window.location = "<html:rewrite action="leaveRoom" />"; } // End leaveRoom(). /** * This function is called to clear the chat history scroll. */ function clearHistory() { document.getElementById("chatScroll").innerHTML = " "; } // End clearHistory(). /** * This function trims whitespace from both ends of a string. */ function fullTrim(inString) { return (inString.replace(/^\s*(.*\S|.*)\s*$/, '$1')); } // End fullTrim(). /** * This function is called to post a message to the room. Note that there * is no AJAX callback handler... since the message scroll will be updated * anyway, it's kind of redundant. It also means there will be potentially * a slight delay between a user submitting a message and it showing up, * but this is considered acceptable. */ function postMessage() { userInputText = document.getElementById("userInput"); if (fullTrim(userInputText.value) != "") { if (window.XMLHttpRequest){ xhrPostMessage = new XMLHttpRequest(); } else { xhrPostMessage = new ActiveXObject('Microsoft.XMLHTTP'); } try { target = "<html:rewrite action="ajaxPostMessage" />"; target += "?msgText=" + escape(userInputText.value); xhrPostMessage.open("post", target, true); xhrPostMessage.send(null); userInputText.value = ""; userInputText.focus(); } catch(e) { alert(e.message); } } } // End postMessage(). function increaseChatScrollFontSize() { cs = document.getElementById("chatScroll"); scrollChatFontSize = scrollChatFontSize + 2; if (scrollChatFontSize > 48) { scrollChatFontSize = 48; } cs.style.fontSize = scrollChatFontSize + "pt"; } function decreaseChatScrollFontSize() { cs = document.getElementById("chatScroll"); scrollChatFontSize = scrollChatFontSize - 2; if (scrollChatFontSize < 8) { scrollChatFontSize = 8; } cs.style.fontSize = scrollChatFontSize + "pt"; } </script> </head> <body onLoad="init();" class="cssMain"> <table align="center" border="1" bordercolor="#000000" width="100%" height="100%" cellpadding="4" cellspacing="0" class="cssRoomMainTable"> <!-- Header section --> <tr> <td colspan="2" class="cssRoomHeader" height="40"> <fmt:message key="messages.nowChattingIn" /> <c:out value="${roomName}" /> </td> </tr> <!-- Chat scroll section --> <tr> <td height="100%" valign="top"> <div id="chatScroll" class="cssRoomChatScroll" /> </td> <!-- User list section --> <td rowspan="3" width="200" align="top"> <div id="userList" class="cssRoomUserList" /> </td> </tr> <!-- User control section --> <tr> <td height="60" valign="middle" id="userControl" class="cssRoomUserControl"> <!-- Leave room button --> <input type="button" value="<fmt:message key="labels.leaveRoomButton" />" class="cssButton" onClick="leaveRoom();" /> <!-- Clear history button --> <input type="button" value="<fmt:message key="labels.clearHistoryButton" />" class="cssButton" onClick="clearHistory();" /> <!-- Increase/Decrease font size --> <fmt:message key="labels.fontSize" /> <img src="img/zoomUp.gif" align="absmiddle" alt="<fmt:message key="labels.increaseFontSize" />" onClick="increaseChatScrollFontSize();" onMouseOver="this.style.cursor='hand';" onMouseOut="this.style.cursor='';"> <img src="img/zoomDown.gif" align="absmiddle" alt="<fmt:message key="labels.decreaseFontSize" />" onClick="decreaseChatScrollFontSize()"; onMouseOver="this.style.cursor='hand';" onMouseOut="this.style.cursor='';"> <br/> <!-- Your color --> <fmt:message key="labels.yourColor" /> <select class="cssSelect" id="yourColor"> <%@ include file="/inc/color_options.inc" %> </select> <!-- Their color --> <fmt:message key="labels.theirColor" /> <select class="cssSelect" id="theirColor"> <%@ include file="/inc/color_options.inc" %> </select> </td> </tr> <!-- User input section --> <tr> <td height="70" valign="middle" class="cssRoomUserInput"> <textarea class="cssUserInput" id="userInput" onKeyUp="if(event.keyCode==13){postMessage();}"></textarea> <input type="button" class="cssButton" value="<fmt:message key="labels.sendButton" />" onClick="postMessage();" /> </td> </tr> </table> </body> </html> |