summaryrefslogtreecommitdiff
path: root/static
diff options
context:
space:
mode:
Diffstat (limited to 'static')
-rwxr-xr-xstatic/index.html23
-rwxr-xr-xstatic/pichat.css53
-rwxr-xr-xstatic/pichat.js170
-rwxr-xr-xstatic/reset.css54
-rwxr-xr-xstatic/spinner.gifbin0 -> 1849 bytes
-rwxr-xr-xstatic/test.html75
6 files changed, 375 insertions, 0 deletions
diff --git a/static/index.html b/static/index.html
new file mode 100755
index 0000000..bd75ab1
--- /dev/null
+++ b/static/index.html
@@ -0,0 +1,23 @@
+<html>
+ <head>
+ <title>Pichat</title>
+ <link rel="stylesheet" type="text/css" href="static/reset.css">
+ <link rel="stylesheet" type="text/css" href="static/pichat.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>
+ $(document).ready(function() {
+ $('#join').click(join);
+ $('#nick').keyup(ifEnter(join));
+ });
+ </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>
+ </body>
+</html>
diff --git a/static/pichat.css b/static/pichat.css
new file mode 100755
index 0000000..383ba7a
--- /dev/null
+++ b/static/pichat.css
@@ -0,0 +1,53 @@
+/* pichat.css */
+
+html, body {
+ padding: 1em;
+}
+
+#content, #chatbox {
+ position: relative;
+}
+
+#messagePane {
+ border: 1px solid green;
+ height: 600px;
+ padding: 5px;
+ position: absolute;
+ width: 540px;
+}
+
+#messageList {
+ height: 575px;
+ width: 540px;
+ overflow-y: auto;
+ overflow-x: hidden;
+ border-bottom: 1px solid grey;
+}
+
+#msgInputDiv {
+ height: 15px;
+}
+
+#msgInput {
+ width: 85%;
+ margin-right: 5px;
+}
+
+#msgSubmit {
+ width: 14%;
+}
+
+.msgDiv {
+ width: 520px;
+}
+
+#userList {
+ overflow: auto;
+ border: 1px solid blue;
+ height: 600px;
+ margin: 0px;
+ position: absolute;
+ padding: 5px;
+ left: 550px;
+ width: 150px;
+} \ No newline at end of file
diff --git a/static/pichat.js b/static/pichat.js
new file mode 100755
index 0000000..b12c772
--- /dev/null
+++ b/static/pichat.js
@@ -0,0 +1,170 @@
+// pichat.js
+
+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') {
+ alert("Can't send message! Please login.");
+ } else if (respText) {
+ alert("Cannot send message! (" + respText + ")");
+ } else {
+ alert("Cannot send message!");
+ }
+}
+
+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 buildUserDiv(user) {
+ return '<div>' + user + '</div>';
+}
+
+// http://snippets.dzone.com/posts/show/6995
+var URLRegex = /((http\:\/\/|https\:\/\/|ftp\:\/\/)|(www\.))+(\w+:{0,1}\w*@)?(\S+)(:[0-9]+)?(\/|\/([\w#!:.?+=&%@!\-\/]))?/i;
+
+function buildMessageDiv(msg) {
+ var match = URLRegex.exec(msg.content)
+ if (match) {
+ return '<div class="msgDev"><b>' + msg.nick + ': </b>'
+ + '<img height="150" width="150" src="' + match[0] + '" /></div>';
+ } else {
+ return '<div class="msgDiv"><b>' + msg.nick + ": </b>"
+ + 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() };
+ if (content == '') { return; }
+
+ var shouldScroll = isScrolledToBottom($('#messageList')[0]);
+
+ $('#messageList').append($(buildMessageDiv(msg)));
+ $('#msgInput').val('');
+
+ if (shouldScroll) {
+ scrollToBottom($('#messageList')[0]);
+ }
+
+ var onSuccess = function() {};
+ var onError = function(resp, textStatus, errorThrown) {
+ handleMsgError(resp);
+ };
+
+ $.ajax({
+ type: 'GET',
+ timeout: 5000,
+ url: 'msg',
+ data: {'content': content },
+ cache: false,
+ dataType: 'json',
+ success: onSuccess,
+ error: onError
+ });
+}
+
+function ifEnter(fn) {
+ return function(e) {
+ if (e.keyCode == 13) { fn(); }
+ };
+}
+
+function isScrolledToBottom(div) {
+ return Math.abs(div.scrollTop - (div.scrollHeight - div.offsetHeight)) <= 3;
+}
+
+function scrollToBottom(div) {
+ div.scrollTop = div.scrollHeight;
+}
+
+function refresh() {
+ var onSuccess = function(json) {
+ if (json.messages.length == 0) {
+ return;
+ }
+
+ var shouldScroll = isScrolledToBottom($('#messageList')[0]);
+
+ // Ignore our own messages
+ var filterFunc = function(m) { return m.nick != Nick };
+ var msgStr = $.map($.grep(json.messages, filterFunc),
+ buildMessageDiv).join('');
+ $('#messageList').append(msgStr);
+
+ if (shouldScroll) {
+ scrollToBottom($('#messageList')[0]);
+ }
+ };
+
+ var onError = function(resp, textStatus, errorThrown) {};
+
+ $.ajax({
+ type: 'GET',
+ timeout: 5000,
+ url: 'refresh',
+ cache: false,
+ dataType: 'json',
+ success: onSuccess,
+ error: onError
+ });
+}
+
+function generateChatInterface(users, messages) {
+ $('#content').html(buildChatInterface(users, messages));
+ $('#msgInput').keyup(ifEnter(submitMessage));
+ $('#msgSubmit').click(submitMessage);
+ setInterval(refresh, 1000);
+}
+
diff --git a/static/reset.css b/static/reset.css
new file mode 100755
index 0000000..8767cdd
--- /dev/null
+++ b/static/reset.css
@@ -0,0 +1,54 @@
+/* reset.css
+ From http://meyerweb.com/eric/tools/css/reset/
+ v1.0 | 20080212 */
+
+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,
+b, u, i, center,
+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-size: 100%;
+ vertical-align: baseline;
+ background: transparent;
+}
+body {
+ line-height: 1;
+}
+ol, ul {
+ list-style: none;
+}
+blockquote, q {
+ quotes: none;
+}
+blockquote:before, blockquote:after,
+q:before, q:after {
+ content: '';
+ content: none;
+}
+
+/* remember to define focus styles! */
+:focus {
+ outline: 0;
+}
+
+/* remember to highlight inserts somehow! */
+ins {
+ text-decoration: none;
+}
+del {
+ text-decoration: line-through;
+}
+
+/* tables still need 'cellspacing="0"' in the markup */
+table {
+ border-collapse: collapse;
+ border-spacing: 0;
+} \ No newline at end of file
diff --git a/static/spinner.gif b/static/spinner.gif
new file mode 100755
index 0000000..5b33f7e
--- /dev/null
+++ b/static/spinner.gif
Binary files differ
diff --git a/static/test.html b/static/test.html
new file mode 100755
index 0000000..1c9bfbe
--- /dev/null
+++ b/static/test.html
@@ -0,0 +1,75 @@
+<html>
+ <head>
+ <style>
+ #container {
+ position: relative;
+ width: 1000px;
+ }
+ #left {
+ border: 1px solid green;
+ height: 600px;
+ left: -89px;
+ margin: 0px auto 10%;
+ margin-left: 10%;
+ padding: 20px;
+ position: absolute;
+ top: 1%;
+ width: 500px;
+ }
+
+ #right {
+ border: 1px solid blue;
+ height: 600px;
+ margin: 0px 10%;
+ margin-right: 10%;
+ padding: 20px;
+ position: absolute;
+ left: 450px;
+ top: 1%;
+ width: 150px;
+ }
+ </style>
+ </head>
+
+ <body>
+ <div id="container">
+ <div id="left">
+ I saw the best minds of my generation destroyed by
+madness, starving hysterical naked,
+dragging themselves through the negro streets at dawn
+looking for an angry fix,
+angelheaded hipsters burning for the ancient heavenly
+connection to the starry dynamo in the machin-
+ery of night,
+who poverty and tatters and hollow-eyed and high sat
+up smoking in the supernatural darkness of
+cold-water flats floating across the tops of cities
+contemplating jazz,
+who bared their brains to Heaven under the El and
+saw Mohammedan angels staggering on tene-
+ment roofs illuminated,
+who passed through universities with radiant cool eyes
+hallucinating Arkansas and Blake-light tragedy
+among the scholars of war,
+who were expelled from the academies for crazy &
+publishing obscene odes on the windows of the
+skull,
+who cowered in unshaven rooms in underwear, burn-
+ing their money in wastebaskets and listening
+to the Terror through the wall,
+who got busted in their pubic beards returning through
+Laredo with a belt of marijuana for New York,
+who ate fire in paint hotels or drank turpentine in
+Paradise Alley, death, or purgatoried their
+torsos night after night
+with dreams, with drugs, with waking nightmares, al-
+cohol and cock and endless balls,
+incomparable blind; streets of shuddering cloud and
+lightning in the mind leaping toward poles of
+ </div>
+ <div id="right">
+ </div>
+ </div>
+ </body>
+
+</html>