var cache = {} var pendingMessages = {} function escapeHtml(txt) { if (!txt) { return ""; } else { return $("").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); } function linkReplace(match){ var PicRegex = /\.(jpg|jpeg|png|gif|bmp)$/i; var matchWithoutParams = match.replace(/\?.*$/i, "") if (PicRegex.test(matchWithoutParams)){ return "" } else { return "" + match + "" } } function buildMsgContent(content) { return linkify(escapeHtml(content)); } function buildMessageDiv(msg, isLoading) { var nick = escapeHtml(msg.nick); var msgId = !isLoading ? 'id="message-' + msg.msg_id + '"' : ''; var loadingClass = isLoading ? ' loading' : ''; return '
' + '' + nick + ': ' + buildMsgContent(msg.content) + '
'; } function buildUserDiv(user) { if (user.avatar) { return '
' + '' + '' + escapeHtml(user.nick) + '
'; } else { return '
' + '' + escapeHtml(user.nick) + '
'; } } function buildGrowlDataAndPopDatShit(msg) { var nick = escapeHtml(msg.nick); nick = '' + nick + ':' var msg = buildMsgContent(msg.content) growl(nick, msg) } function growl(user, msg) { $.gritter.add({title: user, text: msg}); } function handleMsgError(resp) { var respText = resp.responseText ? resp.responseText.trim() : false; if (respText == 'MUST_LOGIN') { alert("Can't send message! Please login."); } else if (respText) { alert("Can't send message! (" + respText + ")"); } else { alert("Can't send message!"); } } function submitMessage() { var content = $.trim($('#msgInput').val()); $('#msgInput').val(''); if (content == '') { return; } pendingMessages[content] = true; var msg = { 'nick': Nick, 'content': content }; var div = addNewMessage(msg, true); var onSuccess = function(json) { div.attr('id', 'message-' + json) .removeClass('loading').addClass('loaded'); }; var onError = function(resp, textStatus, errorThrown) { div.remove(); handleMsgError(resp); }; $.ajax({ type: 'POST', timeout: 5000, url: '/msg', data: { 'room': Room, '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; } // 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; } function setUserList(users) { $("#userList").html($.map(users, buildUserDiv).join('')); } function updateUI(msgs, users) { if (window['growlize'] && msgs && msgs.length > 0) { $.map(msgs, buildGrowlDataAndPopDatShit) } else if (msgs && msgs.length > 0) { addNewMessages(msgs); } if (users !== null) { var flattened = users.sort().join(",") if (!('userlist' in cache) || flattened != cache.userlist) { $("#userList").html($.map(users, buildUserDiv).join('')); } cache.userlist = flattened } } function isDuplicateMessage(m) { if (m.nick == Nick && m.content in pendingMessages) { delete pendingMessages[m.content]; return true; } else { return false; } } function refresh() { var onSuccess = function(json) { try { Timestamp = json.timestamp; var messages = $.grep( json.messages, function(m) { return !isDuplicateMessage(m) }); updateUI(messages, json.users); if (typeof UnseenMsgCounter !== 'undefined' && !HasFocus) { UnseenMsgCounter += messages.length; } } catch(e) { if (IsAdmin && window.console) { console.error(e); } } setTimeout(refresh, 1000); }; var onError = function(resp, textStatus, errorThrown) { if (IsAdmin && window.console) { console.error(resp, textStatus, errorThrown); } setTimeout(refresh, 1000); }; $.ajax({ type: 'GET', timeout: 5000, url: '/refresh', data: { 'room': Room, 'since': Timestamp }, cache: false, dataType: 'json', success: onSuccess, error: onError }); } function initChat() { $('.msgDiv .content').each(function() { var t = $(this); t.html(buildMsgContent(t.text())); }); $('#msgInput').keyup(ifEnter(submitMessage)); $('#msgSubmit').click(submitMessage); messageList = $("#messageList")[0] scrollToEnd() scrollWatcher() setTimeout(refresh, 1000); } function initProfile() { $('.logged-dump .content').each(function() { var t = $(this); t.html(buildMsgContent(t.text())); }); var onSubmit = function(attr, newVal, oldVal) { newVal = $.trim(newVal); if (newVal == oldVal) { return oldVal }; $.ajax({ type: "POST", timeout: 5000, url: "/update-profile", data: { 'attr': attr, 'val': newVal } }); if (attr == 'avatar') { if (newVal != "") { var s = ''; $('#avatarPic').replaceWith(s).show(); } else { $('#avatarPic').hide(); } } return escapeHtml(newVal); }; var avatarOpts = { 'default_text': 'Enter here!', 'callback': onSubmit, 'field_type': 'text', 'callbackShowErrors': false }; $('#avatar.editable').editInPlace(avatarOpts); var textareaOpts = { 'default_text': 'Enter here!', 'callback': onSubmit, 'field_type': 'textarea', 'callbackShowErrors': false }; $('#contact.editable, #bio.editable').editInPlace(textareaOpts); }; function initLog() { $('.logged-dump .content').each(function() { var t = $(this); t.html(buildMsgContent(t.text())); }); } // TODO function favoriteImage() {}; function setupUpload(elementId, roomKey) { new AjaxUpload(elementId, { action: '/upload', autoSubmit: true, name: 'image', data: { room: roomKey } }); } // scrolling stuff // this code keeps the div scrolled to the bottom, but will also let the user scroll up, without jumping down function isScrolledToBottom(){ var threshold = 15; var containerHeight = messageList.style.pixelHeight || messageList.offsetHeight var currentHeight = (messageList.scrollHeight > 0) ? messageList.scrollHeight : 0 var result = (currentHeight - messageList.scrollTop - containerHeight < threshold); return result; } function scrollIfPossible(){ if (lastScriptedScrolledPosition == messageList.scrollTop || isScrolledToBottom()) scrollToEnd() } var lastScriptedScrolledPosition = 0 function scrollToEnd(){ messageList.scrollTop = messageList.scrollHeight lastScriptedScrolledPosition = messageList.scrollTop } function scrollWatcher(){ scrollIfPossible() setTimeout(scrollWatcher, 500) }