X-Git-Url: http://git.bytex64.net/?a=blobdiff_plain;f=www%2Fjs%2Fblerg.js;h=ba1e39e35464480d366060fe1b19cd6fa722df7f;hb=e396ecb2bf773e4df131b6edf769ca69868575bd;hp=9f92594ba51b22777d5855bf0390d4854d0bb3b9;hpb=f4bf2d2efc566e9f165b97bda72cd5a27e0d2b19;p=blerg.git diff --git a/www/js/blerg.js b/www/js/blerg.js index 9f92594..ba1e39e 100644 --- a/www/js/blerg.js +++ b/www/js/blerg.js @@ -3,15 +3,15 @@ */ // Config -var baseURL = ''; +var baseURL = '/admin/blerg'; var recordTemplate = new Template( - '
'); if (pi != -1) { @@ -299,6 +378,25 @@ function mangleRecord(record, template) { l = l.replace(/^>\s*/, ''); } } + + // Sanitize HTML input + l = l.replace(/&/g, '&').replace(//g, '>'); + + // Turn HTTP URLs into links + l = l.replace(/(\s|^)(https?:\/\/[a-zA-Z0-9.-]*[a-zA-Z0-9](\/([^\s"]*[^.!,;?()\s])?)?)/g, '$1$2'); + + // Turn markdown links into links + l = l.replace(/(\s|^)\[([^\]]+)\]\((https?:\/\/[a-zA-Z0-9.-]*[a-zA-Z0-9](\/[^)"]*?)?)\)/g, '$1$2'); + + // Turn *foo* into italics and **foo** into bold + l = l.replace(/([^\w\\]|^)\*\*(\w[^*]*)\*\*(\W|$)/g, '$1$2$3'); + l = l.replace(/([^\w\\]|^)\*(\w[^*]*)\*(\W|$)/g, '$1$2$3'); + + // Turn refs and tags into links + l = l.replace(/(\s|^)#([A-Za-z0-9_-]+)/g, '$1#$2'); + l = l.replace(/(\s|^)@([A-Za-z0-9_-]+)(\/\d+)?/g, '$1@$2'); + + // Create lists when lines begin with * if (l[0] == '*') { if (!listMode) { var pi = out.lastIndexOf('
'); @@ -309,32 +407,20 @@ function mangleRecord(record, template) { out.push('
') out.pop(); + if (listMode) + out.push(''); record.data = out.join(''); record.date = (new Date(record.timestamp * 1000)).toString(); @@ -358,25 +446,28 @@ function displayError(msg) { // Object for browsing tags -function Tag(type, tag) { - this.initPager(); - this.type = type; - this.tag = tag; +function Tag(m) { + Pager.call(this); + this.type = m[1]; + this.tag = m[2]; + this.pageStart = parseInt(m[3]); var url = baseURL + "/tag/"; - switch(type) { + switch(this.type) { case 'tag': //url += '%23'; url += 'H'; // apache is eating the hash, even encoded. Probably a security feature. + this.baseFrag = '/tag/' + this.tag; break; case 'ref': url += '%40'; + this.baseFrag = '/ref/' + this.tag; break; default: - alert('Invalid tag type: ' + type); + alert('Invalid tag type: ' + this.type); return; } - url += tag; + url += this.tag; new Ajax.Request(url, { method: 'get', @@ -389,7 +480,9 @@ function Tag(type, tag) { mangleRecord(v, tagRecordTemplate) }); this.addItems(j); - this.pageStart = j.length - 1; + if (!this.pageStart) + this.pageStart = j.length - 1; + this.itemCount = j.length; } this.displayItems(); }.bind(this), @@ -402,29 +495,87 @@ function Tag(type, tag) { Tag.prototype = new Pager(); Tag.prototype.constructor = Tag; +Tag.prototype.updateState = function(m) { + if (this.type != m[1] || this.tag != m[2]) + return false; + + this.pageStart = parseInt(m[3]) || this.itemCount - 1; + this.displayItems(); + + return true; +} + Tag.prototype.show = function() { + Pager.prototype.show.call(this); + var ctype = {ref: '@', tag: '#'}[this.type]; $$('[name=section]').each(function(v) { v.update(' about ' + ctype + this.tag); }.bind(this)); - $('welcome').hide(); - $('post').hide(); - $('older_link').hide(); - $('newer_link').hide(); - $('rss').hide(); - items.show(); - $('usercontrols').hide(); } -function postPopup() { - if (loginStatus.loggedIn) { + +// Pager for browsing subscription feeds +function Feed(m) { + Pager.call(this); + this.username = loginStatus.username; + this.baseFrag = '/feed'; + this.pageStart = parseInt(m[1]); + + new Ajax.Request(baseURL + '/feed', { + method: 'post', + parameters: { + username: loginStatus.username + }, + onSuccess: function(r) { + var response = r.responseText.evalJSON(); + if (response) { + var maxid = response.length - 1; + response.each(function(v, i) { + v.id = maxid - i; + mangleRecord(v, tagRecordTemplate) + }); + this.addItems(response); + if (!this.pageStart) + this.pageStart = response.length - 1; + this.itemCount = response.length; + } + this.displayItems(); + }.bind(this), + onFailure: function(r) { + this.displayItems(); + }.bind(this) + }); +} +Feed.prototype = new Pager(); +Feed.prototype.constructor = Feed; + +Feed.prototype.updateState = function(m) { + this.pageStart = parseInt(m[1]) || this.itemCount - 1; + this.displayItems(); + + return true; +} + +Feed.prototype.show = function() { + Pager.prototype.show.call(this); + $$('[name=section]').each(function(v) { + v.update(' ' + loginStatus.username + "'s spycam"); + }.bind(this)); +} + + +function postPopup(initial) { + if (loginStatus.loggedIn || initial) { var post = $('post'); if (post.visible()) { post.hide(); } else { post.show(); - if (currentPager.username && currentPager.username != loginStatus.username && !$('post.content').value) { + if (initial) { + $('post.content').value = initial; + } else if (!$('post.content').value && currentPager.username && currentPager.username != loginStatus.username) { $('post.content').value = '@' + currentPager.username + ': '; } $('post.content').focus(); @@ -443,8 +594,7 @@ function signup() { }, onSuccess: function(r) { $('signup').hide(); - location.href = '/#' + username; - hashSwitch(); + qlink(username); loginStatus.login(username, password); }, @@ -456,20 +606,10 @@ function signup() { function signup_cancel() { $('signup').hide(); - hashSwitch(); -} - -function newer_page() { - if (currentPager) - currentPager.newerPage(); -} - -function older_page() { - if (currentPager) - currentPager.olderPage(); + urlSwitch(); } -function obsess() { +function subscribe() { new Ajax.Request(baseURL + '/subscribe/' + currentPager.username, { method: 'post', parameters: { @@ -479,19 +619,19 @@ function obsess() { var response = r.responseText.evalJSON(); if (response.status == 'success') { alert("You call " + currentPager.username + " and begin breathing heavily into the handset."); - $$('[name=user.obsesslink]').each(Element.hide); - $$('[name=user.unobsesslink]').each(Element.show); + $$('[name=user.subscribelink]').each(Element.hide); + $$('[name=user.unsubscribelink]').each(Element.show); } else { - alert('Failed to obsess. This is probably for the best'); + alert('Failed to subscribe. This is probably for the best'); } }, onFailure: function(r) { - alert('Failed to obsess. This is probably for the best'); + alert('Failed to subscribe. This is probably for the best'); } }); } -function unobsess() { +function unsubscribe() { new Ajax.Request(baseURL + '/unsubscribe/' + currentPager.username, { method: 'post', parameters: { @@ -501,8 +641,8 @@ function unobsess() { var response = r.responseText.evalJSON(); if (response.status == 'success') { alert("You come to your senses."); - $$('[name=user.obsesslink]').each(Element.show); - $$('[name=user.unobsesslink]').each(Element.hide); + $$('[name=user.subscribelink]').each(Element.show); + $$('[name=user.unsubscribelink]').each(Element.hide); } else { alert('You are unable to tear yourself away (because something failed on the server)'); } @@ -582,13 +722,15 @@ function stopTicker() { function loadLatest() { new Ajax.Request(baseURL + '/latest.json', { + method: 'GET', onSuccess: function(r) { var j = r.responseText.evalJSON(); $('latest-tags').update(); j.tags.each(function(v) { - var a = new Element('a', {href: '/#tag/' + v}); + var a = new Element('a', {href: baseURL + '/#/tag/' + v}); a.insert('#' + v); + a.onclick = "return qlink()"; a.className = 'ref'; $('latest-tags').insert(a); $('latest-tags').appendChild(document.createTextNode(' ')); @@ -606,52 +748,84 @@ function loadLatest() { }); } -function hashSwitch() { - var m; +function qlink(loc) { + if (loc) { + location.hash = loc; + } else if (event && event.target) { + location.href = event.target.href; + } else { + // Bogus qlink + return; + } + lastHash = location.hash; + urlSwitch(); + return false; +} + +function Welcome() { + loadLatest(); +} + +Welcome.prototype.show = function() { + $$('[name=section]').each(function(v) { v.update('Welcome') }); + $('welcome').show(); +} + +Welcome.prototype.hide = function() { stopTicker(); - if (m = location.search.match(/^\?post\/([^/]+)\/(.+)/)) { - $('post').show(); - $('post.content').value = '[' + decodeURIComponent(m[1]).replace(']','').replace('[','') + '](' + decodeURIComponent(m[2]) + ')'; - } else if (m = location.hash.match(/^#(ref|tag)\/([A-Za-z0-9_-]+)$/)) { - currentPager = new Tag(m[1], m[2]); - currentPager.show(); - } else if (m = location.hash.match(/^#([A-Za-z0-9_-]+)(:(\d+))?$/)) { - if (!currentPager || currentPager.username != m[1]) - currentPager = new User(m[1]); - currentPager.show(); - loginStatus.update(); + $('welcome').hide(); +} - if (m[3]) { - var r = parseInt(m[3]); - currentPager.showRecord = r; - if (currentPager.itemCache[r]) { - currentPager.displayItems(); - } else { - currentPager.loadItems((r >= 49 ? r - 49 : 0), r); - } - } else { - currentPager.pageStart = currentPager.itemCount - 1; - currentPager.loadItems(); +function ExternalURLPost(m) { + this.title = decodeURIComponent(m[1]).replace(']','').replace('[',''); + this.url = decodeURIComponent(m[2]); +} + +ExternalURLPost.prototype.show = function() { + $('post.content').value = '[' + this.title + '](' + this.url + ')'; + $('post').show(); +} + +var urlmap = [ + ['search', /^\?post\/([^/]+)\/(.+)/, ExternalURLPost], + ['hash', /^#\/(ref|tag)\/([A-Za-z0-9_-]+)(?:\/p(\d+))?$/, Tag], + ['hash', /^#\/feed(?:\/p(\d+))?$/, Feed], + ['hash', /^#([A-Za-z0-9_-]+)(?:\/(p)?(\d+))?$/, User] +]; + +function urlSwitch() { + var m; + var pageconstructor; + + for (var i = 0; i < urlmap.length; i++) { + if (m = location[urlmap[i][0]].match(urlmap[i][1])) { + pageconstructor = urlmap[i][2]; + break; } - } else { - $$('[name=section]').each(function(v) { v.update('Welcome') }); - $('signup').hide(); - items.update(); - items.hide(); - $('newer_link').hide(); - $('older_link').hide(); - $('welcome').show(); - $('rss').hide(); - $('usercontrols').hide(); - loadLatest(); } + if (i == urlmap.length) + pageconstructor = Welcome; + + if (currentPager && currentPager instanceof pageconstructor) { + // updateState returns true if the state has been successfully updated. + // Otherwise, we continue and create a new instance. + if (currentPager.updateState(m)) + return; + } + + if (currentPager && currentPager.hide) + currentPager.hide(); + + currentPager = new pageconstructor(m); + if (currentPager.show) + currentPager.show(); } var lastHash; function hashCheck() { if (location.hash != lastHash) { lastHash = location.hash; - hashSwitch(); + urlSwitch(); } } @@ -660,12 +834,12 @@ function init() { loginStatus = new LoginStatus(); lastHash = location.hash; - hashSwitch(); + urlSwitch(); setInterval(hashCheck, 250); document.body.observe('keyup', function(event) { - if (event.shiftKey && event.keyCode == '32') { + if (event.shiftKey && event.keyCode == 32) { postPopup(); event.stop(); }