summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rwxr-xr-xbin/repl.sh2
-rwxr-xr-xsrc/cookie_login.clj2
-rwxr-xr-xsrc/site.clj44
-rwxr-xr-xsrc/utils.clj75
-rwxr-xr-xstatic/away.js1
-rw-r--r--static/browsertool.gifbin4583 -> 6231 bytes
-rw-r--r--static/cloudbar.pngbin0 -> 56423 bytes
-rw-r--r--static/cloudbar2.pngbin0 -> 27560 bytes
-rw-r--r--static/cloudbar3.pngbin0 -> 88316 bytes
-rwxr-xr-xstatic/header.css6
-rwxr-xr-xstatic/index.html4
-rwxr-xr-xstatic/js/home.js3
-rwxr-xr-xstatic/js/pichat.js121
-rwxr-xr-xstatic/js/register.js17
-rwxr-xr-xstatic/js/stats.js79
-rw-r--r--static/noinfo.pngbin0 -> 52768 bytes
-rwxr-xr-xstatic/pichat.css57
-rwxr-xr-xstatic/profile.css15
-rwxr-xr-xstatic/search/browser.html2
-rw-r--r--static/tests/scrolling.html128
-rw-r--r--static/webcam/register.html233
-rw-r--r--static/webcam/webcam.js19
-rwxr-xr-xtemplate/banner.st2
-rwxr-xr-xtemplate/browser.st2
-rwxr-xr-xtemplate/chat.st25
-rw-r--r--template/form_login.st2
-rwxr-xr-xtemplate/profile.st23
27 files changed, 692 insertions, 170 deletions
diff --git a/bin/repl.sh b/bin/repl.sh
index d5c7413..856e592 100755
--- a/bin/repl.sh
+++ b/bin/repl.sh
@@ -1,3 +1,3 @@
#!/bin/sh
-java -server -cp .:lib/commons-io-1.4.jar:lib/commons-fileupload-1.2.1.jar:lib/commons-codec-1.3.jar:lib/jline-0.9.94.jar:lib/clojure.jar:lib/clojure-contrib.jar:lib/compojure-3.2v1.jar:lib/jetty-6.1.14.jar:lib/jetty-util-6.1.14.jar:lib/servlet-api-2.5-6.1.14.jar:lib/postgresql-8.4-701.jdbc4.jar:lib/stringtemplate-3.2.1.jar:lib/antlr-2.7.7.jar:src/ jline.ConsoleRunner clojure.lang.Repl $1
+java -Xmx256m -server -cp .:lib/commons-io-1.4.jar:lib/commons-fileupload-1.2.1.jar:lib/commons-codec-1.3.jar:lib/jline-0.9.94.jar:lib/clojure.jar:lib/clojure-contrib.jar:lib/compojure-3.2v1.jar:lib/jetty-6.1.14.jar:lib/jetty-util-6.1.14.jar:lib/servlet-api-2.5-6.1.14.jar:lib/postgresql-8.4-701.jdbc4.jar:lib/stringtemplate-3.2.1.jar:lib/antlr-2.7.7.jar:src/ jline.ConsoleRunner clojure.lang.Repl $1
diff --git a/src/cookie_login.clj b/src/cookie_login.clj
index ce41c66..e507876 100755
--- a/src/cookie_login.clj
+++ b/src/cookie_login.clj
@@ -38,7 +38,7 @@
"Middleware to support automatic cookie login. Must be placed after
the with-session middleware.
- Must be given three arguments:
+Must be given three arguments:
- process-login-token?
Function to apply to request map to determine whether to
process login token or not. If a false value is returned,
diff --git a/src/site.clj b/src/site.clj
index 7b75b71..2936f13 100755
--- a/src/site.clj
+++ b/src/site.clj
@@ -14,17 +14,7 @@
clojure.contrib.sql
compojure
cookie-login
- image-utils
- ))
-
-(let [db-host "localhost"
- db-port 5432
- db-name "dumpfm"]
- (def db {:classname "org.postgresql.Driver"
- :subprotocol "postgresql"
- :subname (str "//" db-host ":" db-port "/" db-name)
- :user "postgres"
- :password "root"}))
+ utils))
(def *run-flusher* true)
(def *flusher-sleep-ms* 4000)
@@ -80,12 +70,6 @@
(def formatter (new SimpleDateFormat "h:mm EEE M/d"))
-(defn resp-error [message]
- {:status 400 :headers {} :body message})
-
-(defn resp-success [message]
- {:status 200 :headers {} :body (json-str message)})
-
(defn non-empty-string? [s]
(and s (> (count s) 0)))
@@ -104,19 +88,6 @@
(.setTimeZone df (TimeZone/getTimeZone "GMT"))
(.format df dt))))
-;; Database
-
-(defn do-select [query]
- (with-connection db
- (with-query-results rs query
- (doall rs))))
-
-(defn do-count [query]
- ((first (with-connection db
- (with-query-results rs query
- (doall rs))))
- :count))
-
;; User authentication
(def nick-regex #"^[A-Za-z0-9\-_∆˚†]*$")
@@ -274,13 +245,9 @@
(try [(aget x 0) (Long/parseLong (aget x 1)) (aget x 2)]
(catch NumberFormatException _ nil))))
+
(defn read-login-token [token]
- (if-let [[nick expiry token-hash] (parse-login-token token)]
- (if (>= expiry (System/currentTimeMillis))
- (let [db-info (fetch-nick nick)
- computed-hash (sha1-hash (db-info :hash) expiry)]
- (if (= token-hash computed-hash)
- db-info)))))
+ nil)
(defn make-login-token
[{nick :nick hash :hash}]
@@ -303,7 +270,7 @@
db-user (authorize-nick-hash nick hash)
remember-me (= (params :rememberme) "yes")
login-cookie (if remember-me
- (make-login-token db-user *login-token-expiry*)
+ (make-login-token db-user)
(clear-login-token *login-token-key*))]
(if db-user
[(session-assoc-from-db db-user)
@@ -642,6 +609,7 @@
(-> request :route-params :room)
(-> request :route-params :offset)
params))
+ (GET "/stats" (validated-stats session params))
;; TODO: validate POST Referrer headers for POSTs
(POST "/msg" (validated-msg session params))
(POST "/submit-registration" (register session params))
@@ -696,4 +664,4 @@
"/upload/*" (servlet multipart)
"/*" (servlet pichat))
-(send-off flusher flush!) \ No newline at end of file
+(send-off flusher flush!)
diff --git a/src/utils.clj b/src/utils.clj
new file mode 100755
index 0000000..3ffd54b
--- /dev/null
+++ b/src/utils.clj
@@ -0,0 +1,75 @@
+(ns utils
+ (:import java.text.SimpleDateFormat
+ java.util.Date)
+ (:use clojure.contrib.json.write
+ clojure.contrib.sql))
+
+(let [db-host "localhost"
+ db-port 5432
+ db-name "dumpfm"]
+ (def db {:classname "org.postgresql.Driver"
+ :subprotocol "postgresql"
+ :subname (str "//" db-host ":" db-port "/" db-name)
+ :user "postgres"
+ :password "root"}))
+
+;; JSON responses
+
+(def yyyy-mm-dd-formatter (new SimpleDateFormat "yyyy-MM-dd"))
+
+(defmethod print-json Date
+ [d]
+ (print-json (.format yyyy-mm-dd-formatter d)))
+
+(defn resp-error [message]
+ {:status 400 :headers {} :body message})
+
+(defn resp-success [message]
+ {:status 200 :headers {} :body (json-str message)})
+
+;; Database
+
+(defn do-select [query]
+ (with-connection db
+ (with-query-results rs query
+ (doall rs))))
+
+(defn do-count [query]
+ ((first (with-connection db
+ (with-query-results rs query
+ (doall rs))))
+ :count))
+
+
+;; Stats
+
+(defn msg-stats [ts]
+ (let [qry (str "SELECT created_on::date, count(*) FROM messages "
+ "GROUP BY created_on::date "
+ "ORDER BY created_on::date")]
+ (do-select [qry])))
+
+(defn new-user-stats [ts]
+ (let [qry (str "SELECT created_on::date, count(*) FROM users "
+ "GROUP BY created_on::date "
+ "ORDER BY created_on::date")]
+ (do-select [qry])))
+
+(defn msgs-per-user-stats [ts]
+ true)
+
+(def *stat-map* {"msgs" msg-stats
+ "new users" new-user-stats
+ "msgs per user" msgs-per-user-stats})
+
+(defn stats [session params]
+ (let [stat (params :stat)
+ ts (params :timescale)]
+ (if-let [f (*stat-map* stat)]
+ (resp-success (f ts))
+ (resp-error "UNKNOWN STAT"))))
+
+(defn validated-stats [session params]
+ (if (session :is_admin)
+ (stats session params)
+ (resp-error "BAD_REQUEST"))) \ No newline at end of file
diff --git a/static/away.js b/static/away.js
index 36579ff..cf4b19c 100755
--- a/static/away.js
+++ b/static/away.js
@@ -5,6 +5,7 @@ var HasFocus = true;
function onFocus() {
HasFocus = true;
UnseenMsgCounter = 0;
+ $('title').text(OrigTitle);
}
function onBlur() {
diff --git a/static/browsertool.gif b/static/browsertool.gif
index e3dc960..9777d27 100644
--- a/static/browsertool.gif
+++ b/static/browsertool.gif
Binary files differ
diff --git a/static/cloudbar.png b/static/cloudbar.png
new file mode 100644
index 0000000..e4e6893
--- /dev/null
+++ b/static/cloudbar.png
Binary files differ
diff --git a/static/cloudbar2.png b/static/cloudbar2.png
new file mode 100644
index 0000000..ac4d1c8
--- /dev/null
+++ b/static/cloudbar2.png
Binary files differ
diff --git a/static/cloudbar3.png b/static/cloudbar3.png
new file mode 100644
index 0000000..aca0f05
--- /dev/null
+++ b/static/cloudbar3.png
Binary files differ
diff --git a/static/header.css b/static/header.css
index 1aa1d1c..5ad2fbc 100755
--- a/static/header.css
+++ b/static/header.css
@@ -73,17 +73,17 @@ margin-top:2;
color: #fff;
}
#logout7{
- top:-2px;
+ top:-1px;
position:relative;
font-size:12px;
- margin-right: 3px;
+ margin-right: 5px;
float:right;
z-index: 999;
font-family: Arial, Helvetica, sans-serif;
font-weight: normal;
}
-#logout7 a{font-size:11px;text-shadow: 1px 1px 4px #000;
+#logout7 a{font-size:11px;
}
#logout7 a:hover{font-size:11px;
}
diff --git a/static/index.html b/static/index.html
index c3006af..a7e896a 100755
--- a/static/index.html
+++ b/static/index.html
@@ -76,8 +76,8 @@ body {
}
#customer {
position: absolute;
- left: -80px;
- top: -65px;
+ left: -90px;
+ top: -75px;
z-index: 10;
}
diff --git a/static/js/home.js b/static/js/home.js
index 59d4c3d..60b5d07 100755
--- a/static/js/home.js
+++ b/static/js/home.js
@@ -5,7 +5,6 @@ function ifEnter(fn) {
}
function initLoginForm() {
-
var nick = "#nickInput", nickFiller = "username"
var pass = "#passwordInput", passLabel = "#passwordInputLabel", passFiller = "password"
var submit = "#signin-submit"
@@ -152,6 +151,8 @@ function login() {
var onSuccess = function(json) {
location.href = location.href;
+ if (typeof pageTracker !== 'undefined') {
+ pageTracker._setCustomVar(1, "logged-in", nick,
};
var onError = function(resp, textStatus, errorThrown) {
diff --git a/static/js/pichat.js b/static/js/pichat.js
index 06c859d..566bd10 100755
--- a/static/js/pichat.js
+++ b/static/js/pichat.js
@@ -1,24 +1,47 @@
var cache = {}
var pendingMessages = {}
+var MaxImagePosts = 40
+
function escapeHtml(txt) {
- if (!txt) { return ""; }
- else { return $("<span>").text(txt).html(); }
+ if (!txt) { return ""; }
+ else { return $("<span>").text(txt).html(); }
}
function linkify(text) {
- var URLRegex = /((\b(http\:\/\/|https\:\/\/|ftp\:\/\/)|(www\.))+(\w+:{0,1}\w*@)?(\S+)(:[0-9]+)?(\/|\/([\w#!:.?+=&%@!\-\/]))?)/gi;
- return text.replace(URLRegex, linkReplace);
+ LastMsgContainsImage = false
+ var URLRegex = /((\b(http\:\/\/|https\:\/\/|ftp\:\/\/)|(www\.))+(\w+:{0,1}\w*@)?(\S+)(:[0-9]+)?(\/|\/([\w#!:.?+=&%@!\-\/]))?)/gi;
+ return text.replace(URLRegex, linkReplace);
}
-function linkReplace(match){
- var PicRegex = /\.(jpg|jpeg|png|gif|bmp)$/i;
- var matchWithoutParams = match.replace(/\?.*$/i, "")
- if (PicRegex.test(matchWithoutParams)){
- return "<a target='_blank' href='" + match + "'><img src='" + match + "'></a>"
- } else {
- return "<a target='_blank' href='" + match + "'>" + match + "</a>"
- }
+// durty hack to use a global to check this... but otherwise i'd have to rewrite the String.replace function? :/
+var LastMsgContainsImage = false
+function linkReplace(url){
+ var PicRegex = /\.(jpg|jpeg|png|gif|bmp)$/i;
+ var urlWithoutParams = url.replace(/\?.*$/i, "");
+
+ linkUrl = url.indexOf('http://') == 0 ? url : 'http://' + url;
+
+ if (PicRegex.test(url)){
+ LastMsgContainsImage = true
+ return "<a target='_blank' href='" + linkUrl + "'><img src='" + linkUrl + "'></a>"
+ } else {
+ return "<a target='_blank' href='" + linkUrl + "'>" + url + "</a>"
+ }
+}
+
+var ImageMsgCount = 0
+function removeOldMessages(){
+ // don't count posts that are all text
+ if (LastMsgContainsImage) ImageMsgCount += 1;
+ while (ImageMsgCount > MaxImagePosts) {
+ var imgMsg = $(".contains-image:first")
+ if (imgMsg.length) {
+ imgMsg.prevAll().remove() // remove all text messages before the image message
+ imgMsg.remove()
+ } else break;
+ ImageMsgCount -= 1;
+ }
}
function buildMsgContent(content) {
@@ -26,16 +49,19 @@ function buildMsgContent(content) {
}
function buildMessageDiv(msg, isLoading) {
- var nick = escapeHtml(msg.nick);
- var msgId = !isLoading ? 'id="message-' + msg.msg_id + '"' : '';
- var loadingClass = isLoading ? ' loading' : '';
- return '<div class="msgDiv ' + loadingClass + '" ' + msgId + '>'
- + '<b><a href="/u/' + nick + ' ">' + nick + '</a>: </b>'
- + buildMsgContent(msg.content)
- + '</div>';
+ removeOldMessages()
+ var nick = escapeHtml(msg.nick);
+ var msgId = !isLoading ? 'id="message-' + msg.msg_id + '"' : '';
+ var loadingClass = isLoading ? ' loading' : '';
+ var containsImageClass = LastMsgContainsImage ? ' contains-image' : '';
+ return '<div class="msgDiv ' + loadingClass + containsImageClass + '" ' + msgId + '>'
+ + '<b><a href="/u/' + nick + ' ">' + nick + '</a>: </b>'
+ + buildMsgContent(msg.content)
+ + '</div>';
}
function buildUserDiv(user) {
+ console.warn(user);
if (user.avatar) {
return '<div class="username">'
+ '<a href="/u/' + escapeHtml(user.nick) + '" target="_blank">'
@@ -80,6 +106,9 @@ function submitMessage() {
var div = addNewMessage(msg, true);
var onSuccess = function(json) {
+ if (typeof pageTracker !== 'undefined') {
+ pageTracker._trackEvent('Message', 'Submit', typeof Room !== 'undefined' ? Room : 'UnknownRoom');
+ }
div.attr('id', 'message-' + json)
.removeClass('loading').addClass('loaded');
};
@@ -106,30 +135,12 @@ function ifEnter(fn) {
};
}
-/*
-function isScrolledToBottom(div) {
- return Math.abs(div.scrollTop - (div.scrollHeight - div.offsetHeight)) <= 3;
-}
-
-function scrollToBottom(div) {
- div.scrollTop = div.scrollHeight;
-}
-
-// Give images time to start loading before scrolling.
-// Needed until server knows size of images.
-function delayedScrollToBottom(delay) {
- setTimeout(scrollToBottom, delay, $('#messageList')[0]);
-}
-*/
-
function addNewMessages(msgs) {
- //var wasScrolledToBottom = isScrolledToBottom($('#messageList')[0]);
var msgStr = $.map(msgs, buildMessageDiv).join('');
$('#messageList').append(msgStr);
}
function addNewMessage(msg, isLoading) {
- //var wasScrolledToBottom = isScrolledToBottom($('#messageList')[0]);
var msgStr = buildMessageDiv(msg, isLoading);
var div = $(msgStr).appendTo('#messageList');
return div;
@@ -139,6 +150,14 @@ function setUserList(users) {
$("#userList").html($.map(users, buildUserDiv).join(''));
}
+function flattenUserJson(users) {
+ var s = "";
+ $.map(users.sort(), function(user) {
+ s += user.nick + user.avatar;
+ });
+ return s;
+}
+
function updateUI(msgs, users) {
if (window['growlize'] && msgs && msgs.length > 0) {
$.map(msgs, buildGrowlDataAndPopDatShit)
@@ -146,7 +165,8 @@ function updateUI(msgs, users) {
addNewMessages(msgs);
}
if (users !== null) {
- var flattened = users.sort().join(",")
+ var flattened = flattenUserJson(users);
+ console.log(flattened);
if (!('userlist' in cache) || flattened != cache.userlist) {
$("#userList").html($.map(users, buildUserDiv).join(''));
}
@@ -217,11 +237,17 @@ function initChat() {
// see /static/webcam/webcam.js
if ('webcam' in window) webcam.init()
-
setTimeout(refresh, 1000);
}
function initProfile() {
+
+ jQuery(".linkify").each(function() {
+ var text = jQuery(this).text();
+ jQuery(this).html(linkify(text));
+ });
+
+
$('.logged-dump .content').each(function() {
var t = $(this);
t.html(buildMsgContent(t.text()));
@@ -277,11 +303,24 @@ function initLog() {
function favoriteImage() {};
function setupUpload(elementId, roomKey) {
+ var onSubmit = function(file, ext) {
+ if (!(ext && /^(jpg|png|jpeg|gif)$/i.test(ext))) {
+ alert('Error: invalid file extension ' + ext);
+ return false;
+ }
+ };
+ var onComplete = function(file, response) {
+ if (typeof pageTracker !== 'undefined') {
+ pageTracker._trackEvent('Message', 'Upload', typeof Room !== 'undefined' ? Room : 'UnknownRoom');
+ }
+ }
new AjaxUpload(elementId, {
action: '/upload/message',
autoSubmit: true,
name: 'image',
- data: { room: roomKey }
+ data: { room: roomKey },
+ onSubmit: onSubmit,
+ onComplete: onComplete
});
}
@@ -329,7 +368,7 @@ function isScrolledToBottom(){
}
function scrollIfPossible(){
- if (lastScriptedScrolledPosition == messageList.scrollTop || isScrolledToBottom())
+ if (lastScriptedScrolledPosition <= messageList.scrollTop || isScrolledToBottom())
scrollToEnd()
}
diff --git a/static/js/register.js b/static/js/register.js
index 682efcb..1739ed6 100755
--- a/static/js/register.js
+++ b/static/js/register.js
@@ -13,20 +13,25 @@ function submitRegistration() {
var email = $('#emailInput').val();
var password = $('#passwordInput').val() || "";
var code = $('#codeInput').val();
- if ($.inArray(code.toUpperCase(), ValidCodes) == -1) {
- alert("Bad registration code! Try again dude...." );
- return;
- }
- if (nick.length < 3) {
- alert("Nicks must be at least 3 characters long.");
+
+ if (nick.length < 3 || nick.length > 12) {
+ alert("Nicks must be between 3 and 12 characters long.");
return;
} else if (password.length < 5) {
alert("Password must be at least 5 characters long.");
return;
}
+ if ($.inArray(code.toUpperCase(), ValidCodes) == -1) {
+ alert("Bad registration code! Try again dude...." );
+ return;
+ }
+
var hash = hex_sha1(nick + '$' + password + '$dumpfm');
var onSuccess = function() {
+ if (typeof pageTracker !== 'undefined') {
+ pageTracker._trackEvent('User', 'Register', nick);
+ }
location.href = "/";
};
diff --git a/static/js/stats.js b/static/js/stats.js
new file mode 100755
index 0000000..00e00a0
--- /dev/null
+++ b/static/js/stats.js
@@ -0,0 +1,79 @@
+var CurrentStats = ['msgs', 'today'];
+
+function refreshStats() {
+ $('a.statname, a.timescale').addClass('disabled');
+ $('#statschart').empty().append('<img src="/static/spinner.gif">');
+
+ var onSuccess = function(json) {
+ var dataString = "Date,Count\n";
+ $.each(json, function(i, v) {
+ dataString += v.created_on + "," + v.count + "\n";
+ });
+ $('#statschart').empty();
+ new Dygraph($('#statschart')[0],
+ dataString,
+ { showRoller: false}
+ );
+
+ $('a.statname, a.timescale').removeClass('disabled');
+ };
+
+ var onError = function(resp, textStatus, errorThrown) {
+ $('a.statname, a.timescale').removeClass('disabled');
+ };
+
+ $.ajax({
+ type: 'GET',
+ timeout: 5000,
+ url: '/stats',
+ data: { 'stat': CurrentStats[0], 'ts': CurrentStats[1] },
+ cache: false,
+ dataType: 'json',
+ success: onSuccess,
+ error: onError
+ });
+}
+
+function makeStatsWindow() {
+ var statBox= $('<div class="stats" align="center">');
+ var choices = ['msgs', 'new users'];
+ $(choices).map(function(i, c) {
+ return link = $('<a>')
+ .text(c)
+ .attr('href', '#')
+ .addClass('statname')
+ .addClass(i == 0 ? 'active' : 'inactive')
+ .click(function() {
+ if ($(this).hasClass('disabled') ||
+ CurrentStats[0] == c) { return };
+ $('.statname').removeClass('active');
+ $(this).addClass('active');
+ CurrentStats[0] = c;
+ refreshStats();
+ });
+ }).appendTo(statBox);
+ $('<div id="statschart" style="width:375px; height:300px;">').appendTo(statBox);
+ var timescales = ['today', 'all time'];
+ $(timescales).map(function(i, c) {
+ return link = $('<a>')
+ .text(c)
+ .attr('href', '#')
+ .addClass('timescale')
+ .addClass(i == 0 ? 'active' : 'inactive')
+ .click(function() {
+ if ($(this).hasClass('disabled') ||
+ CurrentStats[1] == c) { return };
+ $('.timescale').removeClass('active');
+ $(this).addClass('active');
+ CurrentStats[1] = c;
+ refreshStats();
+ });
+ })//.appendTo(statBox);
+ return statBox;
+}
+
+function initStats() {
+ makeStatsWindow().appendTo('body');
+ refreshStats();
+}
+
diff --git a/static/noinfo.png b/static/noinfo.png
new file mode 100644
index 0000000..a80724a
--- /dev/null
+++ b/static/noinfo.png
Binary files differ
diff --git a/static/pichat.css b/static/pichat.css
index 1e4a4f3..f01a150 100755
--- a/static/pichat.css
+++ b/static/pichat.css
@@ -117,22 +117,16 @@ filter: progid:DXImageTransform.Microsoft.dropShadow(color=#eee, offX=3, offY=4,
z-index:100;
}
#msginputrapper{
-margin-right:359;
+margin-right:374;
}
#msgSubmit {
- border-top-right-radius:10px;
- -webkit-border-top-right-radius:5px;
- -moz-border-radius-topright:5px;
- border-bottom-right-radius:5px;
- -webkit-border-bottom-right-radius:5px;
- -moz-border-radius-bottomright:5px;
- border-radius:5px;
+
position:absolute;
display:inline-block;
width:120px;
height:35px;
-right:240px;
+right:255px;
font-size:20px;
background-image:url(/static/urlbutton.png);
text-indent:27;
@@ -159,7 +153,7 @@ top:15px;
width:120px;
height:35px;
background-position:center;
-right:0;
+right:15;
top:15px;
padding-bottom:1;
text-indent:28;
@@ -186,17 +180,16 @@ background-image:url(/static/cambutton.png);
width:120px;
height:35px;
background-position:center;
-right:0;
+right:15;
top:15px;
-padding-bottom:1;
+padding-bottom:4;
text-align:center;
z-index:100;
cursor:pointer;
background-color:yellow;
- font-size:16px;
+ font-size:17px;
color:#fff;
background-image:url(/static/bg-btn-red.png);
-
text-shadow:1px 1px 3px rgba(0,0,0,1);
}
#webcam-button-snap.blink{
@@ -206,17 +199,37 @@ background-image:url(/static/bg-btn-red.png);
#webcam-button-close { /* 16 x 14 */
position: fixed;
- bottom: 300px; /* 240 + 68 - (16 / 2) */
- right: 313px; /* 320 - (14 / 2) */
+ bottom: 330px; /* 240 + 68 - (16 / 2) */
+ right: 335px; /* 320 - (14 / 2) */
z-index: 5001;
+border:1px solid #000;
+ box-shadow: 3px 4px 4px #c8cbce;
+-webkit-box-shadow: 3px 4px 4px #c8cbce;
+-moz-box-shadow: 3px 4px 4px #c8cbce;
cursor: pointer;
}
#webcam-preview {
position:fixed;
- bottom: 68px;
- right:0;
- z-index:5000
+ bottom: 82;
+opacity:0.9;
+ right:30;
+ box-shadow: 3px 4px 4px #c8cbce;
+-webkit-box-shadow: 3px 4px 4px #c8cbce;
+-moz-box-shadow: 3px 3px 4px #c8cbce;
+ border-top-right-radius:5px;
+ background-color:#FFF;
+ -webkit-border-top-right-radius:5px;
+ -moz-border-radius-topleft:5px;
+ -moz-border-radius-topright:5px;
+ border-bottom-left-radius:5px;
+ border-bottom-right-radius:5px;
+ -webkit-border-bottom-left-radius:5px;
+ -webkit-border-bottom-right-radius:5px;
+ -moz-border-radius-bottomleft:5px;
+ -moz-border-radius-bottomright:5px;
+border:1px solid #999;
+ z-index:5000;
}
#upload {
border-top-right-radius:10px;
@@ -231,7 +244,7 @@ background-image:url(/static/bg-btn-red.png);
width:120px;
height:35px;
background-position:center;
-right:120;
+right:135;
top:15px;
padding-bottom:1;
text-indent:24;
@@ -268,10 +281,10 @@ margin:-2;
position: absolute;
padding: 5px;
top:85px;
- min-width: 190px;
+ min-width: 200px;
width:11%;
float:right;
- right: 6%;
+ right: 6.2%;
font-family: Arial, Helvetica, sans-serif;
font-size: 14px;
font-weight:420;
diff --git a/static/profile.css b/static/profile.css
index 8aaafa8..8ee09d3 100755
--- a/static/profile.css
+++ b/static/profile.css
@@ -17,6 +17,18 @@ background-color:#fff;
line-height:1.5;
}
+#profile h3{
+margin-top:12;
+line-height:2;
+color:#fff;
+text-shadow: blue -2px -2px 0, red 2px 2px 0, green -6px 4px 0;
+}
+#profile h2{
+text-indent:-10;
+margin-top:-7;
+margin-bottom:15;
+}
+
#chatrap{
width:720;
@@ -309,6 +321,7 @@ font-size:60%;
top:80;
background-image:url(/static/welcomebar.gif);
}
+.invisible { display: none !important; }
body,td,th {
font-family: Arial, Helvetica, sans-serif;
background-color:#ffffee;
@@ -320,4 +333,4 @@ background-attachment:fixed;
-}@charset "UTF-8"; \ No newline at end of file
+}@charset "UTF-8";
diff --git a/static/search/browser.html b/static/search/browser.html
index c3f4766..11223ca 100755
--- a/static/search/browser.html
+++ b/static/search/browser.html
@@ -107,7 +107,7 @@ background-image:url(/static/bg-btn-blue.png);
<table class="search" width="425" border="0" cellpadding="5" cellspacing="0">
- <a href="#" id="about">optionz</a></div>
+ <a href="#" id="about">options</a></div>
</table>
diff --git a/static/tests/scrolling.html b/static/tests/scrolling.html
new file mode 100644
index 0000000..00e7b89
--- /dev/null
+++ b/static/tests/scrolling.html
@@ -0,0 +1,128 @@
+<html>
+<head>
+<script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.4/jquery.min.js"></script>
+<script>
+
+var imageQueue = []
+
+function fetch(){
+ $.ajax({
+ "url": "http://pipes.yahoo.com/pipes/pipe.run?_id=59b7cad3b8fb595fa7cb3c2fdf0ab328&_render=json&_callback=fetched",
+ "dataType": "jsonp"
+ })
+ log("fetching more images")
+}
+
+function fetched(data){
+ log("images fetched")
+ var imageUrls = []
+ try {
+ var images = data['value']['items'][0]['recent-images']['recent-image']
+ for(var i = 0; i < images.length; i++)
+ imageQueue.push(images[i]['img'])
+ } catch(e) {
+ console.log("couldn't parse object:")
+ console.log(data)
+ }
+}
+
+function log(m){
+ $("#log").html(m)
+}
+
+function go(){
+ messagePane = $("#chat")[0]
+ maxImages = $("#max-images")[0]
+ imagePoster()
+ scrollToEnd()
+ scrollWatcher()
+}
+
+function imagePoster(){
+ if (!imageQueue.length){
+ log("queue empty")
+ } else if (Paused) {
+ log("paused")
+ } else {
+ log(imageQueue.length + " images in queue ... posting image")
+ var image = imageQueue.shift()
+ imagePost(image)
+ }
+ setTimeout(imagePoster, 500)
+}
+
+imagePosts = 0
+function imagePost(image){
+ imagePosts += 1
+ while (imagePosts > maxImages.value) {
+ var imgs = $(".image-post:first")
+ if (imgs.length) {
+ imgs.remove()
+ } else {
+ break
+ }
+ imagePosts -= 1
+ }
+ var i = $("<img/>").attr("src", image) //.load(scrollIfPossible).error(scrollIfPossible)
+ var d = $("<div class='image-post'/>").html("username: ")
+ d.append(i).appendTo("#chat")
+}
+
+var Paused = false
+function pausego(){
+ Paused = !Paused
+ $("#pausego-button").html(Paused ? "go" : "pause")
+}
+
+function isScrolledToBottom(){
+ var threshold = 50;
+
+ var containerHeight = messagePane.style.pixelHeight || messagePane.offsetHeight
+ var currentHeight = (messagePane.scrollHeight > 0) ? messagePane.scrollHeight : 0
+
+ var result = (currentHeight - messagePane.scrollTop - containerHeight < threshold);
+
+ return result;
+}
+
+function scrollIfPossible(){
+ if (lastScriptedScrolledPosition <= messagePane.scrollTop || isScrolledToBottom())
+ scrollToEnd()
+}
+
+var lastScriptedScrolledPosition = 0
+function scrollToEnd(){
+ messagePane.scrollTop = messagePane.scrollHeight
+ lastScriptedScrolledPosition = messagePane.scrollTop
+}
+
+function scrollWatcher(){
+ scrollIfPossible()
+ setTimeout(scrollWatcher, 500)
+}
+
+</script>
+<style>
+ #chat { width: 500px; height: 90%; overflow: scroll; }
+ img { max-height: 300px; }
+</style>
+</head>
+<body>
+ <div id="chat">
+ test<br>test<br>test<br>test<br>test<br>test<br>test<br>test<br>test<br>test<br>test<br>
+ test<br>test<br>test<br>test<br>test<br>test<br>test<br>test<br>test<br>test<br>test<br>
+ test<br>test<br>test<br>test<br>test<br>test<br>test<br>test<br>test<br>test<br>test<br>
+ test<br>test<br>test<br>test<br>test<br>test<br>test<br>test<br>test<br>test<br>test<br>
+ test<br>test<br>test<br>test<br>test<br>test<br>test<br>test<br>test<br>test<br>test<br>
+ test<br>test<br>test<br>test<br>test<br>test<br>test<br>test<br>test<br>test<br>test<br>
+ </div>
+ <p id="log"></p>
+ <button onclick="fetch()">add images</button>
+ <button onclick="pausego()" id="pausego-button">pause</button>
+ <br />
+ max image posts: <input name="max-images" id="max-images" value="50" />
+</body>
+<script>
+ go()
+</script>
+</html> \ No newline at end of file
diff --git a/static/webcam/register.html b/static/webcam/register.html
new file mode 100644
index 0000000..4458f9c
--- /dev/null
+++ b/static/webcam/register.html
@@ -0,0 +1,233 @@
+</html><head>
+ <script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.4/jquery.min.js"></script>
+ <script type="text/javascript" src="/static/js/underscore-min.js"></script>
+ <script type="text/javascript" src="/static/js/sha1.js"></script>
+ <script type="text/javascript" src="static/js/register.js"></script>
+ <script>
+ $(document).ready(initRegister);
+ </script>
+ <link rel="stylesheet" type="text/css" href="static/reset.css">
+
+ <link rel="shortcut icon" href="static/favicon.ico">
+
+ <meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1"><title>dump.fm</title></head>
+
+
+<style type="text/css">
+
+
+
+
+
+
+<!--
+.white a:link {
+ text-decoration: none;
+ text-shadow: -1px 1px 1px #ccc;
+ color: #504F61;
+}
+.white a:visited {
+ text-decoration: none;
+ text-shadow: -1px 1px 1px #ccc;
+ color: #504F61;
+}
+.white a:hover {
+ text-decoration: none;
+ text-shadow: -1px 1px 1px #ccc;
+ background-color:#e3e3e3;
+
+ color: #fff;
+}
+.white a:active {
+ text-decoration: none;
+ text-shadow: -1px 1px 1px #ccc;
+ color: #504F61;
+}
+#main {
+ background-position:center;
+ width:460px;
+ margin: 0px auto -1px auto;
+ height:400px;
+padding-top:15;
+ z-index:2;
+ opacity:0.9;
+ border-top-left-radius:10px;
+ border-top-right-radius:10px;
+ -webkit-border-top-left-radius:10px;
+ -webkit-border-top-right-radius:10px;
+ -moz-border-radius-topleft:10px;
+ -moz-border-radius-topright:10px;
+ border-bottom-left-radius:10px;
+ border-bottom-right-radius:10px;
+ -webkit-border-bottom-left-radius:10px;
+ -webkit-border-bottom-right-radius:10px;
+ -moz-border-radius-bottomleft:10px;
+ -moz-border-radius-bottomright:10px;
+ border:solid 2px #000;
+ position: relative;
+ background-color: #FFF;
+ background-position:center;
+ background-repeat:no-repeat;
+ box-shadow: 5px 5px 100px #c8cbce;
+-webkit-box-shadow: 5px 5px 100px #c8cbce;
+-moz-box-shadow: 5px 5px 100px #c8cbce;
+}
+#logout7{
+ top:5px;
+ position:relative;
+ font-size:13px;
+ margin-right: 10px;
+ float:right;
+ z-index: 999;
+ font-family: "Times New Roman", Times, serif;
+}
+#logo7{
+ top:20px;
+ margin-left: 10%;
+ margin-right: 10%;
+ z-index:1000;
+ float:left;
+}
+#rapper7{
+ top: 0px;
+ left:0px;
+ position:absolute;
+ width: 100%;
+ height: 78px;
+ z-index: 1000;
+}
+#bottombar{
+ top: 69px;
+ left:0px;
+ position:absolute;
+ width: 100%;
+ height: 20px;
+ z-index: 1000;
+}
+p {
+ font-family: Arial, Helvetica, sans-serif;
+ font-size: 24px;
+}
+td {
+ font-family: Arial, Helvetica, sans-serif;
+ letter-spacing:-1px;
+ font-size: 12px;
+ color: #000000;
+}
+.btnav { border: 0px #000000 solid;}
+body {
+ background:#EEF2FF url(/static/fade-blue.png) top center repeat-x;
+ background-repeat:repeat-x;
+ background-position:top;
+ overflow:hidden;
+margin:8%;
+}
+body a{border:0;
+text-decoration:none;
+}
+.submit {
+
+
+ text-shadow: -1px 1px 1px #ccc;
+
+ font-size:15px;
+}
+.feild {
+ height:40px;
+ width:300px;
+ border:3px #000;
+ background:#e3e3e3;
+ margin:10px;
+ color:#000;
+
+ font-size:30px;
+
+}
+.txt {
+ font-family:Arial, Helvetica, sans-serif;
+ font-size:14px;
+line-height:1.2;
+ text-shadow:1px 1px 0.5px #ccc;
+ word-spacing: 3px;
+}
+ .line {
+ font-family:Arial, Helvetica, sans-serif;
+ letter-spacing: 1px;
+line-height:1;
+ text-shadow:0px 1px 50px #999;
+ color:#000;
+ font-size:19px;
+}
+#nickInput {color:#000;
+}
+.no-cursor { cursor: none; }
+.invisible { display: none !important; }
+#cursor-big { position: absolute; z-index: 1000; }
+
+#submit {
+
+
+ display:inline-block;
+ width:300px;
+height:35px;
+margin-top:-5;
+font-size:14px;
+background-image:url(/static/btngrad1.png);
+margin-left:140;
+top:15px;
+ text-align:center;
+ z-index:100;
+ font-size:18px;
+ color:#fff;
+ text-shadow:1px 1px 1px rgba(0,0,0,1);
+ border-top-left-radius:5px;
+ border-top-right-radius:5px;
+ -webkit-border-top-left-radius:5px;
+ -webkit-border-top-right-radius:5px;
+ -moz-border-radius-topleft:5px;
+ -moz-border-radius-topright:5px;
+ border-bottom-left-radius:5px;
+ border-bottom-right-radius:5px;
+ -webkit-border-bottom-left-radius:5px;
+ -webkit-border-bottom-right-radius:5px;
+ -moz-border-radius-bottomleft:5px;
+ -moz-border-radius-bottomright:5px;
+ border:solid 1px #fff;
+}
+
+-->
+
+
+
+
+
+
+
+</style>
+
+<body>
+<div id="rapper7">
+<div id="header7">
+ <div id="bottombar"></div>
+ <div align="center">
+<br>
+ </div>
+
+ <div class="white"></div>
+ <div align="center"><br /></div>
+</div>
+</div>
+</div>
+<div id="main" align="center">
+<h1>
+Sorry, registration is closed, come back tomorrow
+</h1>
+ </div>
+ </div>
+ </div>
+</div>
+
+
+
+</body>
+</html>
diff --git a/static/webcam/webcam.js b/static/webcam/webcam.js
index 9829fd7..3e3b4fd 100644
--- a/static/webcam/webcam.js
+++ b/static/webcam/webcam.js
@@ -1,21 +1,11 @@
/* JPEGCam v1.0.8 */
/* Webcam library for capturing JPEG images and submitting to a server */
-/* Copyright (c) 2008 - 2009 Joseph Huckaby <jhuckaby@goldcartridge.com> */
+/* Copyright (c) 2008 - 2009
+ Joseph Huckaby <jhuckaby@goldcartridge.com>
+ AND TIMB, ESQ. <http://bon.gs> */
/* Licensed under the GNU Lesser Public License */
/* http://www.gnu.org/licenses/lgpl.html */
-/* Usage:
- <script language="JavaScript">
- document.write( webcam.get_html(320, 240) );
- webcam.set_api_url( 'test.php' );
- webcam.set_hook( 'onComplete', 'my_callback_function' );
- function my_callback_function(response) {
- alert("Success! PHP returned: " + response);
- }
- </script>
- <a href="javascript:void(webcam.snap())">Take Snapshot</a>
-*/
-
// Everything is under a 'webcam' Namespace
window.webcam = {
version: '1.0.8',
@@ -47,6 +37,9 @@ window.webcam = {
},
uploadCompleted: function(){
+ if (typeof pageTracker !== 'undefined') {
+ pageTracker._trackEvent('Message', 'Webcam', typeof Room !== 'undefined' ? Room : 'UnknownRoom');
+ }
$("#webcam-button-snap").attr("value", "Send Pic")
webcam.reset();
},
diff --git a/template/banner.st b/template/banner.st
index a857628..c67bafa 100755
--- a/template/banner.st
+++ b/template/banner.st
@@ -15,7 +15,7 @@
<li><div id="lastli"><a href="/">.</a></div></li>
<li><a href="/log"><img src="/static/text.gif" > Log</a></li>
<li><a href="/u/$user_nick$"><img src="/static/home4.gif"/> Profile</a></li>
- <li><a href="/browser"><img src="/static/image_draw.gif" /> Browser Tool</a></li>
+ <li><a href="/browser"><img src="/static/image_draw.gif" /> Image Search</a></li>
</ul>
$else$&nbsp; &nbsp;
<a href="/register"><img src="/static/answer_good.gif" />Register</a>
diff --git a/template/browser.st b/template/browser.st
index 26dcb8b..e172d15 100755
--- a/template/browser.st
+++ b/template/browser.st
@@ -1,6 +1,6 @@
<html>
<head>
- <title>dump.fm | Browser Tool Beta</title>
+ <title>dump.fm | Image Search Beta</title>
$head()$
<link rel="stylesheet" type="text/css" href="/static/browser.css">
<script type="text/javascript" src="/static/gritter/js/jquery.gritter.js"></script>
diff --git a/template/chat.st b/template/chat.st
index 90e2602..2c0f15f 100755
--- a/template/chat.st
+++ b/template/chat.st
@@ -16,36 +16,13 @@
$endif$
</script>
<script type="text/javascript">
-<!--
-function MM_swapImgRestore() { //v3.0
- var i,x,a=document.MM_sr; for(i=0;a&&i<a.length&&(x=a[i])&&x.oSrc;i++) x.src=x.oSrc;
-}
-function MM_preloadImages() { //v3.0
- var d=document; if(d.images){ if(!d.MM_p) d.MM_p=new Array();
- var i,j=d.MM_p.length,a=MM_preloadImages.arguments; for(i=0; i<a.length; i++)
- if (a[i].indexOf("#")!=0){ d.MM_p[j]=new Image; d.MM_p[j++].src=a[i];}}
-}
-
-function MM_findObj(n, d) { //v4.01
- var p,i,x; if(!d) d=document; if((p=n.indexOf("?"))>0&&parent.frames.length) {
- d=parent.frames[n.substring(p+1)].document; n=n.substring(0,p);}
- if(!(x=d[n])&&d.all) x=d.all[n]; for (i=0;!x&&i<d.forms.length;i++) x=d.forms[i][n];
- for(i=0;!x&&d.layers&&i<d.layers.length;i++) x=MM_findObj(n,d.layers[i].document);
- if(!x && d.getElementById) x=d.getElementById(n); return x;
-}
-
-function MM_swapImage() { //v3.0
- var i,j=0,x,a=MM_swapImage.arguments; document.MM_sr=new Array; for(i=0;i<(a.length-2);i+=3)
- if ((x=MM_findObj(a[i]))!=null){document.MM_sr[j++]=x; if(!x.oSrc) x.oSrc=x.src; x.src=a[i+2];}
-}
-//-->
</script>
$if(isadminroom)$
<style>
iframe {
z-index: 50000;
position: fixed;
- top: 300px;
+ top: 200px;
right: 25px;
}
</style>
diff --git a/template/form_login.st b/template/form_login.st
index 8b126ff..ad61bbb 100644
--- a/template/form_login.st
+++ b/template/form_login.st
@@ -18,7 +18,7 @@
<p>
<label>
- <input type="checkbox" name="rememberme" id="remembermeInput" />
+ <input type="checkbox" name="rememberme" id="remembermeInput" checked="checked"/>
Remember Me
</label>
</p>
diff --git a/template/profile.st b/template/profile.st
index 071b888..b5d3f38 100755
--- a/template/profile.st
+++ b/template/profile.st
@@ -10,16 +10,11 @@
<script type="text/javascript" src="/static/jquery.editinplace.1.0.1.packed.js"></script>
<link type="text/css" href="http://jqueryui.com/latest/themes/base/ui.all.css" rel="stylesheet" />
- <script type="text/javascript" src="http://jqueryui.com/latest/ui/ui.core.js"></script>
- <script type="text/javascript" src="http://jqueryui.com/latest/ui/ui.datepicker.js"></script>
+
<script>
jQuery(document).ready(function(){
initProfile();
- jQuery(".linkify").each(function() {
- var text = jQuery(this).text();
- jQuery(this).html(linkify(text));
- });
});
</script>
@@ -46,7 +41,7 @@
$if(avatar)$
<img id="avatarPic" src="$avatar$" width="150px"/>
$else$
- <b id="avatarPic">No avatar</b>
+ <b id="avatarPic"><img src="/static/noinfo.png"></b>
$endif$
$if(is_home)$
@@ -63,20 +58,21 @@
<h3>contact info</h3>
<div id="contact" class="linkify">$contact$</div>
$else$
- <div>No contact info</div>
+ <br><br>
+ <div><img src="/static/noinfo.png"></div>
$endif$
<br>
$if(is_home)$
- <h3>biography</h3>
+ <h3>bio</h3>
<div id="bio" class="editable">$bio$</div>
- $elseif(contact)$
- <h3>biography</h3>
+ $elseif(bio)$
+ <h3>bio</h3>
<div id="bio" class="linkify">$bio$</div>
$else$
- <div>No bio</div>
+ <div><img src="/static/noinfo.png"></div>
$endif$
@@ -146,6 +142,7 @@
$footer()$
</div>
</div>
- </div></div>
+ </div></div></div>
+$preload()$
</body>
</html>