summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rwxr-xr-xbin/repl.bat2
-rwxr-xr-xbin/run.bat2
-rwxr-xr-xsrc/benchmark.clj12
-rw-r--r--src/site.clj52
-rwxr-xr-xstatic/bg4.pngbin0 -> 5469 bytes
-rwxr-xr-xstatic/bottoml.pngbin0 -> 660 bytes
-rwxr-xr-xstatic/bottomr.pngbin0 -> 649 bytes
-rwxr-xr-xstatic/cloudbg.pngbin0 -> 8386 bytes
-rwxr-xr-xstatic/dfm.pngbin0 -> 4759 bytes
-rwxr-xr-xstatic/favicon.icobin0 -> 1406 bytes
-rwxr-xr-xstatic/favicon6.icobin0 -> 1406 bytes
-rwxr-xr-xstatic/favicon7.icobin0 -> 1406 bytes
-rwxr-xr-xstatic/index.html35
-rwxr-xr-xstatic/pichat.css66
-rwxr-xr-xstatic/pichat.js122
-rwxr-xr-xstatic/style.css171
-rwxr-xr-xstatic/topl.pngbin0 -> 679 bytes
-rwxr-xr-xstatic/topr.pngbin0 -> 651 bytes
18 files changed, 324 insertions, 138 deletions
diff --git a/bin/repl.bat b/bin/repl.bat
index 74ebcfb..68b1814 100755
--- a/bin/repl.bat
+++ b/bin/repl.bat
@@ -1,3 +1,3 @@
REM Windows REPL script
-java -cp lib/commons-io-1.4.jar;lib/commons-fileupload-1.2.1.jar;lib/commons-codec-1.3.jar;lib/clojure.jar;lib/clojure-contrib.jar;lib/compojure.jar;lib/jetty-6.1.14.jar;lib/jetty-util-6.1.14.jar;lib/servlet-api-2.5-6.1.14.jar;lib/jline-0.9.94.jar jline.ConsoleRunner clojure.lang.Repl %1 \ No newline at end of file
+java -server -cp lib/commons-io-1.4.jar;lib/commons-fileupload-1.2.1.jar;lib/commons-codec-1.3.jar;lib/clojure.jar;lib/clojure-contrib.jar;lib/compojure.jar;lib/jetty-6.1.14.jar;lib/jetty-util-6.1.14.jar;lib/servlet-api-2.5-6.1.14.jar;lib/jline-0.9.94.jar jline.ConsoleRunner clojure.lang.Repl %1 \ No newline at end of file
diff --git a/bin/run.bat b/bin/run.bat
index 2157268..11ed49c 100755
--- a/bin/run.bat
+++ b/bin/run.bat
@@ -1,3 +1,3 @@
REM Windows runner script
-java -cp lib/commons-io-1.4.jar;lib/commons-fileupload-1.2.1.jar;lib/commons-codec-1.3.jar;lib/clojure.jar;lib/clojure-contrib.jar;lib/compojure.jar;lib/jetty-6.1.14.jar;lib/jetty-util-6.1.14.jar;lib/servlet-api-2.5-6.1.14.jar clojure.lang.Script %1 \ No newline at end of file
+java -server -cp lib/commons-io-1.4.jar;lib/commons-fileupload-1.2.1.jar;lib/commons-codec-1.3.jar;lib/clojure.jar;lib/clojure-contrib.jar;lib/compojure.jar;lib/jetty-6.1.14.jar;lib/jetty-util-6.1.14.jar;lib/servlet-api-2.5-6.1.14.jar clojure.lang.Script %1 \ No newline at end of file
diff --git a/src/benchmark.clj b/src/benchmark.clj
index 3adf843..d963b74 100755
--- a/src/benchmark.clj
+++ b/src/benchmark.clj
@@ -53,13 +53,15 @@
(struct message-struct nick msg (System/currentTimeMillis))))
(alter users assoc-in [nick :last-seen] (System/currentTimeMillis))
"OK")))
-
+
+(defn out [x]
+ "out")
(defn do-bench []
(let [r (.nextDouble random)]
- (cond (< r 0.8) (json-str (refresh))
- (< r 0.9) (json-str (add-user))
- (< r 1) (json-str (post-message)))))
+ (cond (< r 0.8) (out (refresh))
+ (< r 0.9) (out (add-user))
+ (< r 1) (out (post-message)))))
(defn hello-world []
"hello world!")
@@ -71,4 +73,4 @@
(add-user)
(run-server {:port 8080}
- "/*" (servlet benchmark)) \ No newline at end of file
+ "/*" (servlet benchmark)) \ No newline at end of file
diff --git a/src/site.clj b/src/site.clj
index cce5da1..4e29e2b 100644
--- a/src/site.clj
+++ b/src/site.clj
@@ -8,13 +8,12 @@
(defstruct user-struct :nick :last-seen)
(defstruct message-struct :nick :content :timestamp)
-
(def users (ref {}))
(def messages (ref []))
(def run-flusher true)
(def flusher-sleep-ms 4000)
-(def user-timeout-ms 30000)
+(def user-timeout-ms 5000)
(defn swap [f]
(fn [& more] (apply f (reverse more))))
@@ -38,38 +37,44 @@
(defn resp-success [message]
{:status 200 :headers {} :body (json-str message)})
-(defn join-success [nick]
- (alter users assoc nick (struct user-struct nick (System/currentTimeMillis)))
- (let [users (sort (keys @users))
- messages (reverse (take 40 @messages))
- data {"users" users "messages" messages}]
- [(session-assoc :nick nick)
- (resp-success data)]))
+(defn new-messages
+ ([since] (reverse (take-while (fn [m] (> (m :timestamp) since)) @messages)))
+ ([] (reverse (take 25 @messages))))
-(defn try-join [params]
- (let [nick (escape-html (params :nick))]
- (dosync
- (if (contains? @users nick)
- (resp-error "NICK_TAKEN")
- (join-success nick)))))
+(def random (java.util.Random.))
+(def max-user-int 1000000)
+
+(defn make-random-nick []
+ (let [nick (str "user-" (.nextInt random max-user-int))]
+ (if (contains? @users nick)
+ (make-random-nick)
+ nick)))
-(defn new-messages [since]
- (reverse (take-while (fn [m] (> (m :timestamp) since)) @messages)))
+(defn updates
+ ([] {"users" (keys @users) "messages" (new-messages)})
+ ([since] {"users" (keys @users) "messages" (new-messages since)}))
+
+(defn init [session]
+ (let [new-nick (make-random-nick)]
+ (dosync
+ (alter users assoc new-nick
+ (struct user-struct new-nick (System/currentTimeMillis)))
+ [(session-assoc :nick new-nick)
+ (resp-success (assoc (updates) :nick new-nick))])))
(defn refresh [nick]
(dosync
(if (contains? @users nick)
- (let [last-seen (get-in @users [nick :last-seen])
- user-list (sort (keys @users))]
+ (let [last-seen (get-in @users [nick :last-seen])]
(alter users assoc-in [nick :last-seen] (System/currentTimeMillis))
- (resp-success {"messages" (new-messages last-seen)
- "users" user-list}))
+ (resp-success (updates last-seen)))
(resp-error "UNKNOWN_USER"))))
+
(defn msg [session params]
(dosync
(let [nick (session :nick)
- content (escape-html (params :content))
+ content (params :content)
msg (struct message-struct nick content (System/currentTimeMillis))]
(if (contains? @users nick)
(do (alter messages (swap cons) msg)
@@ -80,7 +85,8 @@
(GET "/" (serve-file "static" "index.html"))
(GET "/static/*" (or (serve-file "static" (params :*))
:next))
- (GET "/join" (try-join params))
+ (GET "/favicon.ico" (serve-file "static" "favicon.ico"))
+ (GET "/init" (init (session :nick)))
(GET "/refresh" (refresh (session :nick)))
(GET "/msg" (msg session params))
(ANY "*" [404 "Page not found"]))
diff --git a/static/bg4.png b/static/bg4.png
new file mode 100755
index 0000000..e20fda8
--- /dev/null
+++ b/static/bg4.png
Binary files differ
diff --git a/static/bottoml.png b/static/bottoml.png
new file mode 100755
index 0000000..0f52893
--- /dev/null
+++ b/static/bottoml.png
Binary files differ
diff --git a/static/bottomr.png b/static/bottomr.png
new file mode 100755
index 0000000..5904272
--- /dev/null
+++ b/static/bottomr.png
Binary files differ
diff --git a/static/cloudbg.png b/static/cloudbg.png
new file mode 100755
index 0000000..f397899
--- /dev/null
+++ b/static/cloudbg.png
Binary files differ
diff --git a/static/dfm.png b/static/dfm.png
new file mode 100755
index 0000000..5e8357e
--- /dev/null
+++ b/static/dfm.png
Binary files differ
diff --git a/static/favicon.ico b/static/favicon.ico
new file mode 100755
index 0000000..f9e8d8d
--- /dev/null
+++ b/static/favicon.ico
Binary files differ
diff --git a/static/favicon6.ico b/static/favicon6.ico
new file mode 100755
index 0000000..027dae5
--- /dev/null
+++ b/static/favicon6.ico
Binary files differ
diff --git a/static/favicon7.ico b/static/favicon7.ico
new file mode 100755
index 0000000..064a3f9
--- /dev/null
+++ b/static/favicon7.ico
Binary files differ
diff --git a/static/index.html b/static/index.html
index cee1d91..2d3bd61 100755
--- a/static/index.html
+++ b/static/index.html
@@ -3,21 +3,40 @@
<title>Pichat</title>
<link rel="stylesheet" type="text/css" href="static/reset.css">
<link rel="stylesheet" type="text/css" href="static/pichat.css">
+ <link rel="stylesheet" type="text/css" href="static/style.css">
+
<script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.3.2/jquery.min.js"></script>
<script type="text/javascript" src="static/pichat.js"></script>
- <script>
+ <script>
$(document).ready(function() {
- $('#join').click(join);
- $('#nick').keyup(ifEnter(join));
+ init();
});
</script>
</head>
<body>
- <div id="content">
- <h1>Welcome to Pichat!</h1>
- <input type="text" name="nick" id="nick">
- <input type="submit" value="Join" id="join">
- <img id="loginspinner" src="static/spinner.gif" style="display: none" />
+ <div id="welcomebar" style="display: none">
+ <span>Welcome, </span>
+ <span id="nickspan"></span>
</div>
+
+ <div id="wrapper">
+ <div id="chatPane">
+ <div id="messageList"></div>
+ <div id="msgInputDiv">
+ <input id="msgInput" type="input" disabled="disabled" />
+ <input id="msgSubmit" type="submit" value="Enter" disabled="disabled" />
+ </div>
+ </div>
+ <div id="userList"></div>
+ </div>
+
+ <div id="apDiv3"></div>
+ <div id="apDiv4"></div>
+ <div id="bottom">
+ <div align="center"></div>
+ </div>
+ <div id="apDiv5"></div>
+ <div id="apDiv6"></div>
+
</body>
</html>
diff --git a/static/pichat.css b/static/pichat.css
index a3cbaca..f413736 100755
--- a/static/pichat.css
+++ b/static/pichat.css
@@ -4,23 +4,36 @@ html, body {
padding: 1em;
}
-#content, #chatbox {
- position: relative;
-
+#content{
+ position:absolute;
+ z-index:3;
}
+#chatbox {
+ position: fixed;
+ top:48px;
+}
+h1,h2{
+ font: 100% 'helvetica neue',sans-serif;
+ letter-spacing:10px;
+ text-transform:uppercase;
+ font-family: Arial, Helvetica, sans-serif;
+ font-size: 9px;
+ top:35px;
+ position: fixed;
+}
#messagePane {
- border: 1px solid green;
- height: 80%;
- padding: 5px;
- position: fixed;
- width: 80%;
+ border: 1px solid green;
+ height: 80%;
+ padding: 5px;
+ position: fixed;
+ width: 80%;
}
#messageList {
height: 100%;
width: 100%;
- position:inherit
+ position: inherit
overflow-y: auto;
overflow-x: hidden;
border-bottom: 1px solid grey;
@@ -28,35 +41,36 @@ html, body {
#msgInputDiv {
height: 15px;
- position:relative;
+ position:relative;
}
#msgInput {
width: 85%;
margin-right: 5px;
margin-top: 15px;
- position:relative;
+ position:relative;
}
#msgSubmit {
width: 14%;
- position:relative;
+ position:relative;
}
-.msgDiv {
- width: 100%;
- max-width:650px;
-width: expression(this.width > 650 ? 650: true);max-height:400px;
-height: expression(this.width > 400 ? 400: true);}
-
+.msgDiv img {
+ max-width: 650px;
+ width: expression(this.width > 650 ? 650: true);
+ max-height:400px;
+ height: expression(this.width > 400 ? 400: true);
+ max-width:400px;
+}
#userList {
- overflow: auto;
- border: 1px solid blue;
- height: 80%;
- margin: 0px;
- position: fixed;
- padding: 5px;
- width: 10%;
- right: 3%;
+ overflow: auto;
+ border: 1px solid blue;
+ height: 80%;
+ margin: 0px;
+ position: fixed;
+ padding: 5px;
+ width: 10%;
+ right: 3%;
}
diff --git a/static/pichat.js b/static/pichat.js
index 4c950af..a7c40ca 100755
--- a/static/pichat.js
+++ b/static/pichat.js
@@ -2,17 +2,6 @@
var Nick = null;
-function handleJoinError(resp) {
- var respText = resp.responseText ? resp.responseText.trim() : false;
- if (respText == 'NICK_TAKEN') {
- alert("Nick '" + Nick + "' was taken! Please choose another.");
- } else if (respText) {
- alert("Cannot join! (" + respText + ")");
- } else {
- alert("Cannot join! Please try again later.");
- }
-}
-
function handleMsgError(resp) {
var respText = resp.responseText ? resp.responseText.trim() : false;
if (respText == 'UNKNOWN_USER') {
@@ -24,56 +13,22 @@ function handleMsgError(resp) {
}
}
-function join() {
- $('#join, #nick').attr('disabled', true);
- $('#loginspinner').show();
- Nick = $('#nick').val();
-
- onSuccess = function(json) {
- generateChatInterface(json.users, json.messages);
- };
-
- onError = function(resp, textStatus, errorThrown) {
- $('#join, #nick').attr('disabled', false);
- $('#loginspinner').hide();
- handleJoinError(resp);
- };
-
- $.ajax({
- type: 'GET',
- timeout: 5000,
- url: 'join',
- data: {'nick': Nick },
- cache: false,
- dataType: 'json',
- success: onSuccess,
- error: onError
- });
-}
-
function escapeHtml(txt) {
- return $("<span>").text(txt).html();
+ if (!txt) {
+ return ""
+ } else {
+ return $("<span>").text(txt).html();
+ }
}
function buildUserDiv(user) {
return '<div>' + escapeHtml(user) + '</div>';
}
-// http://rickyrosario.com/blog/converting-a-url-into-a-link-in-javascript-linkify-function
-function linkify(text){
- if (text) {
- text = text.replace(
- /((https?\:\/\/)|(www\.))(\S+)(\w{2,4})(:[0-9]+)?(\/|\/([\w#!:.?+=&%@!\-\/]))?/gi,
- function(url){
- var full_url = url;
- if (!full_url.match('^https?:\/\/')) {
- full_url = 'http://' + full_url;
- }
- return '<a href="' + full_url + '" target="_blank">' + url + '</a>';
- }
- );
- }
- return text;
+// http://stackoverflow.com/questions/37684/replace-url-with-html-links-javascript
+function linkify(text) {
+ var exp = /(\b(https?|ftp|file):\/\/[-A-Z0-9+&@#\/%?=~_|!:,.;]*[-A-Z0-9+&@#\/%=~_|])/gi;
+ return text.replace(exp,"<a href='$1'>$1</a>");
}
// http://snippets.dzone.com/posts/show/6995
@@ -94,21 +49,6 @@ function buildMessageDiv(msg) {
+ buildContent(msg.content) + '</div>';
}
-function buildChatInterface(users, messages) {
- var userList = '<div id="userList">'
- + $.map(users, buildUserDiv).join('') + '</div>';
- var messageList = '<div id="messagePane">'
- + '<div id="messageList">'
- + $.map(messages, buildMessageDiv).join('')
- + '</div>'
- + '<div id="msgInputDiv">'
- + '<input type="input" id="msgInput">'
- + '<input type="submit" value="Enter" id="msgSubmit">'
- + '</div>'
- + '</div>';
- return '<h1>Pichat</h1><div id="chatbox">' + userList + messageList + '</div>';
-}
-
function submitMessage() {
var content = $('#msgInput').val();
var msg = { 'nick': Nick, 'content': content, 'timestamp': new Date() };
@@ -125,6 +65,7 @@ function submitMessage() {
var onSuccess = function() {};
var onError = function(resp, textStatus, errorThrown) {
+
handleMsgError(resp);
};
@@ -155,7 +96,7 @@ function scrollToBottom(div) {
}
function refresh() {
- var onSuccess = function(json) {
+ var onSuccess = function(json) {
if (json.messages.length > 0) {
var shouldScroll = isScrolledToBottom($('#messageList')[0]);
@@ -185,10 +126,43 @@ function refresh() {
});
}
-function generateChatInterface(users, messages) {
- $('#content').html(buildChatInterface(users, messages));
+
+
+function init() {
+ var onSuccess = function(json) {
+ $('#loadingbox').hide();
+ Nick = json.nick;
+
+ $('#nickspan').text(Nick);
+ $('#welcomebar').show();
+
+ var msgStr = $.map(json.messages, buildMessageDiv).join('');
+ $('#messageList').append(msgStr);
+ $("#userList").html($.map(json.users, buildUserDiv).join(''));
+ $('#nickInput, #nickSubmit, #msgInput, #msgSubmit').removeAttr('disabled');
+
+ // Delay scrolling by .5 seconds so images can start loading.
+ setTimeout(scrollToBottom, 500, $('#messageList')[0]);
+ setInterval(refresh, 1000);
+ };
+
+ var onError = function(resp, textStatus, errorThrown) {
+ alert("Error connecting to chat server!");
+ };
+
+ $.ajax({
+ type: 'GET',
+ timeout: 5000,
+ url: 'init',
+ cache: false,
+ dataType: 'json',
+ success: onSuccess,
+ error: onError
+ });
+
$('#msgInput').keyup(ifEnter(submitMessage));
$('#msgSubmit').click(submitMessage);
- setInterval(refresh, 1000);
-}
+ $('#nickInput').keyup(ifEnter(join));
+ $('#nickSubmit').click(join);
+}
diff --git a/static/style.css b/static/style.css
new file mode 100755
index 0000000..99ee868
--- /dev/null
+++ b/static/style.css
@@ -0,0 +1,171 @@
+@charset "UTF-8";
+/* CSS Document */
+
+#apDiv2 {
+ position:relative;
+ top:150px;
+ width:700px;
+ margin: 0px auto -1px auto;
+ height: 300px;
+ z-index: 3;
+}
+#info {
+ position:relative;
+ top:285px;
+ width:700px;
+ margin: 0px auto -1px auto;
+ height: 14px;
+ color: #999;
+ bottom:0px;
+ z-index: 3;
+
+}
+#front {
+ position:fixed;
+ top:150px;
+}
+#infopage {
+
+
+ margin: 0px auto -1px auto;
+ height: 14px;
+ color: #999;
+ bottom:0px;
+ z-index: 3;
+ font-size: 10px;
+
+ font-size: 12px;
+ letter-spacing: 1px;
+ bottom: 0px;
+}
+#signin {
+ position:absolute;
+ left:0px;
+ width:410px;
+ height:281px;
+ background-image: url(logbg.png);
+ z-index:2;
+}
+#about {
+ position:absolute;
+ width:300px;
+ height: 281px;
+ left:410px;
+ line-height: 18px;
+ padding-left: 20px;
+ ;
+ font-weight: bold;
+ color: #333;
+ z-index:2;
+}
+#input {
+ padding-right:15px;
+ line-height:22px;
+ font-size: 12px;
+}
+body,td,th {
+ font-family: Arial, Helvetica, sans-serif;
+ font-size: 16px;
+ line-height: 40px;
+}
+#apDiv1 div #input #form1 label {
+ font-size: 12px;
+ color: #333;
+}
+.re {
+ font-size: 10px;
+}
+#apDiv2 #about div {
+ font-size: 10px;
+ color: #424143;
+}
+#top {
+ position:absolute;
+ left:0px;
+ top:0px;
+ width:100%;
+ height:32px;
+ z-index:2;
+ background-color: #CCC;
+}
+#apDiv3 {
+ position:fixed;
+ left:0px;
+ top:0px;
+ width:68px;
+ height:68px;
+ background-image: url(topl.png);
+}
+#apDiv4 {
+ position:fixed;
+ top:0px;
+ width:68px;
+ height:68px;
+
+ right: 0px;
+ background-image: url(topr.png);
+}
+#bottom {
+ position:absolute;
+ left:0px;
+ bottom:0px;
+ width:100%;
+ height:10px;
+ z-index:1;
+ font-size: 10px;
+ line-height: 5px;
+}
+#apDiv5 {
+ position:fixed;
+ bottom:0px;
+ width:60px;
+ height:68px;
+
+ left: 0px;
+ background-image: url(bottoml.png);
+}
+#apDiv6 {
+ position:fixed;
+ bottom:0px;
+ width:60px;
+ height:68px;
+
+ right: 0px;
+ background-image: url(bottomr.png);
+}
+#bg {
+ position:absolute;
+ left:0px;
+ top:0px;
+ width:100%;
+ height:100%;
+ z-index:2;
+ background-image:url(grad2.jpg);
+}
+body {
+ background-image: url(bg4.png);
+ background-repeat: repeat-x;
+ background-attachment:fixed;
+}
+#plane {
+ position:fixed;
+ top:9px;
+ right:0px;
+ width:100%;
+ height:100%;
+ z-index:1;
+ background-image: url(cloudbg.png);
+ background-repeat: no-repeat;
+ background-position:center;
+
+}
+.form { font-size: 14px; color="#990000"; }
+.info {
+ font-size: 10px;
+}
+.info {
+ font-size: 12px;
+ letter-spacing: 1px;
+ bottom: 0px;
+ color: #999;
+}
diff --git a/static/topl.png b/static/topl.png
new file mode 100755
index 0000000..dcfe5b9
--- /dev/null
+++ b/static/topl.png
Binary files differ
diff --git a/static/topr.png b/static/topr.png
new file mode 100755
index 0000000..9cfab08
--- /dev/null
+++ b/static/topr.png
Binary files differ