| By James Benson, Jay Fienberg | Article Rating: |
|
| May 12, 2007 11:00 AM EDT | Reads: |
4,505 |
This content is reprinted from Real-World AJAX: Secrets of the Masters published by SYS-CON Books. To order the entire book now along with companion DVDs for the special pre-order price, click here for more information. Aimed at everyone from enterprise developers to self-taught scripters, Real-World AJAX: Secrets of the Masters is the perfect book for anyone who wants to start developing AJAX applications.
The Basic HTML Structure
First, we create a simple structure in HTML that represents the major elements of our user interface:
- A zone for a heading
- A zone for a login control
- A zone to logout control
- A zone for a buddy list
- -8. Four zones for chat windows
- A zone for debug/info/error log messages
Listing 12.1
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
<head>
<meta http-equiv="content-type" content="text/html; charset=utf-8" />
<title>AJAX IM Chat client for Real World AJAX</title>
</head>
<body>
<h1>An Example AJAX IM Client</h1>
<div id="login"></div>
<div id="logout"></div>
<div id="buddy"></div>
<div id="chat1"></div>
<div id="chat2"></div>
<div id="chat3"></div>
<div id="chat4"></div>
<div id="log"></div>
</body>
</html>
We are saving this in a file called im.html. Note that, at this point, each element is simply an HTML DIV with a unique ID.
With this structure, we've fixed the scope of our design so that it supports only four simultaneous chat windows. We felt that this would be an easy way to create an interface where we can experiment with simultaneous chats, and, at the end of this chapter, we'll suggest how the chat windows can be made more dynamic and support "unlimited" simultaneous chats.
Next, we'll add some HTML header elements to reference the external CSS and JavaScript files we'll be creating, and to reference the Prototype JavaScript library, which we'll also be using.
We also add a few HTML class attributes and place the main elements inside a "wrapper" DIV to give us more options for styling in CSS.
Our goal at this point is to be able to visually see the interface. Listing 12.2 provides the HTML.
Listing 12.2
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
<head>
<meta http-equiv="content-type" content="text/html; charset=utf-8" />
<title>AJAX IM Chat client for Real World AJAX</title>
<link rel="stylesheet" type="text/css" href="im.css" />
<script src="prototype.js" type="text/javascript"></script>
<script src="im.js" type="text/javascript"></script>
</head>
<body>
<h1>An Example AJAX IM Client</h1>
<div id="wrap" class="outlined">
<div id="login"></div>
<div id="logout"></div>
<div id="buddy" class="outlined"></div>
<div id="chat1" class="chatwindow outlined"></div>
<div id="chat2" class="chatwindow outlined"></div>
<div id="chat3" class="chatwindow outlined"></div>
<div id="chat4" class="chatwindow outlined"></div>
<div id="log" class="outlined"></div>
</div>
</body>
</html>
(Note: from this point forward, we'll show examples of the new HTML as it fits into this structure.)
The Basic CSS and Visualizing the Client
Here is our the basic CSS (saved in im.css, in the same directory as im.html) that lets us see the interface:
Listing 12.3
body {
margin: 20px;
font-family: verdana, arial, helvetica, sans-serif;
font-size: 76%;
text-align: center;
}
/* structural page elements */
#wrap {
background: #ddd;
width: 810px;
margin-left: auto;
margin-right: auto;
text-align: left;
}
/* textual and general block element styling */
h1 {
font-size: 1.5em;
text-align: center;
width: 100%;
margin-bottom: 1px;
}
.outlined {
border: 1px solid #333;
}
/* Login / Logout elements */
#login, #logout {
text-align: center;
width: 100%;
margin-top: 0px;
}
/* Buddy List elements */
#buddy {
float: left;
width: 150px;
margin: 15px;
background: #fff;
padding-bottom: 25px;
}
/* Chat window elements */
.chatwindow {
float: left;
width: 280px;
height: 250px;
margin: 15px;
background: #fff;
}
/* Log window elements */
#log {
clear: left;
width: 775px;
margin: 15px;
height: 123px;
background: #fff;
}
We now have our zones blocked out. Since, we're using the CSS float property to set the relationships between our "windows," things look a little askew at this point. But, when we have buddies in the Buddy zone, it should straighten everything out.
Next, we'll fill in each of the strucutral elements with the controls we need to make the interface interactive.
HTML Controls 1: My Buddies and My Status
The "buddy list" on an IM client lists the user's buddies and their respective online statuses. Our buddy list will be totally populated and updated via AJAX, so we'll just include a container DIV (with id="buddylist") in our HTML.
Below the buddy list, we'll also include a drop-down select control where users can set their own status. To keep things simple, we'll include three possible statuses: Available, Away, and Offline.
Note too that, as a visual element of the design, we've included a heading "My Buddies". We'll style this in the CSS to look like a header bar, and we'll reuse this style across all of our "windows."
Finally, notice how we're not adding HTML "on" event attributes to trigger JavaScript events, e.g., we don't have an onchage="dosomething()" on the <select id="status">. This is an important way for us, as much as possible, to keep a clean separation between the structural elements of the HTML and the functional elements of the JavaScript.
At this stage, we don't need to worry much about the JavaScript. Later in the chapter, we'll cover in detail how we use the handy Event.observe feature of the Prototype library to dynamically add event listeners.
Listing 12.4
<div id="buddy" class="outlined">
<div class="heading">My Buddies</div>
<div id="buddylist"></div>
<div id="mystatus">
<p>My Status:</p>
<select id="status">
<option class="optavailable">Available</option>
<option class="optaway">Away</option>
<option class="optoffline">Offline</option>
</select>
</div>
</div>
AJAX/dynamic features to note in Listing 12.4
- <div id="buddylist"> has nothing in it and will need to be populated via AJAX.
- An event listener will need to be added to <select id="status"> to catch changes in status via this control.
- Changes to <select id="status"> will need to update the server via AJAX
HTML Controls 2: Chat Windows
The chat windows allow the users to type messages to each other and to see each other's messages. We'll again add a heading, but let's plan for the heading to dynamically update with the name of the buddy with whom the user is chatting. We'll also add a way to "close" the window - in this case, a [X].
As with the buddy list, we'll include a DIV (with id="chatmsg1") for the actual messages that will be filled in via AJAX. And, finally, we'll include a text input and a send link (which we'll style in CSS to look like a button).
Note that all of the HTML ID attributes end with the number 1. We'll duplicate this code for each chat window, with each having a different number, e.g., chat window 2 will have each identifier end in the number 2, etc.
Listing 12.5
<div id="chat1" class="chatwindow outlined">
<div class="heading">Chat 1: <span id="chatinfo1"></span> <a id="close1">[X]</a>
</div>
<div id="chatmsg1" class="msgs"></div>
<input type="text" id="chatin1" /><a id="chatsend1">Send</a>
</div>
AJAX/dynamic features to note in Listing 12.5
- <span id="chatinfo1"> has nothing in it and will need to be updated via AJAX with the name of the buddy with whom the user is chatting.
- An event listener will need to be added to <a id="close1"> to catch the click that will close the window.
- <div id="chatmsg1" class="msgs"> has nothing in it and will need to be updated via AJAX with the messages between the user and the buddy with whom the user is chatting.
- An event listener will need to be added to <input type="text" id="chatin1" /> to catch the key press of the RETURN button that will indicate a new message is ready to be sent to the server via AJAX.
- An event listener will need to be added to <input type="text" id="chatin1" /> to catch focus and blur to change the highlight color (to help the user know that where it's okay to type).
- An event listener will need to be added to <a id="chatsend1"> to catch the click that will indicate a new message is ready to be sent to the server via AJAX.
We decided to include a debug log window to which our JavaScript code can output messages to help us with debugging and monitoring the client interactions. This window will again have a DIV element (with id="logmsgs") that is left empty here so that it can be filled and updated via AJAX.
We'll also include three radio buttons for adjusting the level of log messages. We'll have our log code categorize each message as either a debug message, an info message, or an error message. By default, we'll show info level messages (by setting checked="checked" on the log1 input), but the radio buttons allow the user to select a different level.
Listing 12.6
<div id="log" class="outlined">
<div class="heading">AJAX Log - <span> Level: <input type="radio" name="loglevel"
value="0" id="log0" /><label for="log0"> Debug</label> <input type="radio"
name="loglevel" value="1" id="log1" checked="checked" /><label for="log1"> Info</label>
<input type="radio" name="loglevel" value="2" id="log2" /><label for="log2"> Error</label>
</span></div>
<div id="logmsgs"></div>
</div>
AJAX / dynamic features to note in Listing 12.6
- <div id="logmsgs"> has nothing in it and will need to be updated via JavaScript with the log messages.
- An event listener will need to be added to each radio button (log0, log1, and log2) to catch the click event and set the corresponding filter on our log outputter.
As indicated above in our design strategy, we wanted to minimize any user management functionality in this application. In considering different login/user management options, we came up with the idea that our IM system has only five users (which always works out with a user having, at most, four chat windows open - one of the constraints in our current design).
Most IM systems allow individuals to add or remove buddies from their buddy list. We decided to implement a different scenario where each user automatically has every other user as a buddy ( in our case, user 1 automatically gets users 2-5 as buddies).
This could actually be usable in at least one production setting: a workgroup where, as common, everyone in the group is each others' buddy.
For our login control, we decided to implement the super simple mechanism of a drop-down that lists all the people in the system. The user picks who he or she is, and then can see everyone else as a buddy.
To look nice on the screen and make the interaction clear, we also won't show the logout control unless the user is logged in, and we won't show the login control unless the user is logged out.
Besides this dynamic switching between the login/logout controls, we'll also populate our user list from the server via AJAX. IM systems manage users on the server side, and this also allows the "system admin" to add new users to the system without having to update every client (which, because our client is HTML/JavaScript coming from the server, is actually little different - but, in principle, we're keeping a server feature in the server code rather than embedding it in the client).
Listing 12.7
<div id="login">« <span id="loginmsg">Log in:</span> <select id="user"></select>
»</div>
<div id="logout">« Logged in as: <span id="loginuser"></span>.
<a id="logoutlink">Logout</a> »</div>
AJAX/dynamic features to note in Listing 12. 7
- <select id="user"> has nothing in it and will need to be updated via AJAX with an option for each person in the system.
- An event listener will need to be added to <select id="user"> to catch the select event that will log the user in via AJAX.
- Upon login, the <div id="login"> will be hidden, and the <div id="logout"> will be shown.
- An event listener will need to be added to <a id="logoutlink"> to catch the click event will log the user out via AJAX.
- Upon login, the <div id="logout"> will be hidden, and the <div id="login"> will be shown.
What follows are listings of the complete HTML and CSS code. It's outside of the scope of this book to go through all of the CSS, but note that a number of our dynamic interactions involve showing and hiding elements on the page. Any elements that intially are not shown are given a display: none rule in the CSS.
Listing 12.8
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
<head>
<meta http-equiv="content-type" content="text/html; charset=utf-8" />
<title>AJAX IM Chat client for Real World AJAX</title>
<link rel="stylesheet" type="text/css" href="im.css" />
<script src="prototype.js" type="text/javascript"></script>
<script src="im.js" type="text/javascript"></script>
</head>
<body>
<div id="wrap" class="outlined">
<h1>An Example AJAX IM Client</h1>
<div id="login">« <span id="loginmsg">Log in:</span> <select id="user"></select>
»</div>
<div id="logout">« Logged in as: <span id="loginuser"></span>. <a
id="logoutlink">Logout</a> »</div>
<div id="buddy" class="outlined">
<div class="heading">My Buddies</div>
<div id="buddylist"></div>
<div id="mystatus">
<p>My Status:</p>
<select id="status">
<option class="optavailable">Available</option>
<option class="optaway">Away</option>
<option class="optoffline">Offline</option>
</select>
</div>
</div>
<div id="chat1" class="chatwindow outlined">
<div class="heading">Chat 1: <span id="chatinfo1"></span> <a id="close1">[X]</a></
div>
<div id="chatmsg1" class="msgs"></div>
<input type="text" id="chatin1" /><a id="chatsend1">Send</a>
</div>
<div id="chat2" class="chatwindow outlined">
<div class="heading">Chat 2: <span id="chatinfo2"></span> <a id="close2">[X]</a></
div>
<div id="chatmsg2" class="msgs"></div>
<input type="text" id="chatin2" /><a id="chatsend2">Send</a>
</div>
<div id="chat3" class="chatwindow outlined">
<div class="heading">Chat 3: <span id="chatinfo3"></span> <a id="close3">[X]</a></
div>
<div id="chatmsg3" class="msgs"></div>
<input type="text" id="chatin3" /><a id="chatsend3">Send</a>
</div>
<div id="chat4" class="chatwindow outlined">
<div class="heading">Chat 4: <span id="chatinfo4"></span> <a id="close4">[X]</a></
div>
<div id="chatmsg4" class="msgs"></div>
<input type="text" id="chatin4" /><a id="chatsend4">Send</a>
</div>
<div id="log" class="outlined">
<div class="heading">AJAX Log - <span> Level: <input type="radio" name="loglevel"
value="0" id="log0" /><label for="log0"> Debug</label> <input type="radio"
name="loglevel" value="1" id="log1" checked="checked" /><label for="log1"> Info</label>
<input type="radio" name="loglevel" value="2" id="log2" /><label for="log2"> Error</label></
div>
<div id="logmsgs"></div>
</div>
</div>
</body>
</html>
Listing 12.9
body {
margin: 20px;
font-family: verdana, arial, helvetica, sans-serif;
font-size: 76%;
text-align: center;
}
/* structural page elements */
#wrap {
background: #ddd;
width: 810px;
margin-left: auto;
margin-right: auto;
text-align: left;
}
/* textual and general block element styling */
h1 {
font-size: 1.5em;
text-align: center;
width: 100%;
margin-bottom: 1px;
}
.heading {
padding: 3px;
height: 17px;
background: #003;
color: #fff;
font-weight: bold;
}
.heading span {
font-weight: normal;
}
.outlined {
border: 1px solid #333;
}
/* Login / Logout elements */
#login, #logout {
text-align: center;
width: 100%;
margin-top: 0px;
}
#logout {
display: none;
}
#logout a {
width: 40px;
text-align: center;
text-decoration: none;
padding: 2px;
color: #000;
background: #cfc;
border: 1px dotted #0f0;
}
#logout a:hover {
background: #8f8;
}
/* Buddy List elements */
#buddy {
display: none;
float: left;
width: 150px;
margin: 15px;
background: #fff;
padding-bottom: 25px;
}
#buddy .budlisting {
height: 1.5em;
font-size: 1.3em;
text-align: right;
margin-right: 20px;
margin-left: 10px;
border-bottom: 1px dotted #f33;
cursor:pointer;
cursor:hand;
}
#buddy .budlisting:hover {
background: #dd0;
}
.budlisting p {
text-align: left;
}
.offline, .available, .away {
float: left;
width: 17px;
height: 17px;
margin-right: 10px;
border: 1px solid #000;
}
.offline {
background: #666;
}
.available {
background: #0f0;
}
.away {
background: #cc0;
}
#mystatus {
margin-top: 10px;
}
#mystatus p {
text-align: center;
margin-bottom: 0px;
font-variant: small-caps;
}
#mystatus select {
margin-top: 5px;
margin-left: 10px;
width: 80%;
font-variant: small-caps;
font-weight: bold;
text-align: center;
}
#mystatus option {
margin-top: 2px;
margin-bottom: 3px;
font-variant: small-caps;
font-weight: bold;
text-align: center;
}
.optoffline {
color: #666;
}
.optavailable {
color: #0f0;
}
.optaway {
color: #cc0;
}
/* Chat window elements */
.chatwindow {
display: none;
float: left;
width: 280px;
height: 250px;
margin: 15px;
background: #fff;
}
.chatwindow input {
float: left;
width: 200px;
margin-left: 10px;
margin-right: 10px;
}
.chatwindow a {
display: block;
float: left;
width: 35px;
text-align: center;
text-decoration: none;
padding: 2px;
color: #000;
background: #cfc;
border: 1px dotted #0f0;
}
.chatwindow .heading a {
float: right;
margin-top: -17px;
background: none;
border: none;
color: #fff;
}
.chatwindow a:hover {
background: #8f8;
}
.msgs {
height: 200px;
overflow: auto;
}
.msgs p {
margin-left: 5px;
}
/* Log window elements */
#log {
clear: left;
width: 775px;
margin: 15px;
height: 123px;
background: #fff;
}
#logmsgs {
height: 100px;
overflow: auto;
}
#logmsgs p {
margin-left: 20px;
margin-right: 20px;
border-top: 1px dotted #ccc;
}
#loginmsg, #loginuser {
font-weight: bold;
color: #f33;
}
.debugtext {
color: #333;
}
.infotext {
color: #00f;
}
.errortext {
color: #f00;
}
Figure 12.2 shows what our IM client looks like at this point, in the default state:
This content is reprinted from Real-World AJAX: Secrets of the Masters published by SYS-CON Books. To order the entire book now along with companion DVDs, click here to order.
Published May 12, 2007 Reads 4,505
Copyright © 2007 SYS-CON Media, Inc. — All Rights Reserved.
Syndicated stories and blog feeds, all rights reserved by the author.
About James Benson
Jim Benson, AICP, is the COO of Gray Hill Solutions in Seattle. Gray Hill creates tools for government and industry to harness and utilize real-time data. Jim has always driven applications for his clients to store and provide information in easily extensible ways. Web 2.0 has therefore been a natural environment for him. He is also involved with the Cooperation Commons and the Institute for the Future's Future Commons to study human cooperation and envision the future of cooperation. Jim's tags: Gray Hill Solutions (www.grayhillsolutions.com), Jim's Blog (http://ourfounder.typepad.com), Cooperation Commons (www.cooperationcommons.org), Institute for the Future (www.iftf.org).
About Jay Fienberg
Jay Fienberg is co-founder of Juxtaprose (www.juxtaprose.com) where he designs information architecture and user experience for Websites and information systems. He specializes in design for enterprise-scale, Web-based social and collaboration systems. Since the early 1990s, Jay has also designed and developed hypertext, database, and content management systems and worked in a wide range of programming languages including XML, SQL, SGML, Python, PHP, Javascript, Java, HTML, CSS, and APL. Jay has a number of blogs, websites, and online projects available via jayfienberg.com.
- AJAX World RIA Conference & Expo Kicks Off in New York City
- What is Web 3.0?
- AJAXWorld RIA Conference & Expo 2009 West: Call for Papers
- AJAX and RIA 2009: More Choices, Tough Decisions
- Ulitzer’s Amazing First 30 Days in Public Beta
- SYS-CON Announces Government IT Conference & Expo
- RIAs for Web 3.0 Using the Microsoft Platform
- REA Is Where RIA Becomes the Norm
- Why an Application Grid?
- 2nd International Cloud Computing Expo New York Photo Album
- AJAX World RIA Conference & Expo Kicks Off in New York City
- What is Web 3.0?
- Developing Rich Client Applications Using Swing - II
- AJAXWorld RIA Conference & Expo 2009 West: Call for Papers
- AJAX and RIA 2009: More Choices, Tough Decisions
- AJAX World RIA Conference Awards Announced
- WebORB Launched for Flex, Flash, AJAX and Silverlight
- Appcelerator Revolutionizes UI Prototyping
- Adobe Takes LiveCycle into the Cloud
- Ulitzer’s Amazing First 30 Days in Public Beta
- Building a Drag-and-Drop Shopping Cart with AJAX
- What Is AJAX?
- Google Maps! AJAX-Style Web Development Using ASP.NET
- Flashback to January 2006: Exclusive SYS-CON.TV Interviews on "OpenAjax Alliance" Announcement
- AJAXWorld Conference & Expo to Take Place October 2-4, 2006, at the Santa Clara Convention Center, California
- AJAX Sponsor Webcasts Are Now Available at AJAXWorld Website
- How and Why AJAX, Not Java, Became the Favored Technology for Rich Internet Applications
- "Real-World AJAX" One-Day Seminar Arrives in Silicon Valley
- AJAXWorld University Announces AJAX Developer Bootcamp
- AJAX Support In JadeLiquid WebRenderer v3.1





































