function escapeHtml(txt) { if (!txt) { return ""; } else { return $("").text(txt).html(); } } // 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,"$1"); } // http://snippets.dzone.com/posts/show/6995 var URLRegex = /^((http\:\/\/|https\:\/\/|ftp\:\/\/)|(www\.))+(\w+:{0,1}\w*@)?(\S+)(:[0-9]+)?(\/|\/([\w#!:.?+=&%@!\-\/]))?$/i var PicRegex = /\.(jpg|jpeg|png|gif|bmp)$/i; function isImage(content) { var match = URLRegex.exec(content); sansParams = match && match[0].replace(/\?.*$/i, ""); return sansParams && PicRegex.test(sansParams); } function buildMsgContent(content) { if (isImage(content)) { return '' + ''; } else { return linkify(escapeHtml(content)); } } function buildMessageDiv(msg) { var nick = escapeHtml(msg.nick); return '
' + nick + ': ' + buildMsgContent(msg.content) + '
'; } function buildGrowlDataAndPopDatShit(msg) { var nick = escapeHtml(msg.nick); nick = '' + nick + ':' var msg = buildMsgContent(msg.content) growl(nick, msg) } function buildUserDiv(user) { if (user.avatar) { return '
' + '' + escapeHtml(user.nick) + '
'; } else { return '
' + escapeHtml(user.nick) + '
'; } } 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()); if (content == '') { return; } PostedMessages.push(content); $('#msgInput').val(''); updateUI([{ 'nick': Nick, 'content': content}], null); var onSuccess = function(json) {}; var onError = function(resp, textStatus, errorThrown) { $('#msgInput, #msgSubmit').removeAttr('disabled'); handleMsgError(resp); }; $.ajax({ type: 'GET', 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 updateUI(msgs, users) { if (window['growlize'] && msgs !== null) { $.map(msgs, buildGrowlDataAndPopDatShit) } else if (msgs !== null) { var msgStr = $.map(msgs, buildMessageDiv).join(''); var wasScrolledToBottom = isScrolledToBottom($('#messageList')[0]); $('#messageList').append(msgStr); if (wasScrolledToBottom) { delayedScrollToBottom(500); } } if (users !== null) { $("#userList").html($.map(users, buildUserDiv).join('')); } } // A duplicate message is a message that was likely to have // originated from this browser. function isDuplicateMessage(m) { if (m.nick != Nick || $.inArray(m.content, PostedMessages) == -1) { return false; } var now = new Date().getTime(); return m.created_on - now < 5000; } 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') { UnseenMsgCounter += messages.length; } } catch(e) { if (IsAdmin) { alert("Exception in refresh"); console.log(e); } } setTimeout(refresh, 1000); }; var onError = function(resp, textStatus, errorThrown) { if (IsAdmin) { console.log(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); delayedScrollToBottom(500); setTimeout(refresh, 1000); } function initProfile() { $('.logged-dump .content').each(function() { var t = $(this); t.html(buildMsgContent(t.text())); }); var onSubmit = function(original_element, edit, old) { edit = $.trim(edit); if (edit == old) { return old }; // TODO: Prevent entering script tags if (original_element == 'avatar' && edit.indexOf("<") != -1) { return old; } $.ajax({ type: "GET", timeout: 5000, url: "/update-profile", data: { 'attr': original_element, 'val': edit } }); if (original_element == 'avatar') { var s = ''; $('#avatarPic').replaceWith(s); } return escapeHtml(edit); }; var opt = { 'default_text': 'Enter here!', 'callback': onSubmit, 'field_type': 'text', 'callbackShowErrors': false }; $('#avatar.editable').editInPlace(opt); opt['field_type'] = 'textarea'; $('#contact.editable, #bio.editable').editInPlace(opt); }; function initLog() { $('.logged-dump .content').each(function() { var t = $(this); t.html(buildMsgContent(t.text())); }); } function growl(user, msg) { $.gritter.add({ // (string | mandatory) the heading of the notification title: user, // (string | mandatory) the text inside the notification text: msg }); }