Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Browse files

Implemented interface

  • Loading branch information...
commit 494eacc52a04cca01f9588409edb9065b5473dc2 1 parent c3aac07
@dcneiner dcneiner authored
View
15 demo/chat.js
@@ -5,7 +5,20 @@ var chatServer = chat.createServer();
chatServer.listen(8001);
chatServer.addChannel({ basePath: "/chat" });
chatServer.passThru("/", router.staticHandler("index.html"));
-chatServer.passThru("/style.css", router.staticHandler("style.css"));
+
+// CSS
+chatServer.passThru("/css/layout.css", router.staticHandler("css/layout.css"));
+chatServer.passThru("/css/reset.css", router.staticHandler("css/reset.css"));
+
+// Images
+var files = ["background.png", "button.png", "footer.png", "glows.png", "header-bg.png", "inset-border-l.png", "inset-border.png", "metal.jpg","node-chat.png" ,"send.png"];
+
+for (var i = files.length - 1; i >= 0; i--){
+ chatServer.passThru("/images/" + files[i], router.staticHandler("images/" + files[i]));
+};
+
+//
+
chatServer.passThru("/jquery-1.4.2.js", router.staticHandler("jquery-1.4.2.js"));
chatServer.passThru("/nodechat.js", router.staticHandler("nodechat.js"));
chatServer.passThru("/client.js", router.staticHandler("client.js"));
View
71 demo/client.js
@@ -1,6 +1,33 @@
(function($) {
-var channel = nodeChat.connect("/chat");
+// window.setTimeout(function(){
+// $("#nick").val("Doug Neiner");
+// $("#login").submit();
+// }, 1000);
+
+var colors = ["green","orange","yellow","red","fuschia","blue"],
+ channel = nodeChat.connect("/chat"),
+ scroll = true,
+ log,
+ message ;
+
+// TODO: Turn off auto scrolling if user has scrolled up from the bottom
+
+$(function(){
+ log = $("#chat-log");
+ message = $("#message");
+
+ // Add a button that can be easily styled
+ $("<a />", {id:"submit", text: "Send", href: "#", click: function(e){
+ e.preventDefault();
+ $(this).closest('form').submit();
+ }}).appendTo("#entry fieldset");
+
+ // Add a message indicator when a nickname is clicked
+ $("#users").delegate("li", "click", function(){
+ message.val( $(this).text() + ": " + message.val()).focus();
+ })
+});
// new message posted to channel
// - add to the chat log
@@ -24,7 +51,7 @@ $(channel).bind("nodechat-msg", function(event, message) {
.text(message.text)
.appendTo(row);
- row.appendTo("#chat-log");
+ row.appendTo(log);
})
// another user joined the channel
// - add to the chat log
@@ -48,12 +75,14 @@ $(channel).bind("nodechat-msg", function(event, message) {
.text("joined the room")
.appendTo(row);
- row.appendTo("#chat-log");
+ row.appendTo(log);
})
// another user joined the channel
// - add to the user list
.bind("nodechat-join", function(event, message) {
- var added = false;
+ var added = false,
+ nick = $("<li />", {'class':colors[0], text: message.nick });
+ colors.push(colors.shift());
$("#users > li").each(function() {
if (message.nick == this.innerHTML) {
added = true;
@@ -61,12 +90,12 @@ $(channel).bind("nodechat-msg", function(event, message) {
}
if (message.nick < this.innerHTML) {
added = true;
- $("<li>" + message.nick + "</li>").insertBefore(this);
+ nick.insertBefore(this);
return false;
}
});
if (!added) {
- $("#users").append("<li>" + message.nick + "</li>");
+ $("#users").append(nick);
}
})
// another user left the channel
@@ -90,6 +119,8 @@ $(channel).bind("nodechat-msg", function(event, message) {
.addClass("chat-text")
.text("left the room")
.appendTo(row);
+
+ row.appendTo(log);
})
// another user left the channel
// - remove from the user list
@@ -100,17 +131,35 @@ $(channel).bind("nodechat-msg", function(event, message) {
return false;
}
});
+})
+
+// Auto scroll list to bottom
+.bind("nodechat-join nodechat-part nodechat-msg", function(){
+ window.setTimeout(function(){
+ log.scrollTop(log[0].scrollHeight);
+ }, 10);
});
// handle login (choosing a nick)
$(function() {
- var login = $("#login").submit(function() {
+ var login = $("#login");
+ login.submit(function() {
+ $(this).one('ajaxSuccess.login', function(){
+ login.unbind('ajaxError.login');
+ $("body").removeClass("login").addClass("channel");
+ $("#message").focus();
+ }).one('ajaxError.login', function(){
+ login.unbind('ajaxSuccess.login')
+ .find('label').text("Nickname in use. Please choose another:").end()
+ .addClass("error")
+ .find('input').focus();
+ });
+
channel.join($("#nick").val());
-
- // TODO: handle unsuccessful login
- $("body").removeClass("login").addClass("channel");
+
return false;
});
+ login.find('input').focus();
});
// handle sending a message
@@ -118,7 +167,7 @@ $(function() {
var message = $("#message");
$("#channel form").submit(function() {
channel.send(message.val());
- message.val("");
+ message.val("").focus();
return false;
});
View
401 demo/css/layout.css
@@ -0,0 +1,401 @@
+@import "reset.css";
+
+html {
+ background: #3c3c3c url(../images/background.png);
+}
+
+html, body {
+ width: 100%;
+ height: 100%;
+}
+
+#users li {
+ text-decoration: none;
+ color: #ccc;
+ text-shadow: rgba(0,0,0,1) 0 -1px 0, rgba(0,0,0,0.4) 0 0 1px;
+ font-family: helvetica, arial, sans-serif;
+ font-size: 14px;
+ width: 155px;
+ height: 35px;
+ display: block;
+ text-align: center;
+ text-indent: -1px;
+ line-height: 30px;
+ background: url(../images/button.png) no-repeat;
+ position: relative;
+ margin: 0 0 5px 0;
+ cursor: pointer;
+}
+
+#users li:hover {
+ color: #fff;
+ background-position: 0 -36px;
+}
+
+
+#users li:active {
+ color: #fff;
+ line-height: 33px;
+ text-indent: -1px;
+ background-position: 0 -72px;
+}
+
+#users li:active:after {
+ top: 26px;
+}
+
+#users li:after {
+ content: "";
+ display: block;
+ width: 57px;
+ height: 12px;
+ position: absolute;
+ left: 50%;
+ margin-left: -29px;
+ top: 25px;
+ background: url(../images/glows.png) no-repeat;
+}
+
+#users li.green:after { background-position: 0 0;}
+#users li.orange:after { background-position: -57px 0;}
+#users li.yellow:after { background-position: -114px 0;}
+#users li.red:after { background-position: -171px 0;}
+#users li.fuschia:after { background-position: -228px 0;}
+#users li.blue:after { background-position: -285px 0;}
+
+#users {
+ position: fixed;
+ width: 155px;
+ top: 45px;
+ right: 25px;
+}
+
+#frame {
+ display: block;
+ position: fixed;
+ left: 20px;
+ right: 200px;
+ top: 45px;
+ bottom: 110px;
+ border-width: 5px 7px 7px 5px;
+ -webkit-border-image: url(../images/inset-border.png) 5 7 7 5 stretch stretch;
+ -moz-border-image: url(../images/inset-border.png) 5 7 7 5 stretch stretch;
+}
+
+body > header {
+ height: 23px;
+ background: #000 url(../images/header-bg.png) repeat-x;
+ -webkit-box-shadow: rgba(255,255,255,0.1) 0 1px 0;
+ -moz-box-shadow: rgba(255,255,255,0.1) 0 1px 0;
+ box-shadow: rgba(255,255,255,0.1) 0 1px 0;
+ position: fixed;
+ left: 0;
+ right: 0;
+ top: 0;
+ display: block;
+}
+
+body > header img {
+ position: relative;
+ top: 3px;
+ left: 6px;
+}
+
+footer {
+ height: 26px;
+ position: fixed;
+ left: 0;
+ right: 0;
+ bottom: 0;
+ background: url(../images/footer.png) repeat-x;
+}
+
+footer p.credits {
+ font-family: "Gill Sans", "Gill Sans MT", Helvetica, Arial, sans-serif;
+ text-transform: uppercase;
+ height: 26px;
+ line-height: 26px;
+ padding: 0 15px;
+ font-size: 10px;
+ text-align: right;
+ color: #7b7b7b;
+ text-shadow: #000 0 1px 0, #000 0 0 1px;
+}
+
+footer p.credits a {
+ color: #aaa;
+ text-decoration: none;
+}
+
+footer p.credits a:hover {
+ color: #ccc;
+}
+
+span.pipe {
+ margin: 0 3px;
+}
+
+#entry {
+ border-top: solid 1px #c2c2c2;
+ border-bottom: solid 1px #646464;
+ -webkit-box-shadow: #000 0 -1px 0;
+ -moz-box-shadow: #000 0 -1px 0;
+ box-shadow: #000 0 -1px 0;
+ height: 60px;
+ position: fixed;
+ left: 0;
+ right: 0;
+ bottom: 26px;
+ background: #a7a7a7 url(../images/metal.jpg) center -3px repeat-x;
+}
+
+#entry p {
+ position: fixed;
+ height: 20px;
+ left: 27px;
+ right: 270px;
+
+ width: auto;
+ bottom: 46px;
+
+}
+
+#entry input[type=text]{
+ background: transparent;
+ padding: 0;
+ outline: none;
+ border: none;
+ display: block;
+ color: #fff;
+ width: 100%;
+ height: 100%;
+ text-shadow: #000 0 1px 0;
+ font-size: 11pt;
+ font-family: helvetica, arial, sans-serif;
+}
+
+#entry input[type=submit]{
+ display: none;
+}
+
+#entry a#submit {
+ position: absolute;
+ background: url(../images/send.png) no-repeat;
+ right: -6px;
+ top: -4px;
+ font-family: helvetica, arial, sans-serif;
+ text-align: center;
+ width: 68px;
+ height: 27px;
+ line-height: 25px;
+ border: none;
+ padding: 0;
+ outline: none;
+ font-size: 14px;
+ text-indent: -1px;
+ color: #111;
+ text-shadow: rgba(255,255,255,0.3) 0 1px 0;
+ text-decoration: none;
+}
+
+#entry a#submit:hover {
+ background-position: 0 -27px;
+ text-shadow: rgba(255,255,255,0.3) 0 1px 0, rgba(255,255,255,0.8) 0 0 6px;
+}
+
+#entry a#submit:active {
+ background-position: 0 -54px;
+ line-height: 27px;
+ text-indent: 1px;
+}
+
+#entry input[type=submit]{
+}
+
+#entry fieldset {
+ position: absolute;
+ left: 20px;
+ top: 14px;
+ height: 17px;
+ right: 200px;
+ border-width: 7px 8px 8px 8px;
+ -webkit-border-image: url(../images/inset-border-l.png) 7 8 8 8 repeat repeat;
+ -moz-border-image: url(../images/inset-border-l.png) 7 8 8 8 repeat repeat;
+ -webkit-border-radius: 6px;
+ -moz-border-radius: 4px;
+ border-radius: 4px;
+}
+
+#entry fieldset.focus {
+/* -webkit-box-shadow: rgba(255,255,255,1) 0 0 7px;*/
+}
+
+
+#chat-log {
+ position: absolute;
+ left: 0.5%;
+ bottom: 0.5%;
+ width: 99%;
+ overflow: auto;
+ max-height: 99%;
+ font-family: helvetica, arial, sans-serif;
+ color: #ccc;
+}
+
+#chat-log div.chat-msg {
+ margin-right: 10px;
+ padding: 6px 70px 6px 30px;
+ font-size: 10pt;
+ border-bottom: solid 1px #111;
+ -webkit-box-shadow: #444 0 1px 0;
+ -moz-box-shadow: #444 0 1px 0;
+ box-shadow: #444 0 1px 0;
+ margin-bottom: 1px;
+ border-width: 0 0 1px 0;
+ position: relative;
+ line-height: 140%;
+ text-indent: -20px;
+}
+
+#chat-log div.chat-system-msg {
+ text-align: center;
+ font-style: italic;
+ color: #888;
+ text-shadow: #000 0 -1px 0;
+}
+
+
+
+.chat-time {
+ position: absolute;
+ font-size: 10px;
+ height: 10pt;
+ line-height: 12px;
+ display: block;
+ float: left;
+ right: 6px;
+ top: 7px;
+ color: #111;
+ font-weight: bold;
+ font-style: normal;
+ text-shadow: #4a4a4a 0 1px 0;
+}
+
+#chat-log div.chat-msg .chat-nick {
+ color: #fff;
+ margin-right: 10px;
+}
+
+#chat-log div.chat-msg .chat-nick:after {
+ content: ":";
+}
+
+#chat-log div.chat-system-msg .chat-nick {
+ margin-right: 4px;
+ color: #888;
+ font-weight: bold;
+}
+
+#chat-log div.chat-system-msg .chat-nick:after {
+ content: "";
+}
+
+
+#chat-log div.chat-msg:nth-child(2n){
+ background: rgba(0,0,0,0.05);
+}
+
+
+
+
+#login {
+ position: fixed;
+ height: 70px;
+ left: 0;
+ right: 0;
+ margin-top: -75px;
+ top: 50%;
+ z-index: 200;
+ background: #a7a7a7 url(../images/metal.jpg) 0 -3px repeat-x;
+ border-top: solid 1px #bbb;
+ border-bottom: solid 1px #666;
+ -webkit-box-shadow: rgba(0,0,0,0.4) 0 2px 4px;
+}
+
+#login h1 {
+ font-family: "Gill Sans", "Gill Sans MT", Helvetica, Arial, sans-serif;
+ text-transform: uppercase;
+ color: #333;
+ text-align: center;
+ padding: 4px 0 0 0;
+ font-size: 16px;
+ letter-spacing: 1px;
+ text-shadow: rgba(255,255,255,0.3) 0 1px 0;
+}
+
+#login p {
+ position: absolute;
+ content: "";
+ display: block;
+ height: 35px;
+ line-height: 35px;
+ left: 0;
+ right: 0;
+ bottom: 10px;
+ text-align: center;
+ background: url(../images/footer.png) repeat-x;
+}
+
+#login input {
+ width: 150px;
+ margin-left: 5px;
+ background: #fff;
+ border: none;
+ padding: 3px;
+ -webkit-border-radius: 3px;
+ -moz-border-radius: 3px;
+ border-radius: 3px;
+}
+
+#login.error {
+ -webkit-box-shadow: red 0 0 100px;
+ -moz-box-shadow: red 0 0 50px;
+ box-shadow: red 0 0 100px;
+}
+
+#login p label {
+ font-family: helvetica, arial, sans-serif;
+ color: #ddd;
+ font-size: 12px;
+ font-style: italic;
+ text-shadow: #000 0 1px 0;
+}
+
+body.login header:after {
+ content: "";
+ display: block;
+ position: fixed;
+ top: 0;
+ left: 0;
+ bottom: 0;
+ right: 0;
+ background: url(../images/background.png);
+ opacity: 0.8;
+ z-index: 100;
+}
+
+body.login header:before {
+ content: "";
+ display: block;
+ position: fixed;
+ top: 0;
+ left: 0;
+ bottom: 0;
+ right: 0;
+ background: rgba(0,0,0,0.5);
+ opacity: 0.8;
+ z-index: 101;
+}
+
+body #login { display: none;}
+body.login #login { display: block;}
View
52 demo/css/reset.css
@@ -0,0 +1,52 @@
+/*
+ Written by Eric Myer
+ Source: http://meyerweb.com/eric/thoughts/2007/05/01/reset-reloaded/
+*/
+html, body, div, span, applet, object, iframe,
+h1, h2, h3, h4, h5, h6, p, blockquote, pre,
+a, abbr, acronym, address, big, cite, code,
+del, dfn, em, font, img, ins, kbd, q, s, samp,
+small, strike, strong, sub, sup, tt, var,
+dl, dt, dd, ol, ul, li,
+fieldset, form, label, legend,
+table, caption, tbody, tfoot, thead, tr, th, td {
+ margin: 0;
+ padding: 0;
+ border: 0;
+ outline: 0;
+ font-weight: inherit;
+ font-style: inherit;
+ font-size: 100%;
+ font-family: inherit;
+ vertical-align: baseline;
+}
+
+/* remember to define focus styles! */
+:focus {
+ outline: 0;
+}
+body {
+ line-height: 1;
+ color: black;
+ background: transparent;
+}
+ol, ul {
+ list-style: none;
+}
+
+/* tables still need 'cellspacing="0"' in the markup */
+table {
+ border-collapse: separate;
+ border-spacing: 0;
+}
+caption, th, td {
+ text-align: left;
+ font-weight: normal;
+}
+blockquote:before, blockquote:after,
+q:before, q:after {
+ content: "";
+}
+blockquote, q {
+ quotes: "" "";
+}
View
BIN  demo/images/background.png
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
View
BIN  demo/images/button.png
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
View
BIN  demo/images/footer.png
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
View
BIN  demo/images/glows.png
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
View
BIN  demo/images/header-bg.png
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
View
BIN  demo/images/inset-border-l.png
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
View
BIN  demo/images/inset-border.png
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
View
BIN  demo/images/metal.jpg
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
View
BIN  demo/images/node-chat.png
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
View
BIN  demo/images/send.png
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
View
56 demo/index.html
@@ -1,30 +1,50 @@
-<!doctype html>
+<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
- <title>node chat</title>
+ <title>NodeChat v0.1</title>
- <link rel="stylesheet" type="text/css" href="style.css">
+ <link rel="stylesheet" type="text/css" href="css/layout.css">
<script src="jquery-1.4.2.js"></script>
<script src="nodechat.js"></script>
<script src="client.js"></script>
</head>
<body class="login">
-<div id="wrapper">
- <form id="login">
- <p>Welcome to node-chat.</p>
- <p>Please choose a nick.</p>
- <input id="nick">
- </form><!-- #login -->
- <div id="channel">
- <ul id="users"></ul>
- <div id="chat-log"></div>
- <form>
- <input id="message">
- </form>
- </div><!-- #channel -->
-</div><!-- #wrapper -->
-
+ <header><img src="images/node-chat.png" width="92" height="10" alt="Node Chat v0.1" /></header>
+
+ <form id="login">
+ <h1>Welcome to Node-<strong>Chat</strong></h1>
+ <p>
+ <label for="nick">Please choose a nickname:</label>
+ <input type="text" id="nick" autocomplete="off" />
+ </p>
+ </form><!-- #login -->
+
+ <section id="channel">
+
+ <section id="frame">
+ <div id="chat-log">
+ </div>
+ </section>
+
+ <ul id="users" class="button_list">
+ </ul>
+
+ <form id="entry">
+ <fieldset>
+ <p><input type="text" name="message" value="" autocomplete="off" id="message" /></p>
+ <input type="submit" value="Send" id="Send" />
+ </fieldset>
+ </form>
+
+ <footer>
+ <p class="credits">
+ Node.js + jQuery Chat Demo by <a href="#">Scott Gonz&aacute;lez</a> <span class="pipe">|</span>
+ User Interface by <a href="http://dougneiner.com">Doug Neiner</a>
+ </p>
+ </footer>
+
+ </section>
</body>
</html>
View
2  lib/channel.js
@@ -79,7 +79,7 @@ process.mixin(Channel.prototype, {
nick = nick.toLowerCase();
for (var i in this.sessions) {
- if (this.sessions[i].nick.toLowerCase() === nick) {
+ if (this.sessions[i].nick && this.sessions[i].nick.toLowerCase() === nick) {
return;
}
}
Please sign in to comment.
Something went wrong with that request. Please try again.