// http://plugins.jquery.com/files/jquery.cookie.js.txt jQuery.cookie=function(name,value,options){if(typeof value!='undefined'){options=options||{};if(value===null){value='';options.expires=-1;} var expires='';if(options.expires&&(typeof options.expires=='number'||options.expires.toUTCString)){var date;if(typeof options.expires=='number'){date=new Date();date.setTime(date.getTime()+(options.expires*24*60*60*1000));}else{date=options.expires;} expires='; expires='+date.toUTCString();} var path=options.path?'; path='+(options.path):'';var domain=options.domain?'; domain='+(options.domain):'';var secure=options.secure?'; secure':'';document.cookie=[name,'=',encodeURIComponent(value),expires,path,domain,secure].join('');}else{var cookieValue=null;if(document.cookie&&document.cookie!=''){var cookies=document.cookie.split(';');for(var i=0;i 16) bkey = SHA1.binb(bkey, key.length * 8); var ipad = Array(16), opad = Array(16); for(var i = 0; i < 16; i++){ ipad[i] = bkey[i] ^ 0x36363636; opad[i] = bkey[i] ^ 0x5C5C5C5C; } var hash = SHA1.binb(ipad.concat(SHA1.rstr2binb(data)), 512 + data.length * 8); return SHA1.binb2rstr(SHA1.binb(opad.concat(hash), 512 + 160)); }, "rstr2hex": function(input){ try { SHA1.hexcase } catch(e) { SHA1.hexcase=0; } var hex_tab = SHA1.hexcase ? "0123456789ABCDEF" : "0123456789abcdef"; var output = ""; var x; for(var i = 0; i < input.length; i++){ x = input.charCodeAt(i); output += hex_tab.charAt((x >>> 4) & 0x0F) + hex_tab.charAt( x & 0x0F); } return output; }, "rstr2b64": function(input){ try { SHA1.b64pad } catch(e) { SHA1.b64pad=''; } var tab = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; var output = ""; var len = input.length; for(var i = 0; i < len; i += 3){ var triplet = (input.charCodeAt(i) << 16) | (i + 1 < len ? input.charCodeAt(i+1) << 8 : 0) | (i + 2 < len ? input.charCodeAt(i+2) : 0); for(var j = 0; j < 4; j++){ if(i * 8 + j * 6 > input.length * 8) output += SHA1.b64pad; else output += tab.charAt((triplet >>> 6*(3-j)) & 0x3F); } } return output; }, "rstr2any": function(input, encoding){ var divisor = encoding.length; var remainders = Array(); var i, q, x, quotient; var dividend = Array(Math.ceil(input.length / 2)); for(i = 0; i < dividend.length; i++) dividend[i] = (input.charCodeAt(i * 2) << 8) | input.charCodeAt(i * 2 + 1); while(dividend.length > 0){ quotient = Array(); x = 0; for(i = 0; i < dividend.length; i++){ x = (x << 16) + dividend[i]; q = Math.floor(x / divisor); x -= q * divisor; if(quotient.length > 0 || q > 0) quotient[quotient.length] = q; } remainders[remainders.length] = x; dividend = quotient; } var output = ""; for(i = remainders.length - 1; i >= 0; i--) output += encoding.charAt(remainders[i]); var full_length = Math.ceil(input.length * 8 / (Math.log(encoding.length) / Math.log(2))) for(i = output.length; i < full_length; i++) output = encoding[0] + output; return output; }, "str2rstr_utf8": function(input){ var output = ""; var i = -1; var x, y; while(++i < input.length){ x = input.charCodeAt(i); y = i + 1 < input.length ? input.charCodeAt(i + 1) : 0; if(0xD800 <= x && x <= 0xDBFF && 0xDC00 <= y && y <= 0xDFFF){ x = 0x10000 + ((x & 0x03FF) << 10) + (y & 0x03FF); i++; } if(x <= 0x7F) output += String.fromCharCode(x); else if(x <= 0x7FF) output += String.fromCharCode(0xC0 | ((x >>> 6 ) & 0x1F), 0x80 | ( x & 0x3F)); else if(x <= 0xFFFF) output += String.fromCharCode(0xE0 | ((x >>> 12) & 0x0F), 0x80 | ((x >>> 6 ) & 0x3F), 0x80 | ( x & 0x3F)); else if(x <= 0x1FFFFF) output += String.fromCharCode(0xF0 | ((x >>> 18) & 0x07), 0x80 | ((x >>> 12) & 0x3F), 0x80 | ((x >>> 6 ) & 0x3F), 0x80 | ( x & 0x3F)); } return output; }, "str2rstr_utf16le": function(input){ var output = ""; for(var i = 0; i < input.length; i++) output += String.fromCharCode( input.charCodeAt(i) & 0xFF, (input.charCodeAt(i) >>> 8) & 0xFF); return output; }, "str2rstr_utf16be": function(input){ var output = ""; for(var i = 0; i < input.length; i++) output += String.fromCharCode((input.charCodeAt(i) >>> 8) & 0xFF, input.charCodeAt(i) & 0xFF); return output; }, "rstr2binb": function(input){ var output = Array(input.length >> 2); for(var i = 0; i < output.length; i++) output[i] = 0; for(var i = 0; i < input.length * 8; i += 8) output[i>>5] |= (input.charCodeAt(i / 8) & 0xFF) << (24 - i % 32); return output; }, "binb2rstr": function(input){ var output = ""; for(var i = 0; i < input.length * 32; i += 8) output += String.fromCharCode((input[i>>5] >>> (24 - i % 32)) & 0xFF); return output; }, "binb": function(x, len){ x[len >> 5] |= 0x80 << (24 - len % 32); x[((len + 64 >> 9) << 4) + 15] = len; var w = Array(80); var a = 1732584193; var b = -271733879; var c = -1732584194; var d = 271733878; var e = -1009589776; for(var i = 0; i < x.length; i += 16){ var olda = a; var oldb = b; var oldc = c; var oldd = d; var olde = e; for(var j = 0; j < 80; j++){ if(j < 16) w[j] = x[i + j]; else w[j] = SHA1.bit_rol(w[j-3] ^ w[j-8] ^ w[j-14] ^ w[j-16], 1); var t = SHA1.safe_add(SHA1.safe_add(SHA1.bit_rol(a, 5), SHA1.ft(j, b, c, d)), SHA1.safe_add(SHA1.safe_add(e, w[j]), SHA1.kt(j))); e = d; d = c; c = SHA1.bit_rol(b, 30); b = a; a = t; } a = SHA1.safe_add(a, olda); b = SHA1.safe_add(b, oldb); c = SHA1.safe_add(c, oldc); d = SHA1.safe_add(d, oldd); e = SHA1.safe_add(e, olde); } return Array(a, b, c, d, e); }, "ft": function(t, b, c, d){ if(t < 20) return (b & c) | ((~b) & d); if(t < 40) return b ^ c ^ d; if(t < 60) return (b & c) | (b & d) | (c & d); return b ^ c ^ d; }, "kt": function(t){ return (t < 20) ? 1518500249 : (t < 40) ? 1859775393 : (t < 60) ? -1894007588 : -899497514; }, "safe_add": function(x, y){ var lsw = (x & 0xFFFF) + (y & 0xFFFF); var msw = (x >> 16) + (y >> 16) + (lsw >> 16); return (msw << 16) | (lsw & 0xFFFF); }, "bit_rol": function(num, cnt) { return (num << cnt) | (num >>> (32 - cnt)) } } // The root domain is used so that subdomains don't result in // spurious extra urls (e.g. both dump.fm/nick and sub.dump.fm/nick) window.RootDomain = location.href.match(/http:\/\/(\w)+\./) ? 'http://dump.fm/' : '/'; window.cache = {}; window.PendingMessages = {}; window.MessageContentCache = {}; window.RawFavs = {}; window.MaxImagePosts = 30; // todo: preload these. also, look into image sprites (no go on animating their sizes tho) // css clipping perhaps? window.Imgs = { "chatThumb": "/static/img/thumbs/smallheartfaved.gif", "chatThumbBig": "/static/img/thumbs/chatheartover.gif", "chatThumbOff": "/static/img/thumbs/smallheart.gif", "chatThumbDot": "/static/img/thumbs/smallheart.gif", "logThumb": "/static/img/thumbs/heartfaved.gif", "logThumbBig": "/static/img/thumbs/heartover.gif", "logThumbOff": "/static/img/thumbs/heart.gif" } window.Anim = { "chatThumbBig": {"width": "54px", "height": "54px", "right": "0px", "bottom": "2px"}, "chatThumbTiny": {"width": "16px", "height": "16px", "right": "8px", "bottom": "8px"}, "chatThumb": {"width": "16px", "height": "16px", "right": "4px", "bottom": "4px"}, "logThumb": {"width": "27px", "height": "27px", "marginRight": "0px", "marginTop": "0px"}, "logThumbBig": {"width": "64px", "height": "64px", "marginRight": "-2px", "marginTop": "-2px"} } window.Preferences = { "Domain": '.dump.fm', "getProperty": function(prop, defaultValue) { var value = $.cookie(prop); return (value !== null) ? value : defaultValue; }, "setProperty": function(prop, val) { $.cookie(prop, val, { domain: Preferences.Domain, path: '/' }); }, "delProperty": function(prop) { $.cookie(prop, null, { domain: Preferences.Domain, path: '/' }); } }; window.Away = { "UnseenMsgCounter": 0, "OrigTitle": "", "HasFocus": true, "UpdateFrequency": 3000, "onFocus": function() { Away.HasFocus = true; Away.UnseenMsgCounter = 0; // Courtesy http://stackoverflow.com/questions/2952384/changing-the-window-title-when-focussing-the-window-doesnt-work-in-chrome window.setTimeout(function () { $('title').text(Away.OrigTitle); }, 100); }, "onBlur": function() { Away.HasFocus = false; }, "updateTitle": function () { if (Away.UnseenMsgCounter > 0) { var plural = Away.UnseenMsgCounter > 1 ? 's' : ''; $('title').text(Away.UnseenMsgCounter + ' new dump' + plural + '! | ' + Away.OrigTitle); } setTimeout(Away.updateTitle, Away.UpdateFrequency); }, "startTitleUpdater": function() { Away.OrigTitle = $('title').text(); $(window).blur(Away.onBlur); $(window).focus(Away.onFocus); setTimeout(Away.updateTitle, Away.UpdateFrequency); } }; // Called on loading a chatroom function initChat() { Search.initInpage() $('#textbutton input').attr('checked', TextEnabled).change(setTextEnable); $('#imgbutton input').attr('checked', ImgsEnabled).change(setImgsEnable); /* $('#clearbutton input').click(function() { track('UI', 'ClearScreen'); $('.dump').remove(); $(this).removeAttr('checked'); return false; }); */ $('.oldmsg').each(function() { var dump = $(this); var content = dump.find(".content") MessageContentCache[dump.attr("id").substr(8)] = content.text() content.html(buildMsgContent(content.text(), Recips)); if ((ImgsEnabled && dump.hasClass('contains-image')) || (TextEnabled && !dump.hasClass('contains-image'))) dump.show(); else dump.hide(); }); Drag.bindImages(); $('#msgInput').keyup(ifEnter(submitMessage)); $('#msgSubmit').click(sendClicked); $('#palette-button').click(paletteClicked); messageList = $("#messageList")[0] initChatThumb(); scrollToEnd() scrollWatcher() // see /static/webcam/webcam.js if ('webcam' in window) webcam.init() startChatUpdater(); } window.imgZoomThreshhold = [125, 125]; function initChatMsgs() { $('.msgDiv .content').live('mouseenter', function(e) { $(this).addClass('msg-hover'); }); $('.msgDiv .content').live('mouseleave', function(e) { $(this).removeClass('msg-hover'); }); $('.msgDiv .content .img-wrapper').live('mouseenter', function(e) { var img = $(this).find('img'); if (img.width() < imgZoomThreshhold[0] || img.height() < imgZoomThreshhold[1]) return; var zoomlink = $('') .attr({'href': img.attr('src') }) .addClass('msg-image-zoom') .append($('').attr('src', 'http://dump.fm/static/img/zoom.gif') .addClass('zoom-icon')) .click(function() { window.open(img.attr('src')); return false; }); $(this).append(zoomlink); }); $('.msgDiv .content .img-wrapper').live('mouseleave', function(e) { $(this).find('.msg-image-zoom').remove(); }); $('.content').live('click', function(e) { var tagName = e.target.tagName; if (tagName == 'A' || tagName == 'EMBED' || $(e.target).hasClass('youtube-thumb')) { return true; } var msg = $(this).parent('.msgDiv'); var wasFavorited = msg.hasClass("favorite"); var button = msg.find('.chat-thumb'); if (wasFavorited) { $(button).attr("src", Imgs.chatThumbOff); } else { $(button).attr("src", Imgs.chatThumbBig); $(button).stop().animate(Anim.chatThumbBig, 'fast').animate(Anim.chatThumb, 'fast', 'swing'); } Tag.favorite(button); return false; }); } function startChatUpdater() { setTimeout(refresh, 1000); } function makePlainText() { var j = $(this); j.text(j.text()); } function initChatThumb(){ $(".chat-thumb").live('mouseover mouseout', function(e) { var favorited = $(this).parents(".dump").hasClass("favorite") ? true : false; if (e.type == "mouseover") { if (favorited) { $(this).attr("src", Imgs.chatThumbOff); } else { $(this).attr("src", Imgs.chatThumbBig); $(this).stop().animate(Anim.chatThumbBig, 'fast') } } else { // mouseout if (favorited) { $(this).attr("src", Imgs.chatThumb); $(this).stop().animate(Anim.chatThumb, 'fast'); } else { $(this).delay(600).stop().animate(Anim.chatThumbTiny, 'fast', 'swing', function(){ $(this).attr("src", Imgs.chatThumbDot) $(this).animate(Anim.chatThumb, 0) }) } } }) } // grab message id etc from some element e that's inside a dump // (messages have something like id="message-0001" class="dump" ) function getMessageInfo(e){ var message = $(e).parents(".dump") var id = message.attr("id").substr(8) // cut "message-001" to "001" var nick = message.attr("nick") var link = "http://dump.fm/p/" + nick + "/" + id var content = message.find(".linkify") if (!content.length) content = message.find(".content") var rawContent = content.html() var img = content.find("img").attr("src") var via = "via " + nick + " on dump.fm" return {"nick": nick, "id": id, "link": encodeURIComponent(link), "content": rawContent, "img": encodeURIComponent(img), "via": encodeURIComponent(via)} } // Message Handling window.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; } } window.TextEnabled = Preferences.getProperty("chat.textEnabled", "true") == "none"; window.ImgsEnabled = Preferences.getProperty("chat.imgsEnabled", "true") == "true"; function muteSelector() { var muted = []; for (nick in MUTES) { muted.push(".nick_" + nick); } return muted.join(","); } function setTextEnable() { var muted = muteSelector(); if ($(this).attr('checked')) { TextEnabled = true; Preferences.setProperty("chat.textEnabled", "false"); track('UI', 'TextEnabled'); $('.dump').not('.contains-image,'+muted).show(); } else { TextEnabled = false; Preferences.setProperty("chat.textEnabled", "false"); track('UI', 'TextDisabled'); $('.dump').not('.contains-image').hide() } }; function setImgsEnable() { var muted = muteSelector(); if ($(this).attr('checked')) { ImgsEnabled = true; Preferences.setProperty("chat.imgsEnabled", "true"); track('UI', 'ImgsEnabled'); $('.contains-image').not(muted).show(); } else { ImgsEnabled = false; Preferences.setProperty("chat.imgsEnabled", "false"); track('UI', 'ImgsDisabled'); $('.contains-image').hide(); } }; // 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() } window.lastScriptedScrolledPosition = 0 function scrollToEnd(){ messageList.scrollTop = messageList.scrollHeight lastScriptedScrolledPosition = messageList.scrollTop } function scrollWatcher(){ scrollIfPossible() setTimeout(scrollWatcher, 500) } // Called upon loading /directory function initDirectory() { $('.linkify').each(function() { var t = $(this); t.html(buildMsgContent(t.text())); }); Search.initInpage() initLogThumb('.dlogged-dump .thumb', '.dlogged-dump'); } // See log.js function dragTarget (target, callbacks) { if (! target) return; var base = this; base.target = target; base.callbacks = callbacks; base.init = function(){ base.bind(); } base.bind = function(){ base.target.addEventListener('dragenter', base.enter, false); base.target.addEventListener('dragover', base.over, false); base.target.addEventListener('dragleave', base.leave, false); base.target.addEventListener('dragend', base.end, false); base.target.addEventListener('drop', base.drop, false); } base.enter = function(e){ base.target.classList.add('over'); if ('enter' in callbacks) { callbacks.enter(Drag.url); } return false; } base.over = function(e){ if (e.preventDefault) { e.preventDefault(); // Necessary. Allows us to drop. } if ('over' in callbacks) { callbacks.over(Drag.url); } return false; } base.leave = function(e){ base.target.classList.remove('over'); if ('leave' in callbacks) { callbacks.leave(Drag.url); } return false; } base.end = function(e){ base.target.classList.remove('over'); if ('leave' in callbacks) { callbacks.leave(Drag.url); } return false; } base.drop = function(e){ base.target.classList.remove('over'); if (e.stopPropagation) { e.stopPropagation(); // stops the browser from redirecting. } if (e.preventDefault) { e.preventDefault(); } if ('drop' in callbacks) { callbacks.drop(Drag.url); } return false; } base.init(); }; window.Drag = { 'url': "", 'bindImages': function (){ $('img.unbound').each(function(img){ this.addEventListener('dragstart', Drag.start, false); $(this).removeClass('unbound'); }); }, 'start': function(e){ if (this.src) { Drag.url = this.src; } } } $(function(){ // dragging images into the manual fave palette var palette = document.getElementById("manual-palette"); var paletteButton = document.getElementById("manual-palette-button"); var paletteTimeout = null; var paletteCallbacks = { 'enter': function() { if (paletteTimeout) clearTimeout(paletteTimeout); manPaletteShow(); }, 'leave': function() { if (paletteTimeout) clearTimeout(paletteTimeout); paletteTimeout = setTimeout(manPaletteHideUnlessLocked, 500); }, 'drop': function (url) { if (paletteTimeout) clearTimeout(paletteTimeout); addManualFav(url); } }; Drag.manualPalette = new dragTarget (palette, paletteCallbacks); Drag.manualPaletteButton = new dragTarget (paletteButton, paletteCallbacks); // dragging images directly into the chatbox (fixes chrome and safari) if ($.browser.mozilla) return; var msgInput = document.getElementById("msgInput"); Drag.chatbox = new dragTarget (msgInput, { "drop": function(url) { msgInput.value += " " + url; msgInput.value += " "; msgInput.focus(); } }); }); // Favs function buildFav(f) { var h = '
' + '' + '' + f.from + '' + ' just faved you!' + '
'; return $(h); } function removeFavAndHideBox() { $(this).remove(); if ($('#favbox').children().length == 0) $('#favbox').hide(); } function showFav(f) { $('#favbox').show(); buildFav(f).appendTo('#favbox').animate( {"opacity": 0}, {"duration": 9000, "complete": removeFavAndHideBox }); } function updateFavs(fs) { if (fs.length == 0) return; console.log("new faves"); $('#favbox').show(); $(fs).each(function(i, f) { showFav(f) }); } // well fuck webkit for not supporting {text-decoration: blink} function blinkStart(){ blinkTimer = setInterval(function(){ $(".blink").removeClass("blink").addClass("blink-turning-off") $(".blink-off").removeClass("blink-off").addClass("blink") $(".blink-turning-off").removeClass("blink-turning-off").addClass("blink-off") },500); } function blinkStop(){ clearInterval(blinkTimer); } //big hand stuff // TODO: replace this with simple pointer-events thing. function initBigHand(id){ var cursorId = "#cursor-big" var cursor = $(cursorId)[0] // jquery's reported element sizes are not exactly the same as the browser's 'mouseover' target sizes // so we'll allow a few pixels extra var fudgeFactor = 2 $(id).addClass("no-cursor") // i have to do this weirdly bc putting the cursor image where the mouse cursor is causes problems with mouse events: // * it stops mousemove events on the image below the mouse cursor // * it fucks up mouseover/out and even mouseenter/leave events, as well as click // so i am doing this: // on mousing over the image: // make cursor visible // find image co-ords // bind a global mousemove func // bind cursor click event // unbind mouseover // mousemove func: // move image to mouse co-ords // if mouse co-ords are outside the image co-ords: // make cursor invisible // unbind mousemove func // unbind cursor click event var mousemove = function(e){ var y = e.pageY, x = e.pageX, coords = initBigHand.coords cursor.style.top = y + "px" cursor.style.left = x - 32 + "px" // 32: (4 pixels * 8 pixels per big pixel) to line up pointy finger with cursor if (y < coords.top || y > coords.bottom || x < coords.left || x > coords.right) { $(cursorId).addClass('invisible') $(cursorId).css({"top": 0, "left": 0 }) $(cursorId).unbind('click', cursorClick) $('logo7').unbind('mousemove', mousemove) $(id).mouseover(imageMouseOver) } } var cursorClick = function(){ $(id).click() } var imageMouseOver = function(){ //console.log("moused over...") initBigHand.coords = { "left": $(id).offset().left - fudgeFactor, "top": $(id).offset().top - fudgeFactor, "right": $(id).offset().left + $(id).width() + fudgeFactor, "bottom": $(id).offset().top + $(id).height() + fudgeFactor } $('body').mousemove(mousemove) $(cursorId).click(cursorClick) $(cursorId).removeClass('invisible') $(id).unbind('mouseover', imageMouseOver) } $(id).mouseover(imageMouseOver) } // uhhh todo: move preload stuff into js: // var nextImage = new Image(); // nextImage.src = "your-url/newImage.gif"; // mAcRoMeDiA sHiT function MM_swapImgRestore() { //v3.0 var i,x,a=document.MM_sr; for(i=0;a&&i0&&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' + 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!"); } } /* timb: the ImgCache manages loading images and keeping track of image sizes... it can be passed a bunch of urls to load and a callback that gets called when more images are ready image loading can also be paused and started again. there can be separate ImageCaches, eg, one for search result images, one for chat images (but they all share the actual image cache) In theory it should also avoid a few http requests bc we can just dup DOM nodes for images that are already loaded that don't have cache headers (not sure tho, browsers probably pretty aggressive with that already) */ var ImgCache = { "imgs": {}, // nodes indexed by url "caches": {}, "init": function(name){ // don't clear callback var callback = emptyFunc if (name in ImgCache.caches) callback = ImgCache.caches[name].onImgsLoaded delete ImgCache.caches[name] ImgCache.caches[name] = { "loadAtATime": 10, "urlsToLoad": [], "imgsLoading": {}, "imgsLoadingCounter" : 0, // a hack so i don't have to iterate over the object to always get its size... "imgsLoaded": {}, "onImgsLoaded": callback, "paused": false } }, "add": function(name, urls){ if (!(name in ImgCache.caches)) ImgCache.init(name) if (!$.isArray(urls)) urls = [urls]; var cache = ImgCache.caches[name] urls.forEach(function(url){ cache.urlsToLoad.push(url) }) }, "config": function(name, cfg){ if (!(name in ImgCache.caches)) ImgCache.init(name) var cache = ImgCache.caches[name] for(var key in cfg) cache[key] = cfg[key] }, "clear": function(name){ ImgCache.init(name) }, "pause": function(name){ ImgCache.caches[name].paused = true }, "unpause": function(name){ ImgCache.caches[name].paused = false }, "loadImages": function(cache){ if (cache.paused) return; while(cache.urlsToLoad.length && cache.imgsLoadingCounter < cache.loadAtATime) { var url = cache.urlsToLoad.shift() if (url in ImgCache.imgs) { // already loading this image var img = ImgCache.imgs[url] if (img.complete) { cache.imgsLoaded[url] = ImgCache.imgs[url] } else if (!(url in cache.imgsLoading)) { cache.imgsLoading[url] = ImgCache.imgs[url] cache.imgsLoadingCounter += 1 } } else { var img = new Image() img.src = url img.animated = (parseUri(url)["file"].toLowerCase().substr(-3) == "gif") ? true : false; ImgCache.imgs[url] = img cache.imgsLoading[url] = img cache.imgsLoadingCounter += 1 } } }, "processLoadingImages": function(cache){ for (var url in cache.imgsLoading) { var img = cache.imgsLoading[url] if (img.complete) { cache.imgsLoaded[url] = img delete cache.imgsLoading[url] cache.imgsLoadingCounter -= 1 } } }, "loader": function(){ for (name in ImgCache.caches){ var cache = ImgCache.caches[name] ImgCache.processLoadingImages(cache) // move images from imgsLoading into imgsLoaded ImgCache.loadImages(cache) // put new images in imgsLoading/imgsLoaded from urlsToLoad for (var url in cache.imgsLoaded) { cache.onImgsLoaded(cache.imgsLoaded) // only call if new images actually loaded delete cache.imgsLoaded cache.imgsLoaded = {} break; } } setTimeout(ImgCache.loader, 500) } } ImgCache.loader() // parseUri 1.2.2 from http://blog.stevenlevithan.com/archives/parseuri // (c) Steven Levithan , MIT License // timb: todo: this can't deal with @s in urls correctly. ex: http://www.classicbattletech.com/images/gallery/Combat_Operations_Cover@1280x960.jpg function parseUri (str) { var o = parseUri.options, m = o.parser[o.strictMode ? "strict" : "loose"].exec(str), uri = {}, i = 14; while (i--) uri[o.key[i]] = m[i] || ""; uri[o.q.name] = {}; uri[o.key[12]].replace(o.q.parser, function ($0, $1, $2) { if ($1) uri[o.q.name][$1] = $2; }); return uri; }; parseUri.options = { strictMode: false, key: ["source","protocol","authority","userInfo","user","password","host","port","relative","path","directory","file","query","anchor"], q: { name: "queryKey", parser: /(?:^|&)([^&=]*)=?([^&]*)/g }, parser: { strict: /^(?:([^:\/?#]+):)?(?:\/\/((?:(([^:@]*)(?::([^:@]*))?)?@)?([^:\/?#]*)(?::(\d*))?))?((((?:[^?#\/]*\/)*)([^?#]*))(?:\?([^#]*))?(?:#(.*))?)/, loose: /^(?:(?![^:@]+:[^:@\/]*@)([^:\/?#.]+):)?(?:\/\/)?((?:(([^:@]*)(?::([^:@]*))?)?@)?([^:\/?#]*)(?::(\d*))?)(((\/(?:[^?#](?![^?#\/]*\.[^?#\/.]+(?:[?#]|$)))*\/?)?([^?#\/]*))(?:\?([^#]*))?(?:#(.*))?)/ } }; // end parseUri // Called upon loading /user/log function initLog(recips) { Search.initInpage(); $('.logged-dump .content').each(function() { var t = $(this); t.html(buildMsgContent(t.text(), recips)); }); initLogThumb(".logged-dump .thumb", '.dump'); } function initLogThumb(selector, parentSelector) { $(selector).bind('mouseover mouseout', function(e) { var favorited = $(this).parents(parentSelector).hasClass("favorite") ? true : false; if (e.type == "mouseover") { if (favorited) { $(this).attr("src", Imgs.logThumbOff); } else { $(this).attr("src", Imgs.logThumbBig); $(this).stop().animate(Anim.logThumbBig, 'fast'); } } else { // mouseout if (favorited) { $(this).attr("src", Imgs.logThumb); $(this).stop().animate(Anim.logThumb, 'fast'); } else { $(this).attr("src", Imgs.logThumbOff); $(this).stop().animate(Anim.logThumb, 'fast'); } } }) } // Messages function buildMsgContent(content, recips) { if (content.substr(0,6) == "") return content.substr(6,content.length - 13); else return linkify(escapeHtml(content), recips); } function invalidImageDomain(content) { var words = content.toLowerCase().split(' '); for (var i = 0; i < words.length; i++) { var w = words[i]; if (PicRegex.test(w)) { for (var j = 0; j < InvalidDomains.length; j++) { var d = InvalidDomains[j]; if (w.indexOf(d) != -1) { return d; } } } } } function clearMessages(){ track('UI', 'ClearScreen'); $('.dump').remove(); } function submitMessage() { var content = $.trim($('#msgInput').val()); if (content == "/clear") { clearMessages() $('#msgInput').val(''); return; } var invalidDomain = invalidImageDomain(content); if (invalidDomain) { $('#msgInput').blur(); // Remove focus to prevent FF alert loop alert("Sorry, cannot accept images from " + invalidDomain + ". Maybe host the image elsewhere?"); return; } $('#msgInput').val(''); if (content == '') { return; } if (content.length > 2468) { alert("POST TOO LONG DUDE!"); return; } PendingMessages[content] = true; var msg = { 'nick': Nick, 'content': content }; 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.msgid) .removeClass('loading').addClass('loaded'); div.find('.content').html(buildMsgContent(content, json.recips)); }; var onError = function(resp, textStatus, errorThrown) { div.remove(); handleMsgError(resp); }; $.ajax({ type: 'POST', timeout: 15000, 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(); } }; } // todo: // isLoading doesn't get passed the right thing by $.map in addMessages function buildMessageDiv(msg, opts) { var opts = opts || {}; var nick = escapeHtml(msg.nick); removeOldMessages(); var builtContent = buildMsgContent(msg.content, msg.recips); var msgId = ('msg_id' in msg) ? 'id="message-' + msg.msg_id + '"' : ''; var loadingClass = opts.isLoading ? ' loading' : ''; var containsImageClass = LastMsgContainsImage ? ' contains-image' : ''; var displayStyle = ((ImgsEnabled && LastMsgContainsImage) || (TextEnabled && !LastMsgContainsImage)) ? '' : ' style="display: none"'; if (displayStyle === '' && MUTES[nick]) displayStyle = ' style="display: none"'; return '
' + '' + nick + '' + ' ' + '' + '' + builtContent + '' + '
'; } function addNewMessages(msgs) { var msgStr = $.map(msgs, buildMessageDiv).join(''); $('#messageList').append(msgStr); Drag.bindImages(); } function addNewMessage(msg, isLoading) { var msgStr = buildMessageDiv(msg, { isLoading: true }); var div = $(msgStr).appendTo('#messageList'); Drag.bindImages(); return div; } 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, favs) { if (window['growlize'] && msgs && msgs.length > 0) { $.map(msgs, buildGrowlDataAndPopDatShit) } else if (msgs && msgs.length > 0) { addNewMessages(msgs); } if (users !== null) { var flattened = flattenUserJson(users); if (!('userlist' in cache) || flattened != cache.userlist) { $("#userList").html($.map(users.sort(sortUsersByAlpha), buildUserDiv).join('')); } cache.userlist = flattened } updateFavs(favs); } function sortUsersByAlpha(a, b){ var nickA = a.nick.toLowerCase() var nickB = b.nick.toLowerCase() if (nickA > nickB) return 1 else if (nickA < nickB) return -1 return 0 } 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; $.map(json.messages, function(msg){ MessageContentCache[msg.msg_id.toString()] = msg.content }) var messages = $.grep( json.messages, function(m) { return !isDuplicateMessage(m) }); updateUI(messages, json.users, json.favs); if (!Away.HasFocus) Away.UnseenMsgCounter += messages.length; } catch(e) { if (IsAdmin && window.console) { console.log(e); } } setTimeout(refresh, 1500); }; var onError = function(resp, textStatus, errorThrown) { var msg = $.trim(resp.responseText); if (msg == "UNKNOWN_ROOM") location.href = "http://dump.fm"; if (IsAdmin && window.console) { console.error(resp, textStatus, errorThrown); } setTimeout(refresh, 4000); }; $.ajax({ type: 'GET', timeout: 5000, url: '/refresh', data: { 'room': Room, 'since': Timestamp }, cache: false, dataType: 'json', success: onSuccess, error: onError }); } function sendClicked(){ track('UI', 'SendButtonActuallyClicked'); submitMessage(); } function setupUpload(elementId, roomKey) { var onSubmit = function(file, ext) { if (!(ext && /^(jpg|png|jpeg|gif|bmp|svg)$/i.test(ext))) { alert('SORRY, NOT AN IMAGE DUDE... '); return false; } }; var onComplete = function(file, response) { var r = $.trim(response); if (r.match(/FILE_TOO_BIG/)) { var maxSize = r.split(" ")[1] / 1024; alert("Sorry. Your file is just too darn big. " + maxSize + "KB or less please."); return; } else if (r.match(/FILE_NOT_IMAGE/)) { alert("What did you upload? Doesn't seem like an image. Sorry."); return; } else if (r.match(/INVALID_RESOLUTION/)) { var maxWidth = r.split(" ")[1]; var maxHeight = r.split(" ")[2]; alert("Sorry, the maximum image resolution is " + maxWidth + "x" + maxHeight); return; } else if (r != "OK") { alert(r); return; } if (typeof pageTracker !== 'undefined') { var r = typeof Room !== 'undefined' ? Room : 'UnknownRoom'; pageTracker._trackEvent('Message', 'Upload', r); } } new AjaxUpload(elementId, { action: '/upload/message', autoSubmit: true, name: 'image', data: { room: roomKey }, onSubmit: onSubmit, onComplete: onComplete }); } // manual fave palette by ohgod $(function(){ $('#manual-palette-button').click(manPaletteToggle); $('#manual-add-url-txt').keyup(ifEnter(function(){ addManualFav($('#manual-add-url-txt').val().trim()); $('#manual-add-url-txt').val(""); })); /* $('#manual-add-button').click(function () { addManualFav($('#manual-add-url-txt').val().trim()); $('#manual-add-url-txt').val(""); }); $('#manual-remove-button').click(function () { removeManualFav($('#manual-add-url-txt').val().trim()); $('#manual-add-url-txt').val(""); }); */ }); var manPaletteOpen = false; var manPaletteLocked = false; function manPaletteToggle() { if ($("#manual-palette").css("display") == "none") { manPaletteLocked = true; manPaletteShow(); } else { manPaletteLocked = false; manPaletteHide(); } }; function manPaletteHideUnlessLocked (){ if (manPaletteLocked) return; manPaletteHide(); } function manPaletteHide() { manPaletteOpen = false; $("#manual-palette").css("display", "none"); $("#manual-palette-thumbs").html(""); } function manPaletteShow() { if (manPaletteOpen) return; manPaletteOpen = true; $("#manual-palette").show(); if (! hasLocalStorage()) { $('#manual-palette-localstorage-error').show() } else if (manPaletteIsEmpty()) { $('#manual-palette-thumbs-empty').show(); } else { manualPaletteBuildImageThumbs(); } }; function hasLocalStorage() { try { return 'localStorage' in window && window['localStorage'] !== null; } catch (e) { return false; } } function manPaletteIsEmpty() { return localStorage.manual_favs === undefined || localStorage.manual_favs === "[]" || localStorage.manual_favs === ""; }; function getManualFaves() { return localStorage.manual_favs ? JSON.parse(localStorage.manual_favs) : []; }; function setManualFaves(mfavs) { localStorage.manual_favs = JSON.stringify(mfavs); }; /* function manualPaletteBuildImageThumbs() { var imgs = JSON.parse(localStorage.manual_favs); if (imgs && imgs.length != 0) { for (var i = 0; i < imgs.length; i++) { $("#manual-palette-thumbs").append(""); } } }; */ function addManualFav(url) { if (!url) return; if (hasLocalStorage()) { if (manPaletteIsEmpty()) $("#manual-palette-thumbs").html(""); var mfavs = getManualFaves(); if ($.inArray(url, mfavs) == -1) { mfavs.push(url); setManualFaves(mfavs); manualPaletteBuildImageThumbs(); // $("#manual-palette-thumbs").append(""); } } }; function removeManualFav(url) { if (hasLocalStorage()) { var mfavs = getManualFaves(); var idx = $.inArray(url, mfavs); if (idx != -1) { mfavs.splice(idx, 1); setManualFaves(mfavs); manualPaletteBuildImageThumbs(); } } }; // textchimp autocomplete mod function manualPaletteBuildImageThumbs() { $("#manual-palette-thumbs").html(""); var imgs = JSON.parse(localStorage.manual_favs); if (imgs && imgs.length != 0) { for (var i = 0; i < imgs.length; i++) { $("#manual-palette-thumbs").append('\
\ \
'); } var test_tags = ["dogs", "text", "funny", "disturbing"]; $('.taginput').autocomplete({ source: test_tags, open: function(){ $(this).autocomplete('widget').css({'z-index': '55555555555', 'background-color': '#EFF5FB', 'width': '128px'}); return false; } }); $('.taginput').blur(function(e){ if(!$('.ui-autocomplete').is(':visible') ) { $(e.target).parent().hide(); } }); $('.taginput').keypress(function(e) { if(e.charCode == 13) { add_tags(e.target); } }); $('.mm').hover( function(){ $(this).children(".menuicon").show(); }, function(){ if(!$(this).children('.menuicon').children('.tagin').is(':visible')) { $(this).children(".menuicon").hide(); } }); $('.menuicon').hover( function(){ if(!$(this).children('.tagin').is(':visible')) { $(this).css('opacity', '1.0'); $(this).children('.mymenu').slideDown(100); } }, function(){ if(!$(this).children('.tagin').is(':visible')) { $(this).css('opacity', '0.7'); $(this).children('.tagin').hide(); $(this).children('.mymenu').slideUp(100); } } ); $("").appendTo("head"); $('.mymenu li').css({ 'background-color': '#eee', 'margin': '1px', 'padding-left': '2px', 'cursor': 'pointer', 'font-size': '10pt' }); } } function showtaginput(e) { $(e).parent().hide(); $(e).parent().next().show(); $(e).parent().next().children('.taginput').focus(); } function delfav(e) { console.log($(e).parents('.mm').children('img').attr('src')); removeManualFav($(e).parents('.mm').children('img').attr('src')); } function add_tags(e) { console.log('tags: ' + $(e).val() + '(for: ' + $(e).parents('.mm').children('img').attr('src') + ')'); $(e).parent().hide(); } /* if(!manPaletteOpen) { manPaletteToggle(); } */ // ohgod - checkbox to hide the userlist $(function(){ if ($('#textbutton').length == 0) return; if (window.Room && Room == "atrium") { $('#textbutton input').attr('checked', true); TextEnabled = true; if (setTextEnable) setTextEnable.apply($('#textbutton input')[0]); } $('
').prependTo('#chatbuttons'); $('#showulist').change(function(){ $('#userList').toggle( this.checked ); }); }); function paletteToChat(img){ var chatText = $("#msgInput").val() if (chatText.length && chatText[chatText.length - 1] != " ") chatText += " " chatText += $(img).attr("src") + " " $("#msgInput").val(chatText) $("#msgInput").focus().val($("#msgInput").val()) // http://stackoverflow.com/questions/1056359/ paletteHide() } paletteImageCache = false function paletteBuildImageThumbs(){ if (paletteImageCache) { var imgs = paletteImageCache } else { var imgs = [] var dupeFilter = {} for(fav in RawFavs){ var parsedImgs = getImagesAsArray(RawFavs[fav]) for (var i=0; i") } } function paletteShow(){ $("#palette").css("display", "block") if (isEmptyObject(RawFavs)) { $('#palette-thumbs').html('
This is where all the stuff you FAV goes!

To FAV a post click the little heart next to a users name.

Everything you fav gets saved to your profile.. Have fun!
'); } else { paletteBuildImageThumbs(); } } function paletteHide(){ $("#palette").css("display", "none") $("#palette-thumbs").html("") } function paletteToggle(){ if ($("#palette").css("display") == "none") paletteShow() else paletteHide() } function paletteClicked(){ track('UI', 'FavPaletteActuallyClicked'); paletteToggle(); } function initProfile(recips) { Search.initInpage(); $(".linkify-text").each(function() { var text = jQuery(this).text(); jQuery(this).html(linkifyWithoutImage(text)); }); $(".linkify-full").each(function() { $(this).html(buildMsgContent($(this).text(), recips)); }); $('#edit-toggle').click(enableProfileEdit); activateProfileEditable(); $('.dash-dump .content').each(function() { var t = $(this); t.html(buildMsgContent(t.text())); }); }; function enableProfileEdit() { $('img#contact').replaceWith('
'); $('img#bio').replaceWith('
'); $('#contact, #bio, #avatar').addClass('editable'); $('#avatar-editing').show(); var resetPage = function() { location.reload() }; $('#edit-toggle a').text('done editing').click(resetPage); activateProfileEditable(); } function activateProfileEditable() { 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); }; if ($('#avatar-editing').length > 0) setupUploadAvatar('uploadp'); var textareaOpts = { 'default_text': 'Enter here!', 'callback': onSubmit, 'field_type': 'textarea', 'callbackShowErrors': false }; $('#contact.editable, #bio.editable') .editInPlace(textareaOpts) .each(makePlainText); } function setupUploadAvatar(elementId) { // NOTE: AjaxUpload responses aren't converted from JSON. var onSubmit = function(file, error) { $('#spinner').show(); }; var onComplete = function(file, resp) { $('#spinner').hide(); var r = $.trim(resp); if (r == 'INVALID_REQUEST') { location.reload(); } else if (r == 'NOT_LOGGED_IN') { location.reload(); } else if (r == 'INVALID_IMAGE') { alert("Sorry, dump.fm can't deal with your image. Pick another :("); return; } else if (r.match(/FILE_TOO_BIG/)) { var maxSize = r.split(" ")[1] / 1024; alert("Sorry. Your avatar is just too fucking big. " + maxSize + "KB or less please."); return; } else if (r.match(/INVALID_RESOLUTION/)) { var maxWidth = r.split(" ")[1]; var maxHeight = r.split(" ")[2]; alert("Sorry, the maximum avatar resolution is " + maxWidth + "x" + maxHeight); return; } var s = ''; $('#dashavatar').html(s).show(); $('#dashtotal').css('background-image', 'url(' + r + ')'); }; new AjaxUpload(elementId, { action: '/upload/avatar', autoSubmit: true, name: 'image', onSubmit: onSubmit, onComplete: onComplete }); } Search = { 'term': "", 'images': [], 'tokens': [], 'closed': true, 'initFullpage': function(){ Search.type = "fullpage" Search.init() Search.initSpaceFill = Search.initSpaceFillFullpage }, 'initInpage': function(){ Search.type = "inpage" Search.init() Search.initSpaceFill = Search.initSpaceFillInpage }, 'init': function(){ ImgCache.config("search", {"onImgsLoaded": Search.imgsLoaded}) $('#search-results-images a').live('hover', Search.resultsHover) var input = Search.$input = $("#search-query") var label = "search dump.fm" Search.$container = $("#search-results-images") input.val(label) input.focus(function(){ if (input.val() == label) input.val("") }) input.blur(function(){ if (input.val().trim() == '') input.val(label) }) input.keydown(ifEnter(Search.doSearch)) $("#search-results-images a").live("mouseup", Search.click) }, 'initSpaceFillFullpage': function() { SpaceFill.init({ "container": "#search-results-images", "width": $(document).width(), "height": $(document).height(), "type": "columns", "spacing": "justify", "minMargin": 16, "columnWidth": 250 }) }, 'initSpaceFillInpage': function() { SpaceFill.init({ "container": "#search-results-images", "width": $(document).width() * 0.93, "height": $(document).height(), "type": "columns", "spacing": "justify", "minMargin": 8, "columnWidth": 120 }) }, "resultsHover": function(e){ if (e.type == 'mouseover') { var img = ImgCache.imgs[this.href] if (img.animated) { img.width = img.adjWidth img.height = img.adjHeight $(this).addClass("animating") $(this).append(img) } } else { var img = ImgCache.imgs[this.href] if (img.animated) { $(this).removeClass("animating") this.removeChild(img) } } }, "imgsLoaded": function(imgs){ //if (ColumnFill.isSpaceFilled()) return; if (Search.closed) return; if (Search.$container[0].style.display != "block") { Search.$container.css("display", "block") $("#userList").css("display", "none") Search.setMessage("results for '"+Search.tokens.join(" and ")+"'") } for (var url in imgs){ var img = imgs[url] if (isImgBroken(img)) continue; var width = img.width var height = img.height var maxWidth = SpaceFill.config.columnWidth var maxHeight = Math.floor(SpaceFill.config.columnWidth * 1.2) if (width > maxWidth) { scaleFactor = maxWidth / width width = maxWidth height = Math.floor(height * scaleFactor) } else if (height > maxHeight) { scaleFactor = maxHeight / height height = maxHeight width = Math.floor(width * scaleFactor) } img.adjWidth = width img.adjHeight = height var c = document.createElement("canvas") c.width = width c.height = height var ctx = c.getContext('2d'); ctx.drawImage(img, 0, 0, c.width, c.height) var a = document.createElement("a") a.onclick = falseFunc a.href = img.src a.style.width = width + "px" a.style.height = height + "px" a.appendChild(c) SpaceFill.add(a) } }, 'setContent': function(x){ $("#search-results-images").html(x) }, 'setMessage': function(x){ $("#search-controls").css("display", "block") $("#search-message").html(x) }, 'searchError': function(error){ Search.setContent("") Search.setMessage(error) }, 'doSearch': function(){ Search.closed = false term = $("#search-query").val().trim().toLowerCase() var rawTokens = term.split(" ") Search.tokens = [] rawTokens.forEach(function(t){ if (t.length > 2) Search.tokens.push(t) }) if (Search.tokens.length == 0) { Search.setMessage("search query too small") } else { Search.setMessage("searching for '"+Search.tokens.join(" and ")+"'") Search.doAjax(Search.tokens.join("+")) } }, 'doAjax': function(term) { if (Domain == "http://dump.fm") { $.ajax({ "dataType": "json", "url": "/cmd/search/" + term, "success": Search.results, "error": Search.error, "timeout": 20000, }) } else { // search main site via jsonp $("#search-script").remove() $("head").append("") } }, 'click': function(e){ if (e.which == 1) // left click if (Search.addToChatBoxIfPossible(this)) window.open(this.href) else if (e.which == 2) // middle click window.open(this.href) }, 'addToChatBoxIfPossible': function(img){ var chatBoxExists = $("#msgInput").length if (chatBoxExists) { var chatText = $("#msgInput").val() if (chatText.length && chatText[chatText.length - 1] != " ") chatText += " " chatText += $(img).attr("href") + " " $("#msgInput").val(chatText) $("#msgInput").focus().val($("#msgInput").val()) //http://stackoverflow.com/questions/1056359/ return false } else return true }, 'results': function(results){ Search.resultsClear() if(results === null || results.length == 0) { Search.setMessage("no results found") } else { Search.initSpaceFill() var urls = [] results.forEach(function(r){ var url = r.url if (url.charAt(0) == '/') url = 'http://dump.fm/images' + url else url = 'http://' + url urls.push(url) }) ImgCache.add("search", urls) } }, 'resultsClear': function(){ $("#search-results-images").html("") //ImgCache.pause("search") ImgCache.clear("search") }, 'close': function(){ Search.resultsClear() Search.closed = true Search.$container.css("display", "none") $("#search-controls").css("display", "none") $("#userList").css("display", "block") } } Share = { "openLink": function(url){ window.open(url, "_blank") }, "facebook": function(button){ var message = getMessageInfo(button) var url = "http://www.facebook.com/share.php?u=" + message.img + "&t=" + message.via Share.openLink(url) }, "tumblr": function(button){ var message = getMessageInfo(button) var url = "http://www.tumblr.com/share?v=3&u=" + message.img + "&t=" + message.via Share.openLink(url) }, "twitter": function(button){ var message = getMessageInfo(button) var url = "http://twitter.com/home?status=" + message.img + encodeURIComponent(" ") + message.via Share.openLink(url) }, "delicious": function(button){ var message = getMessageInfo(button) var url = "http://delicious.com/save?url=" + message.img + "&title=" + message.img + "¬es=" + message.via Share.openLink(url) } } window.ColumnFill = { "init": function(){ var cfg = SpaceFill.config var numColumns = ColumnFill.calcColumns() ColumnFill.columns = [] for (var i = 0; i < numColumns; i++) { ColumnFill.columns.push({"height": 0}) } cfg.marginWidth = cfg.marginHeight = cfg.minMargin if (cfg.spacing == "center") { cfg.columnSpacingAmt = (cfg.width - (numColumns * (cfg.columnWidth + cfg.marginWidth) + cfg.marginWidth)) / 2 } else if (cfg.spacing == "justify") { cfg.marginWidth = (cfg.width - (numColumns * cfg.columnWidth)) / (numColumns + 1) } }, "add": function(obj){ var cfg = SpaceFill.config var colIndex = ColumnFill.shortestColumn() var col = ColumnFill.columns[colIndex] if (cfg.spacing == "center") { var colLeft = colIndex * (cfg.marginWidth + cfg.columnWidth) + cfg.columnSpacingAmt var imgLeft = Math.floor((cfg.marginWidth / 2) + (cfg.columnWidth / 2) - (parseInt(obj.style.width) / 2)) + colLeft + "px" } else if (cfg.spacing == "justify") { var colLeft = (colIndex * (cfg.marginWidth + cfg.columnWidth)) var imgLeft = Math.floor((cfg.marginWidth / 2) + (cfg.columnWidth / 2) - (parseInt(obj.style.width) / 2)) + colLeft + "px" } obj.style.position = 'absolute' obj.style.top = col.height + cfg.marginHeight + "px" obj.style.left = imgLeft col.height += cfg.marginHeight + parseInt(obj.style.height) $(cfg.container).append(obj) }, "calcColumns": function(){ var cfg = SpaceFill.config var numColumns = 0 var width = cfg.width - cfg.minMargin var columnSub = cfg.columnWidth + cfg.minMargin while (width > columnSub) { width -= columnSub numColumns++ } return numColumns }, "shortestColumn": function(){ var min = Infinity var mindex = 0 for(var i = 0; i< ColumnFill.columns.length; i++){ var col = ColumnFill.columns[i] if ( min > col.height) { min = col.height mindex = i } } return mindex }, "isSpaceFilled": function(){ var config = SpaceFill.config var colIndex = ColumnFill.shortestColumn() var col = ColumnFill.columns[colIndex] if (col.height > 4 * config.height) return true; else return false; } } window.SpaceFill = { "init": function(config){ config.type = "columns" SpaceFill.config = config SpaceFill.types[config.type].init() SpaceFill.add = SpaceFill.types[config.type].add }, "types": { "columns": ColumnFill } } Tag = { "favorite": function(button) { var message = getMessageInfo(button); var favorited = $(button).parents(".dump").hasClass("favorite"); if (favorited) { Tag.rm(message.id, "favorite"); $(button).parents(".dump").removeClass("favorite"); if (RawFavs[message.id]) { delete RawFavs[message.id]; paletteImageCache = false; } } else { Tag.add(message.id, "favorite"); $(button).parents(".dump").addClass("favorite"); if (RawFavs && MessageContentCache[message.id]) { // chat ui stuff if ($("#palette-button").css("display") == "none") paletteButtonShowAnim(); RawFavs[message.id] = MessageContentCache[message.id]; paletteImageCache = false; } } }, "add": function(message_id, tag) { Tag.ajax("/cmd/tag/add", {"message_id": message_id, "tag": tag}); }, "rm": function(message_id, tag) { Tag.ajax("/cmd/tag/rm", {"message_id": message_id, "tag": tag}); }, "ajax": function(url, data) { $.ajax({ "type": 'POST', "timeout": 5000, "url": url, "data": data, "cache": false }); }, "animated_fav": function(button, scoreClass, bigTextSize, smallTextSize) { if (!Nick) { return; } Tag.favorite(button); var $dump = $(button).parents(".dump"); var isAdding = $dump.hasClass('favorite'); // Frontpage-favs can be triggered by clicking score number, // so manually sync heart-thumb visual state. if ($(button).hasClass('hallscore')) { $dump.find('.thumb').attr('src', isAdding ? Imgs.logThumb : Imgs.logThumbOff); } if ($dump.attr('nick') == Nick) return; var $score = $dump.find(scoreClass); var inc = isAdding ? 1 : -1; var oldScore = parseInt($score.text(), 10); $score.text(oldScore + inc); $score.stop().animate({ 'font-size': bigTextSize }, 250, function() { $score.animate({ 'font-size': smallTextSize }, 250); }); if (isAdding) { var link = $('') .attr('href', Domain + '/' + Nick + '/popular') .append($('').text(Nick)) .append(" "); $dump.find('.faver-list').append(link); } else { $dump.find('.faver-list b').filter(function() { return $(this).text() == Nick }).parent().remove(); } } } // this doesn't properly deal with eg, .gov.uk .co.ck etc function parseDomain(host){ var chunks = host.split(".") if (chunks.length == 1) return chunks[0] else return chunks[chunks.length - 2] } function escapeHtml(txt) { if (!txt) { return ""; } // txt = annoyingCaps(txt) return $("").text(txt).html() } URLRegex = /((\b(http\:\/\/|https\:\/\/|ftp\:\/\/)|(www\.))+(\w+:{0,1}\w*@)?(\S+)(:[0-9]+)?(\/|\/([\w#!:.?+=&%@!\-\/]))?)/gi; PicRegex = /\.(jpg|jpeg|png|gif|bmp|svg|fid)$/i; RecipRegex = /(^|\s)@\w+/g; TopicRegex = /(^|\s)#\w+/g; function getImagesAsArray(text) { var imgs = [] var urls = text.match(URLRegex) if (urls === null) return imgs for (var i = 0; i' + text + ' '; } function recipientReplace(atText, recips) { recips = recips || []; var space = ''; if (atText[0] == ' ') { atText = atText.slice(1); space = ' '; } var nick = atText.slice(1).toLowerCase(); var matchedRecip; for (var i = 0; i < recips.length; i++) { if (recips[i].toLowerCase() == nick) { matchedRecip = recips[i]; break; } } if (matchedRecip) { return space + '@' + matchedRecip + ''; } else { return space + atText; } } function linkify(text, recips) { LastMsgContainsImage = false; var recipWrapper = function(text) { return recipientReplace(text, recips); }; return text .replace(URLRegex, linkReplace) .replace(RecipRegex, recipWrapper) .replace(TopicRegex, topicReplace); } // use this in escapeHtml to turn everyone's text lIkE tHiS function annoyingCaps(text){ var chunks = text.split(" ") for(var i=0; i"; } else if (type == 'youtube') { Youtube.startAnimation(); return "" + "" + "" } else if (type == 'midi' || type == 'wav') { return ' '+uri.file+'' } else return "" + url + ""; } function getUriType(uri){ if (PicRegex.test(uri.file.toLowerCase())) return "image"; var domain = parseDomain(uri.host) if (domain == "gstatic" && uri.path == "/images" && 'q' in uri.queryKey) return "image"; // actual image url = uri.queryKey['q'].split(":").slice(2).join(":") but often the original image is broken... if (domain == "youtube" && ('v' in uri.queryKey || uri.anchor.indexOf('v') != -1)) return "youtube"; if (uri.path.substr(-4) == ".mid" || uri.path.substr(-5) == ".midi") return "midi" if (uri.path.substr(-4) == ".wav") return "wav" return "link"; } function linkifyWithoutImage(text) { LastMsgContainsImage = false return text.replace(URLRegex, linkReplaceWithoutImage); } function linkReplaceWithoutImage(url){ var urlWithoutParams = url.replace(/\?.*$/i, ""); linkUrl = url.indexOf('http://') == 0 ? url : 'http://' + url; return "" + url + "" } var MUTES = {}; $(".mute").live("click", function(){ $(this).removeClass("mute"); $(this).addClass("unmute"); $(this).html("o"); var nick = $(this).parent().children("a").html().replace(/]+>/,""); $(".nick_" + nick).hide(); MUTES[nick] = true; }); $(".unmute").live("click", function(){ $(this).removeClass("unmute"); $(this).addClass("mute"); $(this).html("x"); var nick = $(this).parent().children("a").html().replace(/]+>/,""); $(".nick_" + nick).show(); delete MUTES[nick]; }); function buildUserDiv(user) { var muted = MUTES[user.nick] ? 'o' : 'x'; if (user.avatar) { return ''; } else { return ''; } } // Utils emptyFunc = function(){}; falseFunc = function(){ return false }; isImgBroken = function(img){ return (img.height == 0 || img.width == 0 || img.height == NaN || img.width == NaN) } isEmptyObject = function(obj) { for (key in obj) { if (obj.hasOwnProperty(key)) return false; } return true } String.prototype.trim = function(){ return this.replace(/^\s+|\s+$/g,'') } function isCSSPropertySupported(prop){ return prop in document.body.style } function track(group, name) { if (typeof pageTracker !== 'undefined') { pageTracker._trackEvent(group, name, typeof Nick !== 'undefined' ? Nick : 'anon'); } } // generate a new CSS rule and apply it immediately // (more persistent than dumping a style tag) window.cssRule = function (selector, declaration) { var x = document.styleSheets,y=x.length-1; x[y].insertRule(selector+"{"+declaration+"}",x[y].cssRules.length); $(selector).css(declaration.split(": ")); }; var Log = { "Levels": ['info', 'warn', 'error'], "AjaxSubmitLevels": ['warn', 'error'], "AjaxSubmitPath": "/logerror", "SupplementalInfo": function() { return { 'user': UserInfo && UserInfo.nick }; }, "ajaxSubmit": function(level, component, msg) { var info = Log.SupplementalInfo(); var data = { 'level': level, 'component': component, 'msg': msg }; $.extend(info, data); $.ajax({type: 'POST', timeout: 5000, url: Log.AjaxSubmitPath, data: info }); }, "initialize": function() { $.each(Log.Levels, function(i, level) { Log[level] = function(component, msg) { if (window.console && window.console[level]) window.console[level](args); if (Log.AjaxSubmitLevels.indexOf(level) != -1) Log.ajaxSubmit(level, args); }; }); } }; Log.initialize(); // Time how long a function takes to complete function timeFunc(f){ var start = new Date().getTime(); var res = f(); // console.log((new Date().getTime()) - start + " msecs"); return res; } window.requestAnimFrame = (function(){ return window.requestAnimationFrame || window.webkitRequestAnimationFrame || window.mozRequestAnimationFrame || window.oRequestAnimationFrame || window.msRequestAnimationFrame || function( callback ){ window.setTimeout(callback, 1000 / 60); }; })(); Youtube = { "timer": 0, "startAnimation": function(){ if (!Youtube.timer) Youtube.timer = setTimeout(Youtube.animate, 1000) }, "animate": function(){ var thumbs = $(".youtube-thumb") thumbs.each(Youtube.nextThumb) if (thumbs.length == 0){ clearTimeout(Youtube.timer) Youtube.timer = 0 } else Youtube.timer = setTimeout(Youtube.animate, 1000); }, "nextThumb": function(){ var img = $(this); // yt thumb url is http://i.ytimg.com/vi/0123456789A/1.jpg var v = img.attr("src").substr(22,11) var num = img.attr("src").charAt(34); img.attr("src", (Youtube.nextThumbUrl(v, num))) }, "nextThumbUrl": function(v, num){ if (!num) num = 0; num = (parseInt(num) % 3) + 1 // cycle over 1,2,3 return "http://i.ytimg.com/vi/" + v + "/" + num + ".jpg" }, }