var API_MAGIC = "#(@)PROTOCOLS" var URLregexp = /^(https?:\/\/)(www.)?([-A-Z0-9.]+)(\/)?([-A-Z0-9+&@#\/%?=~_|!:,.;]*[-A-Z0-9+&@#\/%=~_|])*/ig; var months = { Jan: 0, Feb: 1, Mar: 2, Apr: 3, May: 4, Jun: 5, Jul: 6, Aug: 7, Sep: 8, Oct: 9, Nov: 10, Dec: 11 } function isScrolledIntoView (elem) { return true; var docViewTop = $(window).scrollTop(); var docViewBottom = docViewTop + $(window).height(); var elemTop = $(elem).offset().top; var elemBottom = elemTop + $(elem).height(); return ((elemBottom >= docViewTop) && (elemTop <= docViewBottom)); } function scrollToTop (div) { $(div).scrollTop( 0 ) } function scrollToBottom (div) { $(div).scrollTop( $(div)[0].scrollHeight ) } function warn(s) { // return var h = document.getElementById('msg').innerHTML h = s + '
' + h document.getElementById('msg').innerHTML = h } var image_extensions = ["jpg","gif","png","jpeg","JPEG","JPG","GIF","PNG"] function is_image(s) { for (i in image_extensions) { if (s.indexOf(image_extensions[i]) !== -1) return true } return false } var domain_extensions = [".com",".net",".org",".uk",".fr",".de",".ch",".info",".nu",".mu",".io","facebook.com","twitter.com"] function has_domain(s) { for (var i in domain_extensions) { if (s.indexOf(domain_extensions[i]) !== -1) return true } return false } function parse_blurb(s) { // s = linkify(s+"\n") var parsed_lines = [] var lines = s.split("\n") for (i in lines) { var parsed_words = [] var words = lines[i].split(" ") for (j in words) { if (words[j].indexOf("http") !== -1) { if (is_image(words[j])) parsed_words.push('') else parsed_words.push(linkify(words[j])) } else if (words[j].indexOf("www") === 0 || has_domain(words[j])) { parsed_words.push(linkify("http://"+words[j])) } else parsed_words.push(words[j]) } parsed_lines.push( parsed_words.join(" ") ) } // return s.replace(/\n/g, '
') return parsed_lines.join("
") } function linkify(s) { var link = ''; var punctuation = ''; var end = s.length-1; // strip the terminal punctuation mark if it's a period or comma if (s.indexOf(".", end) === end || s.indexOf(",", end) === end) { punctuation = s.substr(end, 1); s = s.substr(0, end); } if (s.indexOf("twitter.com") !== -1) { var partz = s.split("/"); var uname = ''; if (partz[partz.length-1].length) uname = partz[partz.length-1]; else if (parts[-2].length) uname = partz[partz.length-2]; link = '@' + uname + ''; } else { // link = s.replace(URLregexp,"[$3]"); var match = URLregexp.exec(s); if (match && match.length == 6) { var url = match[0] || ""; var http = match[1] || ""; var www = match[2] || ""; var domain = match[3] || ""; var slash = match[4] || ""; var uri = match[5] ? match[5].replace(/\/?index.html$/, "") : ""; link = '[' + domain + ']'; } else { link = s.replace(URLregexp,"[$3]"); } } return link + punctuation; } var URL = { auth: { login: "/login", logout: "/logout", }, party: { list: "/api/party/list", view: "/api/party/view", edit: "/api/party/edit", }, user: { all: "/api/user/all", view: "/api/user/view", edit: "/api/user/edit", destroy: "/api/user/destroy", }, }; var Party = { parties: {}, currentID: -1, partyData: '', liclick: function () { Nav.selectClass(Party.parties, this.id) var id = this.id.split("-")[1] warn("viewing party "+id) Party.view(id) }, list: function() { $('#partyListContainer').fadeOut(200) $('#partyEditContainer').hide() $('#userListContainer').hide() $('#userEditContainer').hide() $('#userViewContainer').hide() $.get(URL.party.list,{},Party.listCallback) }, listCallback: function (raw) { warn("got party list") var lines = raw.split("\n") if (lines.shift() !== API_MAGIC) { warn(raw) warn("bad api: party list") return } var partyList = "" if (Party.currentID != -1) var firstPartyID = Party.currentID for (i in lines) { if (! lines[i]) continue var fields = lines[i].split('\t') if (! firstPartyID) firstPartyID = fields[0] // 0 id 1 date partyList += "
  • "+fields[1]+"
  • " Party.parties["party-"+fields[0]] = fields } $('#partyList').html(partyList) $('#partyListContainer').fadeIn(200) for (id in Party.parties) $('#'+id).click(Party.liclick) Nav.selectClass(Party.parties, "party-"+firstPartyID) if (firstPartyID) Party.view(firstPartyID) }, view: function(id) { $('#userViewContainer').hide() $('#userEditContainer').hide() $('#partyEditContainer').hide() $('#userListContainer').fadeOut(200) $.get(URL.party.view, {'id':id}, Party.viewCallback) }, viewCallback: function (raw) { warn ("got party view") var lines = raw.split("\n") if (lines.shift() !== API_MAGIC) { warn("bad api: party view") return } var partyData = ''; var partyUserList = "" var partyLocationTag = "" var editable = [] var currentHost = -1 for (i in lines) { if (! lines[i]) continue var fields = lines[i].split('\t') if (! partyData) { partyData = fields; continue } // 0 id 1 group 2 name 3 email 4 blurb if (fields[1] !== currentHost) { currentHost = fields[1] if (currentHost === '0') partyUserList += "
  • guest host
  • " else partyUserList += "
  • invited by "+Auth.hosts[fields[1]]+"
  • " } partyUserList += "
  • "+fields[2]+"" if (Auth.isHost || fields[0] === Auth.userID) { partyUserList += "edit" editable.push(fields[0]) } partyUserList += "
  • " Users.userlist['user-'+fields[0]] = fields } partyLocationTag = partyData[2] Party.currentID = partyData[0] Party.partyData = partyData $('#partyLocation').html(partyLocationTag) $('#userList').html(partyUserList) if (Auth.isHost) { $('#user-add').show() $('#party-edit').show() } $('#userListContainer').fadeIn(200) $('#userViewContainer').show() for (id in Users.userlist) { $('#'+id).hover(Users.limousein, Users.limouseout) $('#'+id).click(Users.liclick) } for (i in editable) { $('#edit-'+editable[i]).bind("click",Users.editClick) } Users.hovering = true }, addClick: function () { warn("NEW PARTY FORM") var id = "NEW" var today = new Date() $('#party-id').val(id) $('#party-day').val(today.getDate()) $('#party-year').val(today.getFullYear()) $('#party-month option').attr("selected", false); $('#party-month option[value="'+today.getMonth()+'"]').attr("selected", true); $('#party-location').val("") $('#partyEditContainer h2').html("New party") $('#userListContainer').hide() $('#userViewContainer').hide() $('#userEditContainer').hide() $('#partyEditContainer').show() $('#party-location').focus() Main.saveFunction = Party.editSave Nav.selectClass(Party.parties, "") }, editClick: function () { var id = Party.currentID // 0 id 1 date 2 location var party = Party.partyData var date = party[1].split("-") $('#party-id').val(id) $('#party-day').val(date[0]) $('#party-year').val(date[2]) $('#party-month option').attr("selected", false); $('#party-month option[value="'+months[date[1]]+'"]').attr("selected", true); $('#party-location').val(party[2]) $('#partyEditContainer h2').html("Edit party") $('#userListContainer').hide() $('#userViewContainer').hide() $('#userEditContainer').hide() $('#partyEditContainer').show() Main.saveFunction = Party.editSave }, editSave: function () { if (Main.saving) return Main.saving = true warn("attempting save") var data = { id: $('#party-id').val(), userid: Auth.userID, hostid: Auth.userID, location: $('#party-location').val(), month: $('#party-month').val(), day: $('#party-day').val(), year: $('#party-year').val(), } $('#partyEditContainer').fadeOut(200) $.post(URL.party.edit, data, Party.editSaveCallback) }, editSaveCallback: function (raw) { var lines = raw.split("\n") if (lines.shift() !== API_MAGIC) { warn("bad api: party save") return } var result = lines.shift().split("\t") if (result[0] === "ERROR") { warn("save error: "+result[1]) return } var fields = lines.shift().split("\t") var rowID = "party-"+fields[0] if (result[0] === "OK") { warn("party saved") } else if (result[0] === "NEW") { warn("party created") $("#partyList").append("
  • "+fields[1]+"
  • ") } // Party.parties[rowID] = fields // Party.view(fields[0]) // Nav.selectClass(Party.parties, rowID) Main.saving = false Party.currentID = fields[0] Party.list() }, }; var Users = { userlist: {}, hovering: true, current: false, allCount: 0, userListIndex: [], currentIdx: -1, all: function () { $('#userViewContainer').hide() $('#userEditContainer').hide() $('#partyEditContainer').hide() $('#userListContainer').fadeOut(200) $.get(URL.user.all,{},Users.allCallback) }, allCallback: function (raw) { warn ("got all users") var lines = raw.split("\n") if (lines.shift() !== API_MAGIC) { warn("bad api: user all") return } var partyUserList = []; var guestHosts = []; var editable = []; var firstletter = "A"; Users.allCount = 0; Users.userListIndex = []; for (i in lines) { if (! lines[i]) continue var fields = lines[i].split('\t') // 0 id 1 group 2 name 3 email 4 blurb // if (fields[1] !== currentHost) // { // currentHost = fields[1] // partyUserList += "
  • invited by "+Auth.hosts[fields[1]]+"
  • " // } var a = fields[2].substr(0,1) var li = "li id='r-"+Users.allCount+"'" var userRow = ""; var editSpan = ""; if (firstletter !== a) { firstletter = a li += " class='br'" } if (Auth.isHost || fields[0] === Auth.userID) { editSpan += "edit"; editable.push(fields[0]); } switch (fields[1]) { case '2': // host userRow = "<"+li+">"+fields[2]+" *" + editSpan + ""; break; case '1': // guest host userRow = "<"+li+">"+fields[2]+" *" + editSpan + ""; guestHosts.push(userRow); Users.userListIndex.unshift('user-'+fields[0]); Users.allCount += 1; break; default: // guest userRow = "<"+li+">"+fields[2]+"" + editSpan + ""; } partyUserList.push(userRow); Users.userlist['user-'+fields[0]] = fields; Users.userListIndex.push('user-'+fields[0]); Users.allCount += 1; } $('#partyLocation').html(""); var guestHostHeader = "
  • Guest Hosts
  • "; var guestListHeader = "
  • Guest List
  • "; for (var i in guestHosts) guestHosts[i] = guestHosts[i].replace("class='br'","").replace("*",""); // console.log(guestHosts); // guestHosts[guestHosts.length-1] = guestHosts[guestHosts.length-1].replace("Here\'s a tip! Use the up and down arrow keys to browse this list.').fadeIn(500) $('#userViewContainer').html(''); for (id in Users.userlist) { $('#'+id).hover(Users.limousein, Users.limouseout) $('#'+id).click(Users.liclick) } for (i in editable) { $('#edit-'+editable[i]).bind("click",Users.editClick) } Users.hovering = true }, limouseout: function () { if (Users.hovering) $("#"+this.id).removeClass("selected") }, limousein: function () { if (Users.hovering) { $("#"+this.id).addClass("selected") Users.view(this.id) } }, liclick: function () { if (! Users.hovering && Users.current === this.id) { Nav.selectClass(Users.userlist, false) Users.current = false Users.hovering = true } else { Nav.selectClass(Users.userlist, this.id) Users.view(this.id) Users.hovering = false } }, viewIdx: function (idx) { var id = Users.userListIndex[idx] if (isScrolledIntoView("#r-"+idx)) { var offset = $("#r-"+idx)[0].offsetTop+5 if (offset > 300) $("body").scrollTop( offset ) } else { // get element at x,y var element = document.elementFromPoint(30,180); if (element.tagName === "UL") element = document.elementFromPoint(30,190); if (element.tagName === "UL") element = document.elementFromPoint(30,200); if (element.tagName === "SPAN") id = element.id } Users.hovering = false Users.view(id) Nav.selectClass(Users.userlist, id) }, view: function (id) { var user = Users.userlist[id] var userRec = ''; // 0 id 1 group 2 name 3 email 4 blurb var blurb = parse_blurb( atob ( user[4] ) ) userRec += "

    " + user[2] + "

    " userRec += "

    " + ( user[3] ? ""+user[3]+"" : "" ) + "

    " userRec += "

    " + blurb + "

    " $('#userViewContainer').html(userRec) $('#userEditContainer').hide() $('#partyEditContainer').hide() $('#userViewContainer').show() Users.currentIdx = $("#"+id).parent().attr("id").substr(2) }, addClick: function () { warn("NEW USER FORM") var id = "NEW" $('#user-id').val(id) $('#user-name').val("") $('#user-email').val("") $('#user-emailhidden').attr('checked', false) $('#user-blurb').val("") $('#userViewContainer').hide() $('#userEditContainer').show() $('#user-name').focus() $('#userEditContainer h2').html("Add a new guest") if (Auth.isHost) { $('#user-password-block').show() $('#user-isstaff-block').show() } Nav.selectClass(Users.userlist, "") Users.hovering = false Main.saveFunction = Users.editSave }, editClick: function () { $(window).unbind("keydown") var id = this.id.split("-")[1] Users.hovering = false $('#userViewContainer').fadeOut(200) $('#userEditContainer').hide() $.post(URL.user.view, {id:id}, Users.editClickCallback) }, editClickCallback: function (raw) { var lines = raw.split("\n") if (lines.shift() !== API_MAGIC) { warn("bad api: user edit") return } var user = lines.shift().split('\t') warn ("editing user "+user[0]) var hidemail = user[4] === '1' ? true : false // 0 id 1 name 2 email 3 access 4 emailhidden 5 hostid 6 blurb var blurb = atob ( user[6] ) $('#user-id').val(user[0]) $('#user-name').val(user[1]) $('#user-email').val(user[2]) $('#user-emailhidden').attr('checked', hidemail) $('#user-access option').attr("selected", false); $('#user-access option[value="'+parseInt(user[3])+'"]').attr("selected", true); $('#user-host option').attr("selected", false); $('#user-host option[value="'+parseInt(user[5])+'"]').attr("selected", true); $('#user-blurb').val(blurb) $('#userViewContainer').hide() if (user[0] === Auth.userID) { $('#userEditContainer h2').html("Editing your profile") $('#user-password-block').show() $('#user-isstaff-block').hide() } else { $('#user-password-block').hide() $('#user-isstaff-block').hide() $('#user-invitedby-block').hide() $('#userEditContainer h2').html("Editing "+user[1]) } if (Auth.isHost) { $('#user-password-block').show() $('#user-isstaff-block').show() $('#user-invitedby-block').show() $('#user-delete').show() var ishost = user[3] === '1' ? true : false $('#user-ishost').attr('checked', ishost) } $('#user-password1').val('') $('#user-password2').val('') $('#userEditContainer').fadeIn(300) Main.saveFunction = Users.editSave }, editSave: function () { if (Main.saving) return Main.saving = true var hidemail = $('#user-emailhidden').attr("checked") === true ? 1 : 0 warn("attempting save") var id = $('#user-id').val() var data = { id: id, partyid: Party.currentID, hostid: $('#user-host').val(), name: $('#user-name').val(), email: $('#user-email').val(), emailhidden: hidemail, blurb: $('#user-blurb').val(), } if (Auth.isHost) { var access = $('#user-access').val() data['access'] = access } if (Auth.isHost || id === Auth.userID) { var pw1 = $('#user-password1').val() var pw2 = $('#user-password2').val() if (pw1 && pw2) { warn("setting password?! "+pw1) if (pw1 === pw2) data['password'] = pw1 else warn("passwords don't match!") } } $.post(URL.user.edit, data, Users.editSaveCallback) }, editSaveCallback: function (raw) { var lines = raw.split("\n") if (lines.shift() !== API_MAGIC) { warn("bad api: user edit") return } var result = lines.shift().split("\t") if (result[0] === "ERROR") { warn("save error: "+result[1]) return } var fields = lines.shift().split("\t") var rowID = "user-"+fields[0] if (result[0] === "OK") { warn("user saved") Users.userlist[rowID] = fields Users.view(rowID) Nav.selectClass(Users.userlist, rowID) } else if (result[0] === "NEW") { warn("user created") // $("#userList").append("
  • "+fields[1]+"
  • ") Party.view( Party.currentID ) } Main.saving = false }, deleteClick: function () { var id = $('#user-id').val() var name = $('#user-name').val() var r = confirm("ARE YOU SURE YOU WANT TO DELETE " + name + "?") if (r) $.post(URL.user.destroy, {'id':id}, Users.deleteClickCallback) }, deleteClickCallback: function () { var id = $('#user-id').val() var name = $('#user-name').val() Users.userlist['user-'+id] = [] warn("DELETED "+id+ " "+name) $('#userViewContainer').hide() $('#userViewContainer h2').html('') $('#userViewContainer b').html('') $('#userViewContainer p').html('') $('#userEditContainer').hide() Party.view( Party.currentID ) }, }; var Nav = { navIDs: {"nav_about":0,"nav_parties":0,"nav_users":0,"nav_patrons":0,"nav_reunions":0}, aboutClick: function() { this.blur() $('#aboutMode').show() $('#patronMode').hide() $('#partiesMode').hide() $('#reunionMode').hide() Nav.selectClass(Nav.navIDs, "nav_about") $(window).unbind("keydown") }, partiesClick: function() { this.blur() $('#aboutMode').hide() $('#patronMode').hide() $('#partiesMode').show() $('#reunionMode').hide() Nav.selectClass(Nav.navIDs, "nav_parties") $('#userViewContainer').css("left", 520) Party.list() $(window).unbind("keydown") }, usersClick: function() { this.blur() $('#aboutMode').hide() $('#patronMode').hide() $('#partiesMode').show() $('#reunionMode').hide() $('#userListContainer').hide() $('#partyListContainer').hide() Nav.selectClass(Nav.navIDs, "nav_users") $('#userViewContainer').css("left", 320) Users.all() $(window).unbind("keydown") $(window).bind("keydown", Nav.keydown) }, patronsClick: function() { this.blur() $('#aboutMode').hide() $('#partiesMode').hide() $('#patronMode').show() $('#reunionMode').hide() Nav.selectClass(Nav.navIDs, "nav_patrons") $(window).unbind("keydown") }, reunionClick: function() { this.blur() $('#aboutMode').hide() $('#patronMode').hide() $('#partiesMode').hide() $('#reunionMode').show() Nav.selectClass(Nav.navIDs, "nav_reunions") $(window).unbind("keydown") }, selectClass: function (ids, selected) { for (var id in ids) { $("#"+id).removeClass("selected") } if (selected) $("#"+selected).addClass("selected") }, keydown: function (e) { kc = event.keyCode if (kc === 38) // up { // select previous name or last newIdx = parseInt(Users.currentIdx) - 1 if (newIdx < 0) { newIdx = Users.allCount - 1 scrollToBottom("body") } Users.viewIdx(newIdx) return false } if (kc === 40) // down { // select next name or first newIdx = parseInt(Users.currentIdx) + 1 if (newIdx === Users.allCount) { newIdx = 0 scrollToTop("body") } Users.viewIdx(newIdx) return false } return true }, }; var Auth = { name: '', userID: 1, isHost: false, loginPrompt: false, hosts: {}, init: function () { if (document.cookie.indexOf("sid.protocols") !== -1) { warn('got cookie') $.post(URL.auth.login, {}, Auth.loginCallback) return } Auth.load() }, unload: function () { if (Auth.loginPrompt) { Auth.loginPrompt = false $('#login').fadeOut(1000, function(){ Main.load()} ) } else Main.load() }, load: function () { $('#login').fadeIn(1000) $('#login-email').focus() $('#login-email').keydown(Main.kp) $('#login-password').keydown(Main.kp) $('#login-go').click( Auth.login ) Auth.loginPrompt = true Main.saveFunction = Auth.login Main.saving = false }, login: function () { if (Main.saving) return Main.saving = true warn("attempting login") var data = { username: $('#login-email').val(), password: $('#login-password').val(), } $('#login-password').val(''), $.post(URL.auth.login, data, Auth.loginCallback) }, loginCallback: function (json) { Main.saving = false if (json.error) { if (! Auth.loginPrompt) Auth.load() else warn("bad login!") return } // 0 id 1 name 2 firstname 3 email 4 access var user = Auth.user = json.user var name = user.name.split(' ')[0] || user.email.split('@')[0] warn( "Logged in! Hello "+name ) Auth.userID = user.id Auth.isHost = user.access == 2 ? true : false; Auth.name = user.name Auth.firstName = name $('#profile-edit').html(Auth.firstName + "!") $('#logout').click( Auth.logout ) var hostSelect = "" Auth.hosts = {} json.hosts.forEach(function(host){ if (host.id === Auth.userID) hostSelect += "" else hostSelect += "" Auth.hosts[ host.id ] = host.name }) $("#user-host").html(hostSelect) Auth.unload() }, logout: function () { warn("logging out") document.cookie = 'sid.protocols=LOGGEDOUT; expires=Mon, 1 Jan 2001 12:00:00 UTC; path=/' Main.unload() }, }; var Main = { saveFunction: false, saving: false, kp: function (e) { var evt = window.event ? window.event : e var key = evt.keyCode ? evt.keyCode : e.which if (key === 13) Main.saveFunction() }, init: function () { warn("init site") Auth.init() }, unload: function () { $('header').fadeOut(500) $('section').fadeOut(500) $('footer').fadeOut(500) $('#bg').fadeIn(500) Auth.init() }, load: function () { warn("loading site") $('#bg').fadeOut(500) $('header').show() $('#welcome').fadeIn(500) $('#nav_about').click( Nav.aboutClick ) $('#nav_users').click( Nav.usersClick ) $('#nav_patrons').click( Nav.patronsClick ) $('#nav_reunions').click( Nav.reunionClick ) if (Auth.isHost) { $('#nav_parties').show() $('#nav_parties').click( Nav.partiesClick ) $('#user-add').click( Users.addClick ) $('#user-delete').click( Users.deleteClick ) $('#party-add').click( Party.addClick ) $('#party-edit').click( Party.editClick ) } else { $('#nav_parties').hide() $('#user-add').hide() $('#user-delete').hide() $('#party-add').hide() $('#party-edit').hide() } $('#user-save').click( Users.editSave ) $('#user-name').keydown(Main.kp) $('#user-email').keydown(Main.kp) $('#user-password2').keydown(Main.kp) $('#party-location').keydown(Main.kp) $('#party-day').keydown(Main.kp) $('#party-year').keydown(Main.kp) $('#party-save').click( Party.editSave ) Nav.selectClass(Nav.navIDs, "nav_about") $('#aboutMode').show() warn("done!") }, }; Main.init();